Skip to content

S2 — IMU Propagation

Between camera frames the IMU runs at 200 Hz–1 kHz, and S2 integrates it: it strapdown-integrates the mean (attitude, velocity, position) and propagates the covariance P forward, so the filter arrives at the next image with both a predicted pose and an honest uncertainty about it. This stage was a prime suspect for the #212 over-confidence — and the probe cleared it. This page is what a measured negative result looks like.

  • Mean — debias the IMU sample, then strapdown-integrate R, v, p (zeroth-order hold or RK4).
  • CovarianceP⁻_{k+1} = Φ P⁺_k Φᵀ + Q_d. The transition matrix Φ carries the off-diagonal skew blocks coupling orientation error into velocity and position error — gravity leakage living inside the covariance. The discrete noise Q_d should map measurement-space noise through the noise Jacobian G, producing θ–v–p cross-correlations and the higher-order Δt²/Δt³ scalings — not a plain diagonal.

The cortex Q_d is assembled diagonally — it drops the canonical position-noise block and the velocity–position cross term. A diagonal Q_d understates position/velocity process noise and omits correlations the update relies on, which is a textbook over-confidence mechanism. The question is not “is it diagonal” (it is) but how much does that actually cost — and the only honest way to answer is to measure it against a canonical reference.

Signaturepropagate(x⁻, P⁻, imu[t_k, t_{k+1}]) → (x⁻_{k+1}, P⁻_{k+1})
PreΔt > 0, monotonic timestamps; measurements debiased; P⁺_k symmetric PSD
Post / invariantsR ∈ SO(3) (orthonormal, det 1) · P⁻ symmetric PSD · Q_d PSD with θ–v–p cross-correlations · the 4-D unobservable subspace (global position + yaw) stays in the propagation null space · GT-injection: zero-noise propagation reproduces the GT trajectory within integration tolerance
cortexmsckf/propagator.hpp (Φ assembly, Q, FEJ)

The S2 probe reconstructs the canonical Φ/Q_d and compares them to the shipped Propagator, then drives the real propagator on the synthetic world.

Φ reconstruction & the structural invariants — all pass

Section titled “Φ reconstruction & the structural invariants — all pass”
checkresult
Φ reconstruction (real == reference)1.5e-16 — pass
R orthonormality ‖RᵀR − I‖ @0.5 s2.2e-16 — pass
P min-eigenvalue @0.5 s> 0 — PSD
global-position nullspace leak0 — preserved
GT-injection integrator orderO(Δt) (error halves with Δt: 59→30→15→7 mm @ 50→800 Hz)

The diagonal-Q deficit — real, but small

Section titled “The diagonal-Q deficit — real, but small”

The cortex Q_d does drop terms — but measured against the canonical G Q_meas Gᵀ, the cost is minor:

quantitycortex vs canonical
Q θ-σ, Q v-σmatch
Q position term0 vs 3.06e-6 m — dropped
Q v–p cross term0 vs 1.25e-9 — dropped
Q relative-Frobenius gap0.35% of Q dropped
position-σ under-report @0.05 s (inter-frame)7.4%
position-σ under-report @0.5 s0.7%

Diagonal-Q position-σ deficit vs canonical Per-step propagation error vs ground truth

Propagation-only NEES — consistent at the default Q

Section titled “Propagation-only NEES — consistent at the default Q”

Driving the real propagator and scaling Q, the propagation-only 6-DoF pose NEES sits right at its target with the shipped noise:

Q scalepose NEES (target 6)
0.2523.5
0.512.2
1 (shipped)6.4
22.97
41.52

Propagation-only NEES vs Q-scale

At the default Q, NEES ≈ 6.4 ≈ the 6-DoF target — the propagated covariance is essentially honest on its own.

The measurements above come from the synthetic probe — known IMU, known Q, run in CI. Its real-data companion, s2_inspect, runs the real propagator (msckf::Propagator) over a real EuRoC IMU window. It seeds the prior pose+velocity from ground truth at the window start (plus the filter’s initial-P seed), then propagates step by step — no SDK change, since the propagator is already standalone.

Terminal window
s2_inspect --dataset /path/to/V1_01_easy/mav0 --out build/s2 --window-s 0.5
node docs-site/scripts/gen-propagation-figures.mjs build/s2 # → cov_growth.svg, pose_drift.svg

It writes propagation.json and renders two figures:

  • the covariance-growth heatmap — each of the 15 IMU error states’ σ over the window (row-normalized), with the θ/p/v/b_g/b_a blocks marked. The position block growing only via the velocity coupling (no direct position-Q term) is the diagonal-Q simplification, now visible on real data.
  • drift vs the ±3σ envelope — the propagated pose’s dead-reckoning drift from ground truth, plotted against the filter’s own growing 3σ band. Drift that stays inside the band means the propagated covariance honestly covers the error; drift that escapes it (red) is the local, real-data image of an under-noised Q.

This is the real-data check on the synthetic finding below: on EuRoC the envelope covers the inter-frame drift, confirming propagation is essentially honest on its own — the #212 over-confidence enters elsewhere.