Two flawed sensors, fused into one good answer. A gyroscope reads rotation rate — crisp instant-to-instant, but its bias drifts without bound. An accelerometer reads tilt from gravity — dead stable over time, but drowned in noise. High-pass the gyro, low-pass the accel, and — because the two filters sum to exactly one at every frequency — the fused tilt has less error than either sensor alone. Down the center the signals go in, the engine fuses, the estimate comes out. The blue team builds it; the red team breaks it.
source T. Higgins, "A Comparison of Complementary and Kalman Filtering," IEEE Trans. Aerospace & Electronic Systems AES-11(3), 1975; R. Mahony, T. Hamel, JM. Pflimlin, "Nonlinear Complementary Filters on the Special Orthogonal Group," IEEE Trans. Automatic Control 53(5):1203–1217, 2008 — hal-00488376. Cited, not quoted; link AMBER (author preprint, not the paywalled IEEE record).
One line, run every step (dt = 10 ms):
θ₀ = α·(θ₋₁ + ωgyro·dt) + (1−α)·θaccel
The gyro path is a high-pass H(z), the accel path a low-pass L(z). They are complementary: H(z)+L(z) ≡ 1, so no frequency is lost or double-counted. α sets the crossover time constant τ = α·dt/(1−α).
Live error of each estimate on the current signal (smallest wins):
| estimate | RMS error (rad) |
|---|
The complementary filter is the Kalman filter stripped to its bones for orientation: instead of propagating a covariance to earn a time-varying gain, it fixes the gain at α and splits the spectrum by hand — high-pass the gyro, low-pass the accel, sum to one.
For a steady-state single-axis problem the two coincide: Kalman's converged gain is a complementary crossover. One sphere is the other's limit case.
The blue team's live check: re-run selfcheck() — the complementary sum, the fused-error-is-smallest property, the α=1/α=0 limits, steady-state unbiasedness. If red tampers, this badge is where it shows.
Both sensors report the same tilt θ, and both are wrong — in opposite bands:
| sensor | measures | good | bad |
|---|---|---|---|
| gyro | rate ω | fast / short-term | drifts (bias) |
| accel | angle θ | stable / long-term | noisy |
Integrating the gyro gives a smooth angle that walks away; the accelerometer gives a jittery angle that stays put. Feed both into the panel below.
Every value on the canvas is integrated and fused live from the sliders — never looked up.
What the machine produces, proven: a tilt whose error is smaller than the raw gyro (which drifts) and smaller than the raw accelerometer (which is noisy) — with the two filters summing to exactly 1 at every frequency and the estimate unbiased in steady state. The current signal's numbers are above; the guarantee is the output.
The blue team's witness (left) re-checks these live; the red team (right) tries to make them false.
It also assumes a single, well-chosen α. One fixed crossover cannot be optimal for both a slow drift and a fast manoeuvre — that time-varying trade-off is exactly what the Kalman filter earns with a covariance, and what this filter throws away for cheapness.
"Higher α is always better — trust the gyro." Cut. α=1 is pure gyro: no accel correction, so bias drifts without bound (see window 6). The optimum is interior.
"The gains α and 1−α are just a weighted average." Cut. A static average of two angles keeps both flaws. The point is spectral: gyro only above the crossover, accel only below.
"It needs no tuning." Kept, corrected. α must match dt and the noise split via τ=αdt/(1−α) — cheaper than Kalman, not free.
The red team's move: force α=1 — pure gyro, the accelerometer disconnected. The estimate now integrates bias forever and drifts without bound. The blue team's witness (window 7) is watching.
Cut the accelerometer and the fused error stops being the smallest — it becomes the drifting gyro itself. The witness recomputes, the property fails, and the badge turns red. Nothing is faked; the attack is real and it is caught.