# Physical rack and tie-rod reference, v1.0.0

This is numerical verification of rigid, unmeasured educational geometry, not
experimental validation of a vehicle. The old locked-heading suspension reference
and its thresholds remain separate and unchanged.

The independently versioned `vehiclelab.steering-study.v1` owns two corner
definitions, rigid outer joints, entered constant tie lengths and a common rack.
Coordinates are metres in a right-handed, chassis-aligned inspection frame: X
forward, Y left, Z up. Its origin is the front-axle midpoint at design wheel-centre
height. It is not the Full-Car body mass-centre origin; future vehicle integration
must explicitly place this axle frame relative to body/world frames.
Corner origins are [0, ±track/2, 0]. Each rack joint is
`reference + normalizedAxis * (sideOffset + rho)`. Positive rho translates along
the axis; the generic axis is chassis +Y. No steering-wheel calibration is supplied.

## Production equations

Hinge coordinates are q = [alpha, beta, psi]. Upper and lower balls follow
Rodrigues rotations around their own inboard hinge axes. Let n be the normalized
lower-to-upper ball vector. The reference upright basis is R0; its choice defines
the coordinate gauge, not a physical heading constraint. The physical upright is
R = R0 Rz(psi). Wheel centre W, spindle endpoint S and outer tie joint O are rigid
design offsets expressed in R. The solved constraints, all in metres, are

```
F1 = |U-L| - uprightLength
F2 = Wz - j
F3 = |O-I(rho)| - tieLength
```

For hatted ball and tie directions n and t, J has rows
`[n·U_alpha, -n·L_beta, 0]`, `W_q.z` and `t·O_q`.
Differentiate normalized bases analytically, then rotate their columns by psi.
The psi partial is n cross each physical basis column. Solve
`J q_j = [0,1,0]` and `J q_rho = [0,0,t·rackAxis]`.
Every moving hardpoint, carrier basis and element length follows by the chain
rule; compression derivative is minus length derivative. Chassis hardpoints stay
fixed. Tie length derivative along either solved input curve is zero.

Every uncached query starts from an entered design whose tie closure already meets
the same 1e-11 m numerical
tolerance. The editor derives design tie lengths once from its joints; this
consistency criterion is not a physical measurement-precision claim. It advances
along the straight segment (sj, s rho), using at most 1 mm input increments.
It uses analytic 3×3 partial-pivot solves, residual descent and a 0.15 rad maximum
coordinate change per continuation step. Position closure tolerance is 1e-11 m;
there are at most 25 Newton iterations per step and damping stops at 1/128.
Query history cannot seed another assembly. An owned immutable 128-state cache
reuses complete outputs and same-rack design-height baselines only.

## Physical carrier and signs

Orient the normalized spindle S-W into its design body-left hemisphere. That is
carrier Y. Carrier X is normalized (Y cross chassis-up), and Z = X cross Y.
Heading is atan2(Xy, Xx), positive left. Steering is heading minus design heading
at (j,rho)=(0,0). Left toe-in is minus heading; right toe-in is plus heading.
For a tilted spindle, this physical carrier differs from the coordinate-gauge
upright basis. Near-vertical spindle projection cannot define forward heading.

Bump steer is `toeIn(j,rho)-toeIn(0,rho)` at the **same** rho. It is zero at design
height even with nonzero steering. Heading gain is rad/m of rack travel, displayed
as degrees/mm. It is not a steering-wheel ratio, Ackermann calibration or tire
slip angle. Camber/caster/contact/slip and forces are outside this release.

Reflection D = diag(1,-1,1) requires input reversal: right(j,rho) = D left(j,-rho).
Jounce position derivatives use D and axial angular derivatives use -D. Rack
position derivatives use -D; rack angular derivatives use +D. Right heading
changes sign while its rack-heading gain does not. Do not mirror a left solved
pose at the same nonzero rack input to draw the right wheel.

## Independent geometric reduction

`packages/validation/src/steering-reference.ts` imports no production solver,
Jacobian, basis, carrier, toe or continuation implementation. Fixture definitions
are literal data; the reference owns its vector and Cartesian frame arithmetic.

Parameterize the lower ball circle by beta. At fixed beta, intersect the upper
ball's hinge circle with the sphere of rigid upright radius around the lower ball.
This gives `a cos(alpha)+b sin(alpha)=c`; select the root continuously containing
the design assembly. Around n, the outer steering joint follows another circle.
Intersect this circle with the constant-radius tie sphere centered on I(rho):
`d cos(psi)+e sin(psi)=f`. This second geometric root also contains design.
Finally, scalar bisection of beta closes Wz=j in a declared ±0.24 rad bracket.
This is a separate geometric reduction; it uses neither the 3-variable Newton
algorithm nor its derivative matrix or seeds.

Differentiating the first circle gives
`alpha_beta = (U-L)·L_beta / ((U-L)·U_alpha)`.
For tie vector v, `psi_beta = -v·O_beta / (v·O_psi)` and
`psi_rho_partial = v·axis / (v·O_psi)`. Define
`travel_beta = W_beta.z + W_psi.z * psi_beta`.
Then beta_j = 1/travel_beta and
beta_rho = -W_psi.z * psi_rho_partial/travel_beta. Apply these to the independent
Cartesian points/frames/element lengths. The carrier heading is computed directly
as atan2(-canonicalSpindleX, canonicalSpindleY), independently of production.

For the parallel-arm fixture, radius r=0.35 m, alpha=beta=-asin(j/r) on the left.
L=[0,-0.4+sqrt(r²-j²),-0.15+j] in corner coordinates. The 0.12 m rearward
steering arm gives O=L+[-0.12 cos(psi),-0.12 sin(psi),0]. The wheel is
W=L+[-0.05 sin(psi),0.05 cos(psi),0.15]. With v=O-I, the heading gain is
`v_y/(0.12*(v_x sin(psi)-v_y cos(psi)))`; at design both wheels give
-1/0.12 = -8.3333333333 rad/m. The design raw singular values are
`[r*phi,r/phi,0.12]`, where phi=(1+sqrt(5))/2. These exact cases qualify the
linear algebra independently of the spatial reference.

## Rank, sampled bounds and evidence

One-sided Jacobi SVD works directly on J columns, scaled by their largest entry,
without squaring the condition through J-transpose J. Both raw and unit-column
minimum/maximum singular-value ratios must be at least 1e-4. Near-singular warning
is ratio below 1e-2, raw condition above 100, or heading projection below 0.2.
Raw units are m/rad; normalized singular values are dimensionless. A normalized
column can hide a tiny steering lever near tie-sphere tangency, so the raw test is
also mandatory. No old 2×2 threshold is reused or relaxed.

Invalid definition/request, singularity, failed Newton convergence and nonfinite
numerics are separate errors. Newton rejection states that the selected branch
may be infeasible or numerically inaccessible; it does not prove global geometric
nonexistence. A travel study stops in each direction at the first rejected sample.
Its last accepted and first rejected coordinates are sampled boundaries, not
certified physical stops. The plot never extends through a rejected interval.

Three geometries include parallel arms, generic front and genuinely skew hinges.
The published grid is five jounce values × five rack values × both corners:
75 axle / 150 corner poses. All points, physical frames, two-input derivatives,
3×3 partials, closure, mirror signs and element sensitivities are checked. Independent
central differences at 1 mm, 0.1 mm and 0.01 mm establish second-order convergence.
Budgets were declared before measuring the grid in `steering-evidence.ts`.
Frame budget 2e-12 applies to orthonormality/handedness; reference axis-component
agreement shares the 5e-8 angle budget. Position 3e-9 m, derivative/angular
5e-8, Jacobian 3e-9 m/rad, closure 2e-11 m, rotation/implicit identities 2e-11,
reference FD position 5e-8 and heading 5e-7 accommodate Float64 and differentiated
circle/bisection cancellation without changing historical acceptance.

Run `npm run generate:steering` to regenerate only the steering dataset and
`npm run verify:steering` to check byte-exact reproducibility. Regular CI runs the
independent grid and this stale-evidence check. Historical evidence is never regenerated.
