Triaxis

MLX90396 Stray Field Immune (SFI) Joystick

Kinematics, Raw Signals, Polar Radar & SFI Battle Matrix
Standby Mode (Connect USB or Start)
Requirement 4: Stray Field Disturbance Coil (SW + HW GPIO)

Injects 5.0 mT external uniform stray field via SCPI GPIO on physical rig (Melexis IO A0).

COIL: OFF (0.0 mT)
How the Desmos calibration works here

This page runs the shared angle_calib.js module (the same engine the Thumbstick page uses). There are two engines, and the readouts tell them apart:

  • Legacy Standard 3D Hall — 1px mode, a single pixel’s absolute field (Bx, By, Bz, units mT). Feeds computeSfi1Px → the “std” radar α/β readouts. It is the uncompensated reference — fully exposed to stray fields and to the field’s falloff.
  • MLX90396 SFI — 2px mode, the four differential channels between neighboring pixels (dBx/dx = X02, dBz/dx = Z02, dBy/dy = Y13, dBz/dy = Z13, units mT/mm, i.e. counts ÷ (20 × pixel pitch) — the pitch is set in Calibration Tuning). Feeds computeSfi2Px → the “MLX” radar α/β readouts. Uniform external fields cancel in the subtraction, so this pair rejects stray field; the graph tabs plot these gradients directly.

Both run the same model. For 1px, x1 = Bx, y1 = By, z1 = Bz:

a1 = atan2( √(z1² + (k1·(y1 − o11·z1))²), x1 − o12·z1 )
b1 = atan2( √(z1² + (k2·(x1 − o21·z1))²), y1 − o22·z1 )

The default 2px selection runs the reviewer’s normal formula (their step 1), each in its own differential axis:

α = ATAN2(dBx/dx, dBz/dx)  =  ATAN2(X02, Z02)
β = ATAN2(dBy/dy, dBz/dy)  =  ATAN2(Y13, Z13)

The radar plots that α on the X axis and β on the Y axis in the same circular polar style as the legacy radar (centre = (90°, 90°)), and every readout (summary, radar labels, Tilt X/Y) uses the same two numbers.

Select Enhanced in Calibration Tuning to apply the reviewed cross-axis formula:

α = atan2( √(X02² + (k1·(Z13 − o11·X02))²), Z02 − o12·X02 )
β = atan2( √(Y13² + (k2·(Z02 − o21·Y13))²), Z13 − o22·Y13 )

The selected formula feeds the α/β readouts, radars and live gimbal.

Inputs and parameters are normalised against NaN/Infinity, so a bad sample can never break the loop.

Alpha tilt0.0°
Beta tilt0.0°
LEGACY STANDARD 3D HALL (PX0 VULNERABLE) UNCOMPENSATED
Raw Bx0:
0.0 mT
Raw By0:
0.0 mT
Raw Bz0:
0.0 mT
Req 2: Signal Strength |B_std|
√(Bx² + By² + Bz²)
0.0 mT
MLX90396 DIFFERENTIAL SFI (PX02 IMMUNE) ACTIVE GRADIENT DSP
dBx/dx:
0.0 mT/mm
dBy/dy:
0.0 mT/mm
dBz/dx:
0.0 mT/mm
dBz/dy:
0.0 mT/mm
Req 2: Signal Strength |B_diff|
√((dBx/dx)² + (dBy/dy)² + (dBz/dx)² + (dBz/dy)²)
0.0 mT
Legacy field and 6 mm magnet modelSTRAY-SENSITIVE
v 0.0 px/smT
Bx0.0By0.0Bz0.0
MLX90396 differential field and 6 mm magnet modelSFI COMPENSATED
v 0.0 px/smT/mm
dBx/dx0.0dBy/dy0.0dBz/dx0.0dBz/dy0.0
Legacy Standard 3D Hall Radar
|B|0.0 mT α_std0.0° β_std0.0°
MLX90396 Differential SFI Radar
|∇B|0.0 mT/mm α_diff0.0° β_diff0.0°
Dome Kinematics: auto-pattern transitions to live hardware telemetry
Zero: α 90.0°, β 90.0° Tilt X: 0.0° | Tilt Y: 0.0° | Press: —
Fixed XYZ view | Scroll: Zoom

Frame Health

Everything on this tab is the unmodified reply from the three transfers the SFI loop issues each cycle: 0xFC000 and 0x03F00 for the twelve absolute pixels, 0x000AC for the four 2px gradient channels. Nothing is averaged, scaled or clamped.

Source--
Status byte--
Function--
Data ready--
Flags--
CRC--
Loop period--
Waiting for a measurement

Absolute Pixels — raw LSB

Signed 12-bit counts, full scale ±2048. The averages are the four-pixel means the dome uses for the absolute heading.

ChannelCount
X0--
Y0--
Z0--
X1--
Y1--
Z1--
X2--
Y2--
Z2--
X3--
Y3--
Z3--
Average X--
Average Y--
Average Z--
Peak |count|--
Waiting for a measurement

Differential Channels — raw LSB

The chip's own inter-pixel gradients, read in a single transfer (mask 0x000AC: X02, Z02, Y13, Z13). They feed the SFI radar and the dome. The counts are converted to mT/mm by 20 × pixel pitch (the Pixel pitch field in Calibration Tuning); a magnet sitting centred reads a small gradient — that is the null, not a missing magnet.

ChannelCount
X02--
Z02--
Y13--
Z13--

Dome Output

What the Idle / Auto-Pattern tab is drawing, after the 2px gradient → tilt mapping is applied.

Position sourceDifferential 2px (dBz/dx, dBz/dy)
Tilt X--
Tilt Y--
Press magnitude--
Press state--