IMU & Inertial Navigation
An IMU measures its own motion and nothing external. From accelerometers and gyroscopes a strapdown algorithm computes position, velocity and attitude by integration — everywhere, underwater, underground, in space, while jammed — at the cost of drift. This page is the long version: what the sensor actually outputs and why it is an integral rather than a rate, the complete error model, the mechanization equations, coning and sculling, the two stages of ground alignment with the filter mathematics written out — state vector, process dynamics and every measurement residual — Schuler oscillation, how the numbers in the filter's covariance come from bench calibration, and a worked navigation-grade example showing why a sensor's error ratios decide which states get estimated.
Symbols used on this page are defined in the Nomenclature → inertial navigation.
Related: Fine alignment and the drift test go deeper on alignment as an estimation problem; IMU acceptance testing is the bench-procedure view; Hardware — IMUs covers parts and grades; Rocket navigation puts it in a flight architecture.
1 · What the sensor actually gives you
Two triads sit in the unit. Accelerometers sense specific force — the non-gravitational part of acceleration — and gyroscopes sense angular rate. But almost no navigation-grade IMU reports those quantities directly.
1.1 ΔV and Δθ, not acceleration and rate
The physical sensing elements are intrinsically integrating. A ring-laser gyro counts interference fringes, and each fringe is a fixed increment of angle, not a rate. A pendulous-integrating-gyro accelerometer, or a force-rebalance accelerometer with a pulse-counting loop, emits pulses each worth a fixed increment of velocity. So the natural output is a count over an interval:
$$ \Delta\boldsymbol\theta_k = \int_{t_{k-1}}^{t_k}\!\boldsymbol\omega_{ib}^b(t)\,\mathrm dt, \qquad \Delta\mathbf v_k = \int_{t_{k-1}}^{t_k}\!\mathbf f^b(t)\,\mathrm dt $$These are often called delta-angles and delta-velocities. A rate-output IMU (most MEMS parts) samples $\boldsymbol\omega$ and $\mathbf f$ instead, and the consumer has to integrate them. The distinction matters more than it looks:
| Increment output (ΔV, Δθ) | Rate output (f, ω) | |
|---|---|---|
| What a sample means | The exact integral over the interval — no information lost between samples | A point sample of a continuous signal |
| Under vibration | Correct: high-frequency motion inside the interval is still captured in the integral | Aliased: motion faster than Nyquist folds down and corrupts the estimate irreversibly |
| Dropped sample | Loses a known, bounded amount of motion | Loses an unknown amount — the signal between samples was never measured |
| Coning/sculling | Can be reconstructed from consecutive increments (§3) | Needs a high sample rate and is still approximate |
| Typical grade | Navigation, strategic (RLG, HRG, FOG) | Consumer, industrial MEMS |
One consequence for the software: increments are interval quantities, so they must be consumed exactly once and their interval must be known. A dropped or duplicated increment message is a direct velocity or attitude error, not a momentary glitch, which is why the timing interface between an IMU and a navigator is such a common source of flight anomalies.
1.2 The complete error model
What you receive is the true increment corrupted by a deterministic and a random stack. Written per triad, for the sensed quantities:
$$ \tilde{\mathbf f}^b = \big(I + S_a + M_a\big)\,\mathbf f^b + \mathbf b_a + \mathbf b_a(t) + \mathbf q_a(\mathbf f) + \boldsymbol\eta_a $$ $$ \tilde{\boldsymbol\omega}^b = \big(I + S_g + M_g\big)\,\boldsymbol\omega^b_{ib} + \mathbf b_g + \mathbf b_g(t) + \Gamma\,\mathbf f^b + \boldsymbol\eta_g $$with each term meaning something physically distinct:
| Term | Name | Structure | Observable when… |
|---|---|---|---|
| $S$ | Scale factor | Diagonal. A gain error, in ppm. Output is proportional to input, so it needs a large input to be visible. | A large rate or acceleration is applied — a rate table, or flight |
| $M$ | Misalignment / non-orthogonality | Off-diagonal. The sensing axes are not exactly the axes you think, so input on one axis leaks into another. | Input is applied on one axis while another is observed |
| $\mathbf b$ | Turn-on bias | Constant within a run, different every power cycle. This is the term alignment estimates. | Always present; separable from tilt only by changing geometry |
| $\mathbf b(t)$ | In-run bias instability | Slowly wandering. Modelled as a first-order Gauss–Markov process, not a constant. | Over long runs; sets the Allan-variance floor |
| $\boldsymbol\eta$ | White noise | Integrates to angle random walk (ARW) and velocity random walk (VRW). | Always; averages down as $1/\sqrt T$ |
| $\Gamma\mathbf f$ | g-sensitivity | Gyro bias proportional to acceleration. Matters enormously under sustained thrust. | Under high g — a centrifuge, or boost |
| $\mathbf q_a$ | Non-linearity / g² | Quadratic and vibration-rectification terms. Usually lumped into an error budget rather than estimated. | High-g and high-vibration environments |
Two observations that drive everything downstream. First, scale factor and misalignment multiply the input, so on a stationary pad — where the only inputs are $1g$ on one axis and $\Omega$ about one axis — they are essentially invisible. That is why they are calibrated on a bench (§9) and not by an alignment filter. Second, bias adds regardless of input, so it is always present and always the dominant concern for a static process. This split is the reason §5 and §6 look the way they do.
The compensation step applies the estimated parameters to the raw increments before the mechanization ever sees them:
$$ \Delta\mathbf v^{\text{comp}} = \big(I + \hat S_a + \hat M_a\big)^{-1} \big(\Delta\tilde{\mathbf v} - \hat{\mathbf b}_a\,\Delta t\big), \qquad \Delta\boldsymbol\theta^{\text{comp}} = \big(I + \hat S_g + \hat M_g\big)^{-1} \big(\Delta\tilde{\boldsymbol\theta} - \hat{\mathbf b}_g\,\Delta t\big) $$Note $\hat{\mathbf b}\,\Delta t$, not $\hat{\mathbf b}$ — the increment accumulated over $\Delta t$ carries $\Delta t$ worth of bias. Getting this wrong by using the rate-form bias directly is a classic unit bug that produces an error scaling with sample rate.
Flight code usually writes this in a cheaper, per-axis form. If the filter's scale-factor state is defined as a fractional error $s$ on each axis and the bias state $b$ in rate units, the compensation is a division rather than a matrix solve:
$$ \Delta v^{\text{comp}}_i = \Delta\tilde v_i + \frac{b_{a,i}\,\Delta t}{1 - s_{a,i}}, \qquad \Delta\theta^{\text{comp}}_{A,i} = \Delta\tilde\theta_{A,i} + \frac{\tfrac12 b_{g,i}\,\Delta t}{1 - s_{g,i}} $$Three details in that expression are worth stating explicitly, because each encodes a convention that must match the filter exactly or the correction is applied backwards:
- The sign is a convention, not a derivation. Here the states are defined so that the correction is added. Elsewhere the same physics is written with a subtraction and the opposite state sign. Either is fine; mixing them doubles the error instead of cancelling it.
- $1/(1-s)$, not $(1+s)$. These agree to first order, and for a scale factor of a few hundred ppm the difference is negligible — but the reciprocal is the exact inverse of a sensor that reports $(1+s)$ times truth, so it stays correct if the state ever grows.
- The half-interval increments each get half the bias. $\Delta\theta_A$ and $\Delta\theta_B$ span half the interval apiece, so each carries $\tfrac12 b_g\,\Delta t$. Giving both the full $b_g\Delta t$ is a factor-of-two attitude error that looks exactly like a gyro bias twice the true size.
Cross-axis misalignment ($M$ in the model above) is often not compensated in real time on a well-calibrated navigation-grade unit: the terms are small, they are already trimmed at the factory, and a full matrix inverse per sample costs more than it buys. It remains in the error budget as a consider parameter.
1.3 In practice: two streams, two timestamps, two consumers
§1.1 argued that a navigation-grade IMU reports increments. The complete answer, on real hardware, is that it reports both forms in the same message, and they are not redundant — they are sampled for different consumers and carry different timestamps.
| Field | Quantity | Units | Consumed by | Why this form |
|---|---|---|---|---|
| $\Delta\boldsymbol\theta_A$ | Attitude increment, start → mid of interval | rad | Navigation strapdown, alignment, the filter |
Exact integrals over the interval. Nothing is lost between samples, and the half-interval split lets the mechanization build the attitude valid at the interval midpoint — see the callout below. |
| $\Delta\boldsymbol\theta_B$ | Attitude increment, mid → end of interval | rad | ||
| $\Delta\mathbf v$ | Velocity increment over the interval | ft/s | ||
| $\boldsymbol\omega$ | Angular rate | rad/s | Flight control autopilot, structural filters |
Control laws are written in rates and accelerations, and want the instantaneous value at a known instant, not an interval average. |
| $\mathbf a$ | Linear acceleration | ft/s² |
The midpoint attitude is obtained by applying only the first half-increment to the running attitude; the second half then carries it to the end of the interval. So the mechanization maintains two attitudes per cycle, with different jobs:
| Attitude | Built from | Used for |
|---|---|---|
| $C^n_b\big|_{\text{mid}}$ | running attitude $\oplus\,\Delta\boldsymbol\theta_A$, plus half the navigation-frame rotation | Rotating $\Delta\mathbf v$; the reported angular rate; and the linearisation point for the filter's $F$ matrix (§6.3) |
| $C^n_b\big|_{\text{end}}$ | midpoint attitude $\oplus\,\Delta\boldsymbol\theta_B$, plus the second half | The reported attitude, and the starting point for the next interval |
The navigation frame is itself rotating, so reaching the midpoint means advancing the body attitude by $\Delta\boldsymbol\theta_A$ and the reference frame by half of its own rotation over the interval. Position is then updated trapezoidally, $\mathbf r \mathrel{+}= \big(\mathbf v + \tfrac12\Delta\mathbf v\big)\Delta t$ — the same second-order idea applied once more. Coning and sculling (§3) remain separate concerns: the halves reduce the velocity-rotation error, not the non-commutativity of the attitude update itself.
Two engineering consequences follow, and both are easy to get wrong:
- The two streams carry separate times of validity. The increment fields are stamped with the end of the integration interval; the rate/acceleration fields with the instant they were latched. Using one timestamp for both introduces a systematic, sub-sample timing bias — exactly the kind of error that never shows up in a static test and then scales with dynamic pressure.
- Only the increments may be integrated. Feeding $\boldsymbol\omega$ and $\mathbf a$ into the strapdown as if they were interval averages discards the sensor's own exact integration and reintroduces the rectification errors of §3 at the sample rate.
Message rate matters as well. A navigation-grade ring-laser unit typically publishes at a few hundred hertz — call it $f_{\text{imu}}$ — while the vehicle's control thread runs slower. The navigation manager therefore consumes several IMU messages per control cycle, and every one of them must be integrated; dropping the intermediate samples and using only the most recent one throws away most of the interval and biases the solution. When a message is genuinely missing, the correct behaviour is to reuse the previous sample and flag the gap, not to extrapolate.
A lower-grade MEMS unit in the same architecture may publish at a lower rate and require an anti-aliasing filter on the control-side stream — typically a low-order Butterworth, run at the sensor rate and decimated to the control rate, one filter per channel. The navigation-side increments are not filtered: they are already integrals, and filtering them would destroy the property that makes them useful.
1.4 Where coning and sculling are actually compensated
§3 derives the coning and sculling corrections. A fair question is then: does the navigation software compute them? For a navigation-grade unit the answer is no — and it should not. The corrections are applied inside the IMU, and the increments that cross the interface are already compensated.
| Effect | Compensated where | Why there |
|---|---|---|
| Coning attitude non-commutativity |
Inside the IMU | Needs sub-sample angular history. The sensor has it at its internal rate — typically many times the output rate — and the navigation computer does not. |
| Sculling rotation × acceleration rectification |
Inside the IMU | Same argument: it needs $\boldsymbol\omega$ and $\mathbf a$ correlated within the interval. |
| Velocity-rotation error frame rotates during the interval |
In the navigation computer | Handled structurally by the midpoint attitude of §1.3 — which is precisely why the sensor bothers to split $\Delta\boldsymbol\theta$ in half. |
| Bias, scale factor | In the navigation computer (§1.2) | These are filter states; they change as the filter learns them, so they cannot be baked into the sensor. |
Two practical consequences. First, searching a flight navigation codebase for "coning" can legitimately return nothing — its absence is a statement about the sensor, not a missing feature. Second, the property is lost if the increments are mishandled downstream: averaging several samples together before integrating, or using the rate/acceleration stream as though it were an interval average, reintroduces exactly the rectification errors the sensor spent its internal bandwidth removing.
A lower-grade unit that reports only rate and acceleration shifts the burden the other way: the navigation computer must then form the increments itself and apply the corrections of §3 explicitly, at the highest rate it can sustain. That is a real architectural difference between sensor classes, not a detail — it changes what the software is responsible for being correct about.
1.5 The frames, and the chain between them
Nearly every quantity in inertial navigation is meaningless without saying which frame it is resolved in and relative to what. Six frames appear in a launch-vehicle navigator, and they are not interchangeable:
| Frame | Origin | Axes | Rotates? | Used for |
|---|---|---|---|---|
| Inertial ECI |
Earth's centre | Fixed relative to the stars | No — this is the one Newton's laws apply in | What the gyros and accelerometers actually sense motion with respect to |
| Earth-fixed ECEF |
Earth's centre | Rotate with the Earth; one axis through the pole | Yes, at $\Omega \approx 15.04^\circ$/h | The mechanization and filter frame for a launch vehicle. The pad is surveyed here and GNSS reports here. |
| Local-level UEN / NED |
The vehicle | Up–East–North, or North–East–Down | Yes — with the Earth and with vehicle motion | Human-readable attitude: roll, pitch, heading. Where tilt and azimuth mean something. |
| Sensor / IMU the "centre of navigation" |
A point inside the IMU, defined by the supplier | The IMU's own axes, also supplier-defined | With the vehicle | The frame every increment arrives in. The navigation state is propagated for this point. |
| Vehicle / body | A structural reference on the stage | Vehicle roll/pitch/yaw axes | With the vehicle | What flight control steers. Related to the sensor frame by a surveyed, fixed rotation. |
| Antenna | The GNSS antenna phase centre | Usually aligned to the vehicle frame | With the vehicle | Where GNSS measurements are actually made — offset from the sensor frame by a lever arm (§7.8). |
The chain, as the software actually composes it:
Read the notation as $C^{\text{to}}_{\text{from}}$, and note the two distinct jobs. Earth-fixed is where the arithmetic happens: it is non-rotating with respect to the ground, the pad survey is expressed in it, and GNSS needs no conversion. Local-level is where the meaning lives: "tilt" and "azimuth" are statements about the local vertical and local north, so the azimuth pseudo-measurement must be formed there and then mapped back. And inertial is where the sensors are honest — which is why Earth rate and the Coriolis term keep appearing as corrections when integrating in a rotating frame.
A subtlety worth naming: the navigation solution is computed for the sensor point, but almost everything that consumes it cares about a different point — flight control about the vehicle reference, GNSS about the antenna, aerodynamics about the centre of mass. Each requires a lever-arm translation, and under rotation each picks up a $\boldsymbol\omega\times\mathbf l$ velocity term. Frame errors and lever-arm errors are the two most common sources of a solution that is internally consistent and externally wrong.
2 · Strapdown mechanization
Mechanization is the integration of increments into a navigation state. Attitude first, because velocity depends on it.
2.1 Attitude
In continuous form, for the body-to-navigation rotation $C^n_b$:
$$ \dot C^n_b = C^n_b\,[\boldsymbol\omega^b_{ib}\times] - \big[(\boldsymbol\omega^n_{ie} + \boldsymbol\omega^n_{en})\times\big]\,C^n_b $$The first term is what the gyros sense. The second removes what the gyros sense because the reference frame itself is rotating: $\boldsymbol\omega_{ie}$ is Earth's rotation and $\boldsymbol\omega_{en}$ is the transport rate, the rotation of the local-level frame as the vehicle moves over a curved Earth:
$$ \boldsymbol\omega^n_{en} = \begin{bmatrix} \dfrac{v_E}{R_E + h} \\[6pt] -\dfrac{v_N}{R_N + h} \\[6pt] -\dfrac{v_E\tan L}{R_E + h} \end{bmatrix} $$That transport term is not a detail — it is the feedback path that creates Schuler oscillation (§6). In discrete form, using the increment directly rather than a sampled rate:
$$ C^n_{b}(t_k) = C^n_b(t_{k-1})\,\exp\!\big([\Delta\boldsymbol\theta^{\text{comp}}_k\times]\big) - \text{(frame-rotation correction)} $$with the exponential evaluated in closed form by Rodrigues' formula, or equivalently as a quaternion update (see Attitude & rotations). Quaternion renormalisation is applied on a slow schedule — the norm drifts only through round-off, so renormalising every cycle is wasted work, and never renormalising is a slow corruption.
2.2 Velocity and position
$$ \dot{\mathbf v}^n = C^n_b\,\mathbf f^b - \big(2\boldsymbol\omega^n_{ie} + \boldsymbol\omega^n_{en}\big)\times\mathbf v^n + \mathbf g^n(\mathbf r) $$Three corrections, each easy to get wrong. The $2\boldsymbol\omega_{ie}\times\mathbf v$ term is Coriolis; the $\boldsymbol\omega_{en}\times\mathbf v$ term is the centripetal effect of moving over a curved surface; and $\mathbf g^n(\mathbf r)$ is modelled gravity, including the centrifugal part of local gravity, evaluated at the current estimated position. A gravity-model error is therefore indistinguishable from an accelerometer bias in the vertical channel — which is exactly why it is usually a consider parameter rather than an estimated state.
3 · Coning & sculling — the non-commutativity corrections
Summing gyro increments and calling the result a rotation is wrong whenever the rotation axis moves within the interval, because finite rotations do not commute. Two named errors follow.
3.1 Coning (attitude)
If the angular-rate vector sweeps a cone — two axes oscillating 90° out of phase — the true attitude accumulates a secular drift about the third axis while the naive sum of increments reports zero. The correction, from consecutive sub-interval increments $\boldsymbol\alpha$:
$$ \Delta\boldsymbol\theta = \boldsymbol\alpha_k + \underbrace{\tfrac12\,\boldsymbol\alpha_{k-1}\times\boldsymbol\alpha_k}_{\text{coning}} + \cdots $$Higher-order algorithms use more sub-samples and more cross terms. The key point: the information needed to reconstruct coning is present in a sequence of increments, which is the deeper reason the ΔV/Δθ interface of §1.1 is preferred.
3.2 Sculling (velocity)
The velocity analogue. When angular rate and specific force oscillate in phase, a rectified velocity error builds up — the sensor is being rotated while it is being accelerated, so a fixed body-frame acceleration paints out a non-zero mean in the navigation frame:
$$ \Delta\mathbf v^n = C^n_b\Big[\Delta\mathbf v_k + \underbrace{\tfrac12\,\boldsymbol\alpha_k\times\Delta\mathbf v_k}_{\text{rotation}} + \underbrace{\tfrac12\big(\boldsymbol\alpha_{k-1}\times\Delta\mathbf v_k + \Delta\mathbf v_{k-1}\times\boldsymbol\alpha_k\big)}_{\text{sculling}}\Big] $$The effect is easiest to believe when you watch it. Two axes oscillate out of phase below; naively summing increments reports zero net rotation about the third axis, yet the body really is rotating:
4 · How each error term grows
A bias does not produce a constant error — it produces a growing one, and the power of $t$ depends on how many integrations sit between the sensor and the quantity you care about.
| Error | Symbol | Attitude | Velocity | Position (short term) |
|---|---|---|---|---|
| Accel bias | $b_a$ | — | $b_a t$ | $\tfrac12 b_a t^2$ |
| Gyro bias | $b_g$ | $b_g t$ | $\tfrac12 g\,b_g t^2$ | $\tfrac16 g\,b_g t^3$ |
| Accel white noise (VRW) | $\sigma_v$ | — | $\propto\sqrt t$ | $\propto t^{3/2}$ |
| Gyro white noise (ARW) | $\sigma_\theta$ | $\propto\sqrt t$ | $\propto t^{3/2}$ | $\propto t^{5/2}$ |
| Bias instability | — | random walk | dominates long runs | dominates long runs |
| Scale factor | $S$ | $\propto\!\int\!\omega$ | $\propto\!\int\! f$ | ∝ distance travelled |
| g-sensitivity | $\Gamma$ | $\propto\!\int\! f$ | large under boost | large under boost |
These are the short-term (non-rotating-Earth) growth laws. Over times comparable to the Schuler period they are replaced by the bounded oscillatory solutions of §6 — the $t^3$ law for gyro bias is the first term of an expansion of $R\beta(t-\sin\omega_s t/\omega_s)$, valid while $\omega_s t \ll 1$.
Set a bias and watch the estimate peel away from truth, then enable a periodic fix and see it bounded:
5 · Ground alignment — the two stages
Before an INS can navigate it needs an initial state. Position is surveyed and velocity is zero, so the entire problem is attitude — and the only references available to a stationary vehicle are the gravity vector and Earth's rotation vector. This runs in two stages that are not alternatives: fine alignment requires coarse alignment to have run first.
5.1 The block diagram
Note the two inputs that are not from the IMU: the surveyed position, which supplies the latitude that gyrocompassing needs and the truth for the position update, and the a priori sensor statistics from bench calibration, which become the filter's initial covariance (§6.5).
5.2 Stage 1 — coarse alignment (levelling)
Process. Accumulate increments over a short window and divide by the elapsed time to recover the mean sensed vectors. Averaging is the entire signal-processing content of this stage:
$$ \bar{\mathbf f}^b = \frac{1}{T}\sum_{k=1}^{N}\Delta\mathbf v_k, \qquad \bar{\boldsymbol\omega}^b = \frac{1}{T}\sum_{k=1}^{N}\Delta\boldsymbol\theta_k, \qquad T = N\,\Delta t $$Because the vehicle is stationary, the expected values are known: $\bar{\mathbf f}^b$ should be the reaction to gravity and $\bar{\boldsymbol\omega}^b$ should be Earth rate, both expressed in body axes. White noise averages down as $1/\sqrt T$, which is why even a second or two of averaging is enough for the gravity direction — the signal is $1g$ against microgravity-level noise.
Levelling. A single measured vector fixes two of three attitude degrees of freedom. Roll and pitch follow directly:
$$ \phi = \operatorname{atan2}\big(-\bar f_y,\; -\bar f_z\big), \qquad \theta = \operatorname{atan2}\Big(\bar f_x,\; \sqrt{\bar f_y^2 + \bar f_z^2}\Big) $$Heading. Two options, and a real system usually implements both:
Analytic coarse alignment (TRIAD)
Use both averaged vectors. Gravity and Earth rate are non-parallel, so their cross product completes a frame and the attitude follows in closed form:
$$ \hat{\mathbf u}_1 = \frac{-\bar{\mathbf f}}{|\bar{\mathbf f}|},\quad \hat{\mathbf u}_2 = \frac{\hat{\mathbf u}_1\times\bar{\boldsymbol\omega}} {|\hat{\mathbf u}_1\times\bar{\boldsymbol\omega}|},\quad \hat{\mathbf u}_3 = \hat{\mathbf u}_1\times\hat{\mathbf u}_2 $$Build the same triad from the known reference vectors and $C^n_b = U_n U_b^{\mathsf T}$. Fast, but the heading is only as good as a few seconds of averaging against a 15°/h signal — i.e. poor. It is an initialisation, not an answer.
This is Wahba's problem with two vectors — see Attitude.
Surveyed / mounting attitude
If the vehicle's orientation on the pad is surveyed, take heading from that directly. Deterministic and instant, and it does not care about gyro quality — but it depends on the survey and on the mechanical interface being what the paperwork says.
Usually the preferred path when available, with the analytic method as the fallback that needs no external information.
A by-product that matters later: gravity-exposed axes. While averaging, check which accelerometer axes actually sense a significant component of gravity:
$$ \text{exposed}_i = \big[\,|\bar f_i| \ge f_{\min}\,\big] $$Only an exposed axis has any hope of having its bias or scale factor observed, because only there is there an input to observe it against. This boolean triple is handed to the fine-alignment filter as a gate on bias estimation — attempting to estimate a parameter with no excitation does not just fail, it injects process noise that leaks through correlations into the states that are observable.
5.3 What is passed from coarse to fine
| Passed | From | Why fine alignment needs it |
|---|---|---|
| $C^n_b$ coarse attitude | Levelling + TRIAD or survey | The filter is linearised. It needs a starting attitude close enough for small-angle error states to be valid — arcminutes, not degrees. |
| Position (ECEF / LLA) | Survey, converted | Truth for the position update; latitude for the Earth-rate reference vector. |
| Velocity = 0 | Definition | Truth for the zero-velocity update. |
| Gravity magnitude & model | Gravity model at surveyed position | Enters the mechanization and the tilt-to-velocity coupling. |
| Gravity-exposed axis flags | Averaging check above | Gates which accelerometer biases the filter is allowed to estimate. |
| A priori $\hat{\mathbf b}$, $\hat S$, $\hat M$ | Bench calibration (§9) | Initial compensation, and the mean of the initial state. |
| A priori covariance $P_0$ | Bench calibration / datasheet (§6.5) | Tells the filter how much to trust each initial value — the single most consequential tuning input. |
6 · Stage 2 — fine alignment, as a filter
Heading needs the Earth-rate reference, whose horizontal component is only $\Omega\cos L \approx 10.6^\circ/\mathrm h$ at mid-latitudes. That is comparable to the bias of even a good gyro, so heading and gyro bias must be estimated jointly, over minutes, by a filter. A formula cannot do it.
6.1 Why an error-state formulation
The filter does not estimate the navigation state. It estimates the error in the navigation state while the mechanization integrates the full nonlinear state at high rate:
$$ \mathbf x_{\text{true}} = \hat{\mathbf x} \oplus \delta\mathbf x $$Three reasons this is the right choice here. The errors genuinely are small, so linearisation is honest rather than a stretch. The error dynamics are slow and smooth even though attitude is being integrated hundreds of times a second, which permits a large rate separation between mechanization and filter. And the nonlinear attitude integration stays in the mechanization where it belongs, rather than inside a linear filter that would have to approximate it.
6.2 The process model
The state — position, velocity, attitude error, and the sensor parameters. A 15-state core is typical for alignment; scale factors are usually carried as consider parameters here and only promoted to estimated states once flight provides the excitation to observe them:
$$ \delta\mathbf x = \begin{bmatrix} \delta\mathbf r & \delta\mathbf v & \delta\boldsymbol\psi & \mathbf b_g & \mathbf b_a \end{bmatrix}^{\mathsf T} \in \mathbb R^{15} $$Each state earns its place, and — critically — not all of them are observable while the vehicle is stationary:
| State | Why it is estimated here | Observable on a static pad? |
|---|---|---|
| $\delta\mathbf r$ (3) | Position error. The pad is surveyed, so truth is known. | Strong — directly measured |
| $\delta\mathbf v$ (3) | Velocity error. Truth is zero, so whatever the mechanization accumulates is error. This is the channel through which every other state becomes visible. | Strong — directly measured |
| $\delta\psi_N,\delta\psi_E$ (2) tilt |
Mis-resolved gravity drives $\delta\dot{\mathbf v}$ with a gain of $g$, so tilt appears fast as a growing horizontal velocity error. Highest-leverage state for flight. | Strong — amplified by $g$ |
| $\delta\psi_D$ (1) heading |
Heading. The whole reason fine alignment exists. | Weak — only via Earth rate, needs minutes |
| $b_{g,N},b_{g,E}$ (2) | Horizontal gyro bias integrates into tilt, which gravity then amplifies into velocity error. | Good — correlated with tilt |
| $b_{g,D}$ (1) | Vertical gyro bias causes azimuth drift, which leaks Earth rate into a horizontal axis. | Weak — aliases with heading |
| $b_{a,N},b_{a,E}$ (2) | Horizontal accelerometer bias. Carried because it is real and matters in flight. | Not separable from tilt — see §6.7 |
| $b_{a,D}$ (1) | Vertical accelerometer bias. Observable only because that axis sees the full $1g$. | Partly — aliases with gravity-model error |
Gated by the gravity-exposed flags from §5.2: a bias on an axis with no gravity component has no excitation, and estimating it injects process noise that leaks into the observable states through their correlations. Full observability discussion on Fine alignment §2.1.
The linearised dynamics $\delta\dot{\mathbf x} = F\,\delta\mathbf x + G\mathbf w$, local-level frame:
$$ F = \begin{bmatrix} 0 & I & 0 & 0 & 0 \\ \partial\mathbf g/\partial\mathbf r & -\big[(2\boldsymbol\omega_{ie}+\boldsymbol\omega_{en})\times\big] & -\big[C^n_b\mathbf f^b\times\big] & 0 & C^n_b \\ 0 & F_{\psi v} & -\big[(\boldsymbol\omega_{ie}+\boldsymbol\omega_{en})\times\big] & -C^n_b & 0 \\ 0 & 0 & 0 & -1/\tau_g\,I & 0 \\ 0 & 0 & 0 & 0 & -1/\tau_a\,I \end{bmatrix} $$The blocks that carry the physics of alignment:
- $-[C^n_b\mathbf f^b\times]$ — the tilt-to-velocity coupling. On the pad $C^n_b\mathbf f^b \approx [0,0,-g]^{\mathsf T}$, so a tilt of $\delta\psi$ produces a horizontal acceleration error of $g\,\delta\psi$. The factor of $g$ is why tilt is strongly observable: the measurement sees it amplified nearly tenfold per second of integration.
- $F_{\psi v}$ — the transport-rate feedback, $\partial\boldsymbol\omega_{en}/\partial\mathbf v$, of order $1/R$. Tiny, but non-zero, and together with the row above it closes the Schuler loop (§6.6).
- $-C^n_b$ in the attitude row — how gyro bias becomes tilt. This is the correlation that makes gyro bias observable at all: bias integrates into tilt, and tilt is visible through gravity.
- $C^n_b$ in the velocity row — how accelerometer bias becomes velocity error, on the same row and with the same structure as the tilt term. That structural identity is the aliasing problem of §6.6.
- $-1/\tau\,I$ on the bias rows — the biases are modelled as first-order Gauss–Markov processes, not constants. A pure random walk has unbounded variance, which is physically wrong for a bias that the datasheet bounds; a constant cannot adapt at all. FOGM has a bounded steady state $\sigma^2(1 - e^{-2\Delta t/\tau})$ and a correlation time you can measure.
Discretisation over the filter interval, with $Q$ from the noise coefficients of §9:
$$ \Phi_k \approx I + F\,\Delta t + \tfrac12 F^2\Delta t^2, \qquad Q_k = \int_0^{\Delta t}\!\Phi(\tau)\,G\,Q_c\,G^{\mathsf T}\Phi(\tau)^{\mathsf T}\,\mathrm d\tau $$In a two-rate implementation the fast side accumulates the coupling terms that $\Phi$ is built from across the whole filter interval at high-rate fidelity, rather than the filter assuming one coarse linearisation over a whole second. Under dynamics that distinction is significant. §7 shows the mechanism — and note it is a running sum on the fast side, with the matrix products deferred to the filter.
6.3 The same filter as flight software writes it
The local-level form above is the clearest way to see the physics, because gravity points down one axis and Earth rate splits into two. Flight software for a launch vehicle usually mechanizes in ECEF instead: the pad is surveyed in ECEF, GNSS reports in ECEF, and the vehicle leaves the region where a local-level frame is even meaningful. The state grows to 18 because scale factor is carried explicitly:
$$ \delta\mathbf x = \begin{bmatrix} \underbrace{\delta\mathbf r}_{3} & \underbrace{\delta\mathbf v}_{3} & \underbrace{\delta\boldsymbol\theta}_{3} & \underbrace{\mathbf b_a}_{3} & \underbrace{\mathbf b_g}_{3} & \underbrace{\mathbf s_a}_{3} \end{bmatrix}^{\mathsf T} \in \mathbb R^{18} $$| Index | State | Units | Meaning |
|---|---|---|---|
| 0–2 | $\delta\mathbf r$ | ft | Position error of the vehicle reference point w.r.t. ECEF, resolved in ECEF |
| 3–5 | $\delta\mathbf v$ | ft/s | Velocity error, same frames |
| 6–8 | $\delta\boldsymbol\theta$ | rad | Attitude error as a rotation vector, from the error quaternion between truth and estimate |
| 9–11 | $\mathbf b_a$ | ft/s² | Accelerometer bias error, body axes |
| 12–14 | $\mathbf b_g$ | rad/s | Gyro bias error, body axes |
| 15–17 | $\mathbf s_a$ | ppm | Accelerometer scale-factor error, body axes |
The attitude error being a rotation vector rather than three Euler angles matters: it has no singularity, it composes correctly with the quaternion the mechanization actually propagates, and the covariance block is directly interpretable as an uncertainty ellipsoid about the estimated axes.
With the state in that order, $F$ is:
$$ F = \begin{bmatrix} 0 & I_3 & 0 & 0 & 0 & 0 \\ \partial\dot{\mathbf v}/\partial\mathbf r & -2\big[\boldsymbol\Omega_{ie}\times\big] & -C^e_b\big[\mathbf a_{\text{sensed}}\times\big] & C^e_b & 0 & C^e_b \\ 0 & 0 & -\big[\boldsymbol\Omega_{ib}\times\big] & 0 & I_3 & 0 \\ 0 & 0 & 0 & -\tfrac{1}{\tau_a}I_3 & 0 & 0 \\ 0 & 0 & 0 & 0 & -\tfrac{1}{\tau_g}I_3 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \end{bmatrix} $$where the gravity-gradient block, for a spherical primary plus the centrifugal term, is
$$ \frac{\partial\dot{\mathbf v}}{\partial\mathbf r} = \frac{\mu}{\|\mathbf r\|^3}\left[\frac{3\,\mathbf r\mathbf r^{\mathsf T}}{\|\mathbf r\|^2} - I_3\right] + \|\boldsymbol\Omega_{ie}\|^2 I_3 $$Reading the rows against the local-level version of §6.2:
- Only $-2[\boldsymbol\Omega_{ie}\times]$ survives in the velocity row, not the transport-rate term. There is no transport rate in ECEF — the frame does not rotate with the vehicle's motion over the surface — so the Coriolis term is the whole story and the $1/R$ feedback of the local-level form is gone. The Schuler loop has not disappeared; it is now implicit in the gravity-gradient block.
- $C^e_b$ appears twice in the velocity row, once for bias and once for scale factor. Same structure, same row: this is the §6.7 aliasing again, now with a third participant. Bias, scale factor and tilt all push on velocity through the same channel, and on a static pad the measurement cannot tell them apart without help.
- $I_3$ couples gyro bias into the attitude row. Sign and frame are the whole content of this block — it is what makes gyro bias observable at all, via tilt, via gravity.
- The scale-factor row is exactly zero. Scale factor is modelled as a constant, not a Gauss–Markov process: it is a manufacturing property that does not wander within a flight. Bias does wander, which is why those rows carry $-1/\tau$.
The process noise is diagonal by block and simply proportional to the propagation interval — velocity random walk on the velocity block, angle random walk on attitude, and a bias-drift term on each bias block:
$$ Q = \operatorname{diag}\big(0,\; Q_{v},\; Q_{\theta},\; Q_{b_a},\; Q_{b_g},\; Q_{s_a}\big)\,\Delta t_{\text{prop}} $$Two implementation details that are easy to underestimate. A small floor is added to every diagonal of $Q$: an exactly-zero diagonal makes the factorised update singular the moment a state becomes perfectly known. And the propagation interval is measured from the actual timestamps of consecutive filter calls, not assumed to be the nominal period — the scheduler is not guaranteed to be periodic, and assuming it is silently mis-scales $Q$ on every late cycle.
| IMU class | Accel bias | Gyro bias | Accel scale factor | Reasoning |
|---|---|---|---|---|
| Navigation-grade RLG e.g. HG9900 class |
consider | consider | estimated | Scale-factor error dominates free-inertial position error for this grade, and the axis nearest local vertical is observable under $1g$. The gyro biases are small enough to ignore over the flight and barely observable without attitude aiding. Horizontal accel bias is indistinguishable from tilt (§6.7) and the vertical one is not needed to close the budget. |
| Tactical / MEMS lower grade, larger errors |
estimated gravity-exposed axes only |
estimated | consider | Here the biases are large enough that leaving them unestimated will not close the requirement. Estimating gyro bias also substantially slows tilt-error growth. Accel bias is enabled only on axes carrying enough projected gravity to be observable. |
| Intermediate with azimuth aiding enabled |
consider | estimated | estimated | With an azimuth pseudo-measurement available, all three gyro axes become somewhat observable while stationary, so gyro bias is worth estimating alongside scale factor. |
The pattern is consistent: estimate the error that dominates your mission, and only if the pad geometry makes it observable. Estimating an unobservable state does not merely fail to help — it injects process noise that leaks into the states you can observe, through exactly the correlations that made you hope it was observable.
A practical corollary: the gravity-exposure gate from §5.2 is evaluated at the end of coarse alignment, when the axis-to-gravity geometry is first known, and it can override the per-sensor default. A filter reset re-applies the gate rather than restoring the defaults blindly.
6.4 The measurement model
Nothing external is available. Every measurement is a statement about what truth must be because the vehicle is bolted down — which is what converts an unobservable attitude problem into an observable one.
| Update | Measurement $\mathbf z$ | $H$ | $R$ reflects |
|---|---|---|---|
| Zero velocity (ZUPT) | $\hat{\mathbf v} - \mathbf 0 = \delta\mathbf v$ | $\begin{bmatrix}0 & I & 0 & 0 & 0\end{bmatrix}$ | Mechanization noise and any real pad motion — sway, wind, crew activity. Truth itself has no uncertainty. |
| Fixed position | $\hat{\mathbf r} - \mathbf r_{\text{survey}}$ | $\begin{bmatrix}I & 0 & 0 & 0 & 0\end{bmatrix}$ | Survey error, and the IMU-to-survey-point lever arm. |
| Static azimuth | $\hat\psi - \psi_{\text{ref}}$ from accumulated Earth-rate observation | $\begin{bmatrix}0 & 0 & \mathbf e_D^{\mathsf T} & 0 & 0\end{bmatrix}$ | A pseudo-measurement — correlated with data the filter already used, so $R$ must be inflated and the update throttled to a long period. |
The update itself is standard, but the numerical form is not optional at these condition numbers:
$$ K = P^-H^{\mathsf T}\big(HP^-H^{\mathsf T}+R\big)^{-1}, \qquad P^+ = (I-KH)P^-(I-KH)^{\mathsf T} + KRK^{\mathsf T} $$The Joseph form shown is symmetric by construction; the short form $P^+=(I-KH)P^-$ loses symmetry and can go indefinite over a long run with a very accurate measurement. Production systems go further and factorise, updating $U$ and $D$ in $P = UDU^{\mathsf T}$, which doubles effective precision and cannot produce a negative variance. See NASA nav-filter best practices.
Written out concretely, in the ECEF formulation of §6.3, the three residuals are almost disappointingly simple — which is the point. Each is a difference against a quantity that is known because the vehicle is stationary:
$$ \mathbf z_{\text{pos}} = \hat{\mathbf r}_{\text{ECEF}} - \mathbf r_{0,\text{ECEF}}, \qquad \mathbf z_{\text{vel}} = \hat{\mathbf v}_{\text{ECEF}} - \mathbf 0 = \hat{\mathbf v}_{\text{ECEF}} $$with $\mathbf r_{0}$ the position handed over by coarse alignment (§5.3). Both have $H = \begin{bmatrix} I_3 & 0 & \cdots \end{bmatrix}$ in the appropriate columns — a plain identity block picking off the three error states being measured, and nothing else.
The azimuth update is the only one with real structure. It compares the attitude the filter currently believes against the attitude implied by the initial alignment, and keeps only the component about the local vertical:
$$ \delta\mathbf q = \big(\mathbf q^{\text{est}}\big)^{-1} \otimes \mathbf q^{\text{obs}}, \qquad \mathbf p = \begin{bmatrix} 2\,\delta q_x & 0 & 0\end{bmatrix}^{\mathsf T}, \qquad \mathbf z_{\text{az}} = C^{\text{body}}_{\text{ref}}\;\mathbf p $$The factor of two and the single retained component are both the small-angle approximation: for a small rotation, the vector part of the error quaternion is half the rotation vector, and zeroing the other two components is what makes this an azimuth-only update rather than a full attitude reset. That approximation is only valid because coarse alignment already removed the large errors — which is exactly why the update must also be throttled to a period short enough that azimuth cannot drift out of the small-angle regime between applications.
One counter-intuitive safeguard: after an azimuth update, the azimuth variance is deliberately inflated back up if it has fallen below a threshold. Driving $\sigma_\psi$ toward zero before launch would be actively harmful — it tells the filter to stop believing any future evidence, and the true heading is still subject to wind loading and structural flex that the model does not capture. Tilt, by contrast, is left alone: it is genuinely well determined by gravity, and forcing uncertainty back into it would inject error into a good estimate.
Note also what is not in the list: there is no attitude measurement, no external heading reference, no magnetometer. Everything above is derived from the vehicle being bolted to a surveyed pad on a rotating Earth. That is the entire information budget available to ground alignment, and it is why heading takes minutes while tilt takes seconds.
6.5 Where the initial covariance comes from
$P_0$ is not a tuning knob picked to make the plots look nice. Each diagonal block is a statement about a physical quantity, with a defensible source:
| Block | Initial 1σ from | Reasoning |
|---|---|---|
| $\delta\mathbf r$ | Survey accuracy | Centimetres to decimetres. Tight, because the pad really is surveyed. |
| $\delta\mathbf v$ | Expected pad motion | Not zero. The vehicle sways; setting this to zero tells the filter the ZUPT is perfect and invites it to fit sway as sensor error. |
| $\delta\psi$ tilt | Coarse-alignment accuracy $\approx b_a/g$ | Directly from the accelerometer bias repeatability, because that is what limits levelling. A 50 µg turn-on repeatability gives ~10 arcsec. |
| $\delta\psi$ heading | Coarse heading quality | Degrees if from a short analytic alignment; much tighter if from survey. Must be generous enough to contain the truth or the filter will reject the very measurements that would fix it. |
| $\mathbf b_g$ | Turn-on repeatability, from bench data | Note: repeatability, not in-run stability. The filter is estimating what the bias is this power cycle, and run-to-run scatter is exactly that uncertainty. |
| $\mathbf b_a$ | Turn-on repeatability | Same argument. Gated by the gravity-exposed flags from §5.2. |
Worked through with round numbers for a notional navigation-grade unit at $L=45^\circ$ — illustrative values, not anyone's specification, but the reasoning is what transfers:
| Block | Bench number | → $P_0$ 1σ | Arithmetic |
|---|---|---|---|
| $\delta\mathbf r$ horiz. | Survey to 0.05 m | 0.05 m | Taken directly |
| $\delta\mathbf v$ horiz. | Pad sway ~0.1 m/s RMS | 0.1 m/s | Not zero — the ZUPT is not perfect, and saying it is invites the filter to fit sway as bias |
| $\delta\psi$ tilt | Accel repeatability 50 µg | ≈ 10 arcsec | $b_a/g = 50\times10^{-6}$ rad $= 5\times10^{-5}\times206265$ |
| $\delta\psi$ heading | Coarse analytic align | ≈ 0.5–2° | A few seconds of averaging against $\Omega\cos L$ — deliberately generous so the truth is contained |
| $\mathbf b_g$ | Turn-on repeatability 0.01 °/h | 0.01 °/h | $= 4.85\times10^{-8}$ rad/s. Sets the heading floor at $b_g/(\Omega\cos L)\approx 200$ arcsec |
| $\mathbf b_a$ | Turn-on repeatability 50 µg | 50 µg | Gated to gravity-exposed axes only (§5.2) |
Watch the consequence: the filter drives uncertainty down as $1/\sqrt T$ until it reaches a floor set by bias, and no additional dwell helps. Latitude drives the heading floor as $1/\cos L$:
6.6 Consider states — bias is not the only parameter
Some error sources must be accounted for but should not be estimated: gravity-model error, the IMU-to-reference-point lever arm, survey error, and any sensor parameter with no excitation in this phase (scale factors, on a static pad). Estimating them lets the filter fit noise; ignoring them yields an optimistic covariance. The consider filter resolves this by partitioning:
$$ \begin{bmatrix}\delta\dot{\mathbf x}\\ \dot{\mathbf c}\end{bmatrix} = \begin{bmatrix}F & F_c\\ 0 & 0\end{bmatrix} \begin{bmatrix}\delta\mathbf x\\ \mathbf c\end{bmatrix} + \begin{bmatrix}\mathbf w\\ \mathbf 0\end{bmatrix}, \qquad \mathbf z = H\,\delta\mathbf x + H_c\,\mathbf c + \boldsymbol\nu $$The gain is computed as if $\mathbf c$ did not exist, so no estimate of $\mathbf c$ is ever formed and the filter cannot chase it. But the covariance carries its contribution, with the sensitivity $S = \partial\delta\hat{\mathbf x}/\partial\mathbf c$ propagated alongside $P$:
$$ P^{\text{true}} = P^{\text{filter}} + S\,P_{cc}\,S^{\mathsf T} $$So the reported uncertainty answers the question that actually matters operationally: how wrong could I be, including the things I chose not to estimate?
Estimate / consider / ignore is a decision per error source, and "ignore" needs a number justifying it. Full treatment on Fine alignment and Linear covariance analysis.
6.7 The one degeneracy you cannot filter away
A horizontal accelerometer bias and a tilt error enter the horizontal specific force identically:
$$ f_{\text{horiz}} = \underbrace{g\,\delta\theta}_{\text{tilt}} + \underbrace{b_a}_{\text{bias}} + \text{noise} $$One measurement, two unknowns, the same structure up to the constant $g$. The observable quantity is the combination $g\,\delta\theta + b_a$; the direction $(\delta\theta, b_a)\propto(1,-g)$ is in the null space and no dwell time recovers it. The filter converges on whatever mixture makes the static solution correct — which is the right answer to the question the measurement asks, and means that on any static test the deterministic accelerometer terms are cancelled by construction. Separation requires changing the geometry: rotating the unit (§9.2) or flying.
7 · How the two rates actually interlock
Everything above describes what the filter computes. This section is about when — and it is where most of the real engineering lives, because the mechanization runs at sensor rate while the filter runs perhaps a hundred times slower. Two questions have non-obvious answers: what does the filter do about all the motion it never saw, and what happens to a correction that is already stale when it arrives.
7.1 The bucket buffer — why not one Φ per sample
The filter needs $\Phi$ over the whole interval since its last run. The naive options are both bad: form a full $\Phi$ every IMU sample and multiply them (expensive, and most of the work is thrown away), or linearise once over the entire second (cheap, and wrong under any dynamics, because $F$ depends on the current attitude and specific force which have both changed).
The resolution is to accumulate at sensor rate but only as sums. Each bucket covers a fixed short span and holds the running sum of the coupling terms over the samples that fell in it, together with its own start and end timestamps. No matrix exponential, no matrix product — just addition, at sensor rate. When the bucket fills, the writer advances to the next slot in a circular buffer.
At filter time the sums are normalised by the frame count to recover a mean $F$ per bucket, and $\Phi$ is assembled as a chained product over the buckets the interval spans:
$$ \Phi(t_{\text{prev}}\!\to t_{\text{now}}) \;=\; \Phi_{\text{end}}^{\text{partial}} \cdot \Big(\textstyle\prod_{k}\Phi_k^{\text{full}}\Big) \cdot \Phi_{\text{start}}^{\text{partial}} $$The two end factors are the important detail. The filter's interval boundaries do not land on bucket boundaries, so the first and last buckets are used with a shortened $\Delta t$ — the sliver from $t_{\text{prev}}$ to the end of its bucket, and from the start of the last bucket to $t_{\text{now}}$. The buffer must therefore be long enough to straddle both propagation times; sizing it is (buckets − 1) × bucket span > longest propagation interval + scheduling latency.
7.2 The correction is stale on arrival — so propagate it
The filter's correction is computed from a state valid at $t_{\text{now}}$, but by the time it reaches the mechanization, more samples have been integrated. Applying it directly would correct the present using a statement about the past. So the same $\Phi$ machinery is reused in the other direction:
$$ \delta\mathbf x_{\text{apply}} = \Phi\big(t_{\text{now}} \to t_{\text{current}}\big)\; \delta\mathbf x_{\text{filter}} $$then the navigation state is corrected and the sensor-error states are accumulated into the running compensation parameters of §1.2 — accumulated, not replaced, because each filter cycle estimates the remaining error after the previous correction was already being applied.
There is also a deliberate asymmetry worth noticing: the filter is feed-forward only. It never writes directly into the mechanization's integration loop; it publishes a correction that the fast loop chooses to consume at a well-defined point. That is what allows the navigation solution to keep meeting a hard real-time deadline while the filter takes as long as it needs, and what allows the filter to be reset or even to fail without stopping the vehicle from navigating.
The same pattern generalises beyond alignment. In flight the slow loop fuses GNSS instead of pad pseudo-measurements, and measurements arrive with real latency — so the buffered-history approach becomes load-bearing rather than merely efficient: a measurement valid 200 ms ago is applied against the $\Phi$ that spans from that epoch, not against the current state. See Rocket navigation for the flight-mode architecture.
7.3 The complete cycle, written out
The sections above described the architecture in words. What follows is the arithmetic: every index, every symbol, and a worked cycle for both the pad case (pseudo-measurements) and the flight case (GNSS). Read the notation table first — the rest is unambiguous once the indices are pinned down.
7.4 Notation and timebase
There are two clocks and it is essential to keep them apart. The fast index $k$ counts IMU samples; the slow index $m$ counts filter cycles. Between two filter cycles there are $N$ IMU samples:
$$ N \;=\; \frac{T_{\text{sfm}}}{\Delta t} \;=\; f_{\text{imu}}\,T_{\text{sfm}}, \qquad\text{e.g. } f_{\text{imu}} = 300\ \text{Hz},\; T_{\text{sfm}} = 1\ \text{s} \;\Rightarrow\; N = 300 $$| Symbol | Meaning | Lives in | Units |
|---|---|---|---|
| Indices and time | |||
| $k$ | IMU sample index (fast loop) | NM | — |
| $m$ | Filter cycle index (slow loop) | SFM | — |
| $N$ | IMU samples per filter cycle | both | — |
| $\Delta t$ | IMU sample interval, $t_{k+1}-t_k$ | NM | s |
| $T_{\text{sfm}}$ | Nominal filter period; not assumed — see $\Delta t_m$ | SFM | s |
| $\Delta t_m$ | Actual propagation span, $t_m - t_{m-1}$, from timestamps | SFM | s |
| $t_{k,\text{mid}}$ | Midpoint of interval $k$, $t_k + \Delta t/2$ | NM | s |
| Sensor data at sample $k$ | |||
| $\Delta\mathbf v_k$ | Velocity increment, body axes, over interval $k$ | NM | ft/s |
| $\Delta\boldsymbol\theta_{A,k}$ | Attitude increment, start → midpoint | NM | rad |
| $\Delta\boldsymbol\theta_{B,k}$ | Attitude increment, midpoint → end | NM | rad |
| Navigation state (the NM's property) | |||
| $\mathbf r_k,\;\mathbf v_k$ | Position, velocity in the reference frame | NM | ft, ft/s |
| $\mathbf q_k$ | Attitude quaternion, body → reference, valid at $t_k$ | NM | — |
| $C_k,\;C_{k,\text{mid}}$ | Rotation matrices at end and midpoint of interval $k$ | NM | — |
| Uncertainty (the SFM's property) | |||
| $\delta\mathbf x_m$ | Error-state estimate, 18×1 (§6.3) | SFM | mixed |
| $P_m$ | Error-state covariance, 18×18, held as $U D U^{\mathsf T}$ | SFM | mixed |
| $\Phi_{m}$ | Discrete transition over $[t_{m-1},t_m]$, 18×18 | SFM | — |
| $Q_m$ | Process noise over the same span | SFM | mixed |
| $H,\;R,\;K$ | Measurement Jacobian, noise variance, gain | SFM | mixed |
| The two shared objects | |||
| $\mathcal B$ | Bucket buffer: accumulated $F$-couplings, NM → SFM | shared | mixed |
| $\mathbf c_m$ | Control vector: $-\delta\hat{\mathbf x}_m$ plus its timestamp, SFM → NM | shared | mixed |
| $\tau_m$ | Toggle: flips when $\mathbf c_m$ is fresh | shared | — |
Superscript convention: $(-)$ is before a measurement update (a priori), $(+)$ is after (a posteriori). A hat denotes an estimate. Note $\Delta t_m$ rather than $T_{\text{sfm}}$ in every equation below — the slow loop is not guaranteed periodic, and using the nominal period would mis-scale both $\Phi$ and $Q$ on any late cycle.
7.5 The fast loop: state, at every $k$
Step 1 — compensate, using the sensor-error parameters currently latched (these change only when a new correction arrives, §7.7):
$$ \Delta\mathbf v_k^{c} = \Delta\tilde{\mathbf v}_k + \frac{\hat{\mathbf b}_a\,\Delta t}{1-\hat{\mathbf s}_a}, \qquad \Delta\boldsymbol\theta_{A,k}^{c} = \Delta\tilde{\boldsymbol\theta}_{A,k} + \frac{\tfrac12\hat{\mathbf b}_g\,\Delta t}{1-\hat{\mathbf s}_g} \quad\text{(and likewise for }B) $$Step 2 — attitude to the midpoint, then to the end. $\otimes$ is quaternion product; $\boldsymbol\omega_{\text{ref}}$ is the reference frame's own rotation rate:
$$ \mathbf q_{k,\text{mid}} = \mathbf q\big(\!-\!\Delta\boldsymbol\theta_{A,k}^{c}\big)\otimes\mathbf q_k \otimes\mathbf q\!\left(\tfrac12\boldsymbol\omega_{\text{ref}}\Delta t\right), \qquad \mathbf q_{k+1} = \mathbf q\big(\!-\!\Delta\boldsymbol\theta_{B,k}^{c}\big)\otimes\mathbf q_{k,\text{mid}} \otimes\mathbf q\!\left(\tfrac12\boldsymbol\omega_{\text{ref}}\Delta t\right) $$Step 3 — velocity and position, rotating by the midpoint attitude (§1.3):
$$ \Delta\mathbf v_k^{\text{ref}} = C_{k,\text{mid}}\,\Delta\mathbf v_k^{c} - 2\,\boldsymbol\omega_{ie}\times\mathbf v_k\,\Delta t + \mathbf g(\mathbf r_k)\,\Delta t $$ $$ \mathbf r_{k+1} = \mathbf r_k + \Big(\mathbf v_k + \tfrac12\Delta\mathbf v_k^{\text{ref}}\Big)\Delta t, \qquad \mathbf v_{k+1} = \mathbf v_k + \Delta\mathbf v_k^{\text{ref}} $$Step 4 — accumulate into the current bucket. This is the only thing the fast loop does for the filter, and it is addition only. For a bucket $j$ spanning some set of samples $\mathcal K_j$:
$$ \mathcal B_j \mathrel{+}= F\big(\mathbf r_k,\;C_{k,\text{mid}},\;\mathbf a_k\big), \qquad n_j \mathrel{+}= 1, \qquad t^{\text{end}}_j \leftarrow t_{k+1} $$where $F(\cdot)$ means the handful of 3×3 coupling blocks of §6.3 — gravity gradient, the tilt-to-velocity term, the bias and scale-factor columns — each summed independently. No matrix exponential and no matrix product occurs at rate $f_{\text{imu}}$.
Step 5 — publish. The state goes to flight control every cycle, and a copy $(\mathbf r,\mathbf v,\mathbf q)$ with its timestamp is written into a ring buffer for later interpolation (§7.8).
7.6 The slow loop: uncertainty, once per $m$
Step 1 — build $\Phi_m$ from the buckets. Normalise each bucket's sum by its frame count to recover a mean $F$, form a per-bucket transition, and chain them:
$$ \bar F_j = \frac{1}{n_j}\mathcal B_j, \qquad \Phi_j = I + \bar F_j\,\Delta t_j + \tfrac12\big(\bar F_j\Delta t_j\big)^2 + \dots $$ $$ \Phi_m = \Phi^{\text{part}}_{j_{\text{end}}}\!\left(\delta t_{\text{end}}\right) \cdot \!\!\prod_{j=j_{\text{start}}+1}^{\,j_{\text{end}}-1}\!\! \Phi_j \cdot \Phi^{\text{part}}_{j_{\text{start}}}\!\left(\delta t_{\text{start}}\right) $$with the two partial spans being exactly the slivers left over because the filter's boundaries do not land on bucket boundaries:
$$ \delta t_{\text{start}} = t^{\text{end}}_{j_{\text{start}}} - t_{m-1}, \qquad \delta t_{\text{end}} = t_m - t^{\text{start}}_{j_{\text{end}}} $$Step 2 — one time update for the whole span:
$$ \delta\mathbf x^-_m = \Phi_m\,\delta\mathbf x^+_{m-1} \;(=\mathbf 0), \qquad P^-_m = \Phi_m\,P^+_{m-1}\,\Phi_m^{\mathsf T} + Q_m, \qquad Q_m = \operatorname{diag}(\dots)\,\Delta t_m $$$\delta\mathbf x^+_{m-1}=\mathbf 0$ because the correction was handed to the NM and the error state was reset — the filter's job each cycle is to estimate the error remaining. Only the covariance carries memory across cycles. This is what makes it a feedback (reset) formulation rather than a feed-forward one.
Step 3 — measurement updates, in a fixed order, each component as an independent scalar update:
$$ \text{for each scalar } i:\quad K_i = \frac{P\,\mathbf h_i^{\mathsf T}}{\mathbf h_i P\,\mathbf h_i^{\mathsf T} + R_i}, \qquad \delta\mathbf x \mathrel{+}= K_i\big(z_i - \mathbf h_i\,\delta\mathbf x\big), \qquad P \leftarrow \big(I - K_i\mathbf h_i\big)P $$On the pad the three updates of §6.4 run in the order position → velocity → azimuth. In flight they are replaced by GNSS (§7.8). In practice $P$ is never formed during the update at all: $U$ and $D$ are updated directly and $P = UDU^{\mathsf T}$ is reconstituted only when needed for output.
Step 4 — emit the control vector. By convention it is the negative of the estimated error, stamped with the epoch it is valid at, and the toggle is flipped:
$$ \mathbf c_m = -\,\delta\hat{\mathbf x}^+_m, \qquad t(\mathbf c_m) = t_m, \qquad \tau_m = \lnot\,\tau_{m-1} $$7.7 The hand-back: what crosses the boundary
This is the part that is easy to get wrong, because the correction is already stale when it arrives. Suppose the filter finished at $t_m$ but the fast loop is now at sample $k^\star$, with $t_{k^\star} > t_m$. The NM notices $\tau$ changed, and does three things:
(a) Propagate the correction forward — reusing the same buckets, but only over the 9 PVA states, because the sensor-parameter rows of $F$ are zero or nearly so:
$$ \delta\mathbf x^{\text{PVA}}_{\text{apply}} = \Phi^{\text{PVA}}\big(t_m \to t_{k^\star}\big)\;\mathbf c_m^{\text{PVA}}, \qquad \delta\mathbf x^{\text{sensor}}_{\text{apply}} = \mathbf c_m^{\text{sensor}} \;\;\text{(copied, not propagated)} $$(b) Apply to the navigation state — additive on position and velocity, multiplicative on attitude:
$$ \mathbf r_{k^\star} \mathrel{+}= \delta\mathbf r, \qquad \mathbf v_{k^\star} \mathrel{+}= \delta\mathbf v, \qquad \mathbf q_{k^\star} \leftarrow \mathbf q\big(\!-\!\delta\boldsymbol\theta\big)\otimes\mathbf q_{k^\star} $$(c) Accumulate the sensor errors into the parameters used by step 1 of the fast loop — accumulate, not overwrite:
$$ \hat{\mathbf b}_a \mathrel{+}= \delta\mathbf b_a,\qquad \hat{\mathbf b}_g \mathrel{+}= \delta\mathbf b_g,\qquad \hat{\mathbf s}_a \mathrel{+}= \delta\mathbf s_a $$| Direction | Contents | When | Notably absent |
|---|---|---|---|
| NM → SFM | Current $\mathbf r,\mathbf v,\mathbf q$ and their timestamp; the initial $\mathbf r_0,\mathbf q_0$ from coarse alignment; latitude/longitude; the bucket buffer; the gravity-exposed axis flags | Every filter cycle $m$ | Nothing about uncertainty — the NM has no $P$ |
| SFM → NM | The control vector (18 corrections + epoch + toggle); a few scalar health $\sigma$s for telemetry; a sequence number | When the filter completes | Not $P$, not $\Phi$, not the gain. The covariance never leaves the SFM |
7.8 A full cycle, both cases
Case A — on the pad. No external sensor. Take $N=300$, and suppose the filter ran at $t_m$ and the fast loop is at $k^\star$ when the result lands:
Case B — in flight, with GNSS. Two things change, and both are about time. The measurement is not valid at $t_m$ — it is valid at the receiver's own epoch $t_{\text{pps}}$, typically some hundreds of milliseconds earlier. And the measurement is of the antenna, not the navigation reference point.
The pseudorange row of $H$ is the line-of-sight unit vector, which is what makes GNSS observe position directly and attitude not at all:
$$ \mathbf h_s = \begin{bmatrix} -\hat{\mathbf u}_s^{\mathsf T} & \mathbf 0 & -\hat{\mathbf u}_s^{\mathsf T}\big[C\,\mathbf l_{\text{ant}}\times\big] & \cdots & 1 & \cdots \end{bmatrix}, \qquad \hat{\mathbf u}_s = \frac{\mathbf r_s - \mathbf r_{\text{ant}}}{\|\mathbf r_s - \mathbf r_{\text{ant}}\|} $$The middle block is the only reason a position measurement says anything about attitude at all: rotating the vehicle moves the antenna on its lever arm. With a short lever arm that term is small, which is why GNSS alone aligns attitude slowly and why the manoeuvres matter more than the fixes.
Counting the epochs in Case B: the measurement is valid at $t_{\text{pps}}$, the filter's covariance is valid at $t_m$, and the correction is applied at $t_{k^\star}$ — three distinct times in one cycle, with $t_{\text{pps}} < t_m < t_{k^\star}$. Every one of them has to be carried explicitly. This is the single biggest source of subtle error in a two-rate navigator, and the reason every structure above carries a timestamp rather than an assumed period.
8 · Schuler oscillation in a strapdown INS
Here is the result that makes inertial error behaviour counter-intuitive: horizontal error does not grow without bound — it oscillates, with a period of 84.4 minutes, and that period is the same for every stationary IMU on Earth regardless of quality.
8.1 The causal chain, step by step
Before any algebra, the mechanism in words, because the loop is easy to state and easy to get backwards. Put an IMU on a level surface and give its estimate of "down" a small error $\delta\theta$ — the hardware is perfect, only the estimated orientation is wrong:
So the headline result is a good one: a pure tilt error does not run away. It converts back and forth between tilt and velocity error indefinitely, and both stay bounded. That is the Schuler mechanism working in your favour — and it is also why a bias, which drives the loop from outside rather than merely setting its initial condition, behaves completely differently (§8.3).
8.2 The same thing as equations
Take the two coupled error equations from the $F$ matrix of §6.2, keeping only the horizontal channel and one axis for clarity. Step ③ is the first equation; step ⑥ is the second:
$$ \delta\dot v = g\,\delta\theta + \alpha + \nu(t) \qquad\text{(tilt mis-resolves gravity; }\alpha\text{ = accel bias)} $$ $$ \delta\dot\theta = -\frac{\delta v}{R} + \beta + n(t) \qquad\text{(transport rate feeds velocity error back into tilt; }\beta\text{ = gyro bias)} $$The second equation is the crucial one and it is easy to miss why it exists. The mechanization continuously rotates its idea of "down" to follow the curved Earth as it believes it is moving. If it thinks it is moving at $\delta v$ when it is not, it rotates its local-level frame at $\delta v/R$ — creating a tilt error out of a velocity error. That is a genuine feedback path, and it is negative.
Eliminating $\delta v$ with the sensor terms zero gives a simple harmonic oscillator:
$$ \delta\ddot\theta + \frac{g}{R}\,\delta\theta = 0, \qquad \omega_s = \sqrt{\frac{g}{R}} = 1.24\times10^{-3}\ \mathrm{rad/s}, \qquad T_s = \frac{2\pi}{\omega_s} \approx 84.4\ \mathrm{min} $$With initial conditions $\delta\theta_0$ and $\delta v_0$ the solution is a constant-amplitude oscillation — nothing external drives it, and nothing damps it:
$$ \delta\theta(t) = A\cos(\omega_s t + \varphi), \qquad A = \sqrt{\delta\theta_0^2 + \Big(\frac{\delta v_0}{R\omega_s}\Big)^2}, \qquad \varphi = \operatorname{atan2}\!\Big(\frac{\delta v_0}{R\omega_s},\,\delta\theta_0\Big) $$ $$ \delta v(t) = R\omega_s A\,\sin(\omega_s t + \varphi) $$8.3 Two different mechanisms: initial condition vs forcing
This is the heart of it, and it is the distinction that makes a drift test interpretable. A tilt error and a sensor bias both produce velocity and position error, but they enter the loop in fundamentally different ways:
A tilt error sets the initial condition
$\delta\theta_0$ is where the oscillator starts. Nothing continues to drive it. The loop converts that initial energy back and forth between tilt and velocity forever, at constant amplitude.
Bounded. The mean over a full cycle is zero. Averaged over many cycles it contributes nothing to a position rate.
A gyro bias forces it continuously
$\beta$ is a persistent input. Every second, the gyro reports rotation that is not happening, so tilt is being manufactured continuously — the loop never gets to give the error back.
Unbounded in position. The oscillation acquires a non-zero mean, and integrating a non-zero mean is a ramp.
The mathematics makes this exact. Differentiate the velocity equation and substitute the tilt equation:
$$ \delta\ddot v + \omega_s^2\,\delta v = g\beta + \dot\alpha $$Look at what happened to the two biases. The accelerometer bias $\alpha$ appears only as its derivative — and a constant bias has zero derivative, so it vanishes from the forcing entirely. It survives only through the initial condition it imposes, $\delta\dot v|_0 = \alpha$: a kick at $t=0$ and then nothing. The gyro bias $\beta$ survives undifferentiated, as a constant forcing term on the right-hand side. A constant force on a harmonic oscillator does not change its frequency; it shifts its equilibrium. The oscillation now rings about $R\beta$ instead of about zero:
Gyro bias β — offset, and a ramp
$$ \delta v(t) = R\beta\,(1-\cos\omega_s t) $$ $$ \delta p(t) = R\beta\!\left(t - \frac{\sin\omega_s t}{\omega_s}\right) $$Velocity oscillates about a mean of $R\beta$ — never negative, always biased one way. Position has a genuine ramp of slope $R\beta$. This is the only term that produces a position drift rate.
Accel bias α — bounded
$$ \delta v(t) = \frac{\alpha}{\omega_s}\sin\omega_s t $$ $$ \delta p(t) = \frac{\alpha}{\omega_s^2}(1-\cos\omega_s t) $$Both oscillate about zero and stay bounded forever. No ramp. A 100 µg bias gives a bounded position error of about 640 m — large, but it does not accumulate.
8.4 Why gyro bias dominates the position-error rate
Now the consequence that matters for a health check. Two metrics are normally computed from a free-inertial run: an RMS velocity error and a radial position error rate — the least-squares slope of radial position error against time. They are sensitive to different things, and the difference follows directly from §8.3:
$$ \text{RPE rate} \;=\; \frac{\displaystyle\int_0^T t\,\delta p(t)\,\mathrm dt}{\displaystyle\int_0^T t^2\,\mathrm dt} $$A least-squares slope through the origin is a weighted mean, with weight $t$. Feed it a zero-mean oscillation and the positive and negative half-cycles cancel — the answer tends to zero as the window covers more cycles. Feed it a ramp and you recover the ramp slope exactly. So:
| Error source | Enters as | $\delta p(t)$ shape | RMS velocity | RPE rate |
|---|---|---|---|---|
| Gyro bias β | Forcing term | Ramp $R\beta t$ plus oscillation | Contributes | Dominates — the only ramp |
| Initial tilt $\delta\theta_0$ | Initial condition | Bounded oscillation about 0 | Contributes | ≈ 0 over many cycles |
| Accel bias α | Initial condition only | Bounded oscillation about 0 | Contributes | ≈ 0 — no ramp |
| Gyro ARW | Stochastic forcing | Random walk, grows as $\sqrt t$ | Contributes strongly | Adds scatter, zero mean |
| Accel VRW | Stochastic forcing | Random walk, small | Negligible | Negligible |
For the gyro-bias-only case both metrics are closed-form, and their ratio is a pure number with no sensor parameters in it at all — a useful consistency check on a pair of thresholds:
$$ \mathrm{RMS}[\delta v] = \sqrt{\tfrac32}\,R\beta, \qquad \text{RPE rate} \approx R\beta \qquad\Longrightarrow\qquad \frac{\mathrm{RMS}[\delta v]}{\text{RPE rate}} = \sqrt{\tfrac32} \approx 1.225 $$Which is why the drift-test page treats two thresholds sitting at exactly this ratio as evidence that one was derived from the other rather than independently.
8.5 The random walks
These need variance propagation, because they have no deterministic waveform:
$$ \sigma_{\delta v}^{\text{ARW}} = R\omega_s\sqrt{Q_n\!\left(\frac{t}{2}-\frac{\sin 2\omega_s t}{4\omega_s}\right)}, \qquad \sigma_{\delta v}^{\text{VRW}} = \sqrt{Q_\nu\!\left(\frac{t}{2}+\frac{\sin 2\omega_s t}{4\omega_s}\right)} $$Both grow as $\sqrt t$ and the loop restrains both identically — only the sign of the $\sin$ term differs. In practice ARW dominates by orders of magnitude, because it enters multiplied by $R\omega_s \approx 7906$ while VRW enters with unit gain.
Run the loop below. Start with a tilt error and no bias to see the pure undamped oscillation; add an accelerometer bias and watch the oscillation shift onto a new centre; add gyro bias to see the ramp appear. Then try each damping scheme:
8.6 Three natural frequencies, and one of them diverges
| Mode | Period / time constant | Cause | Stable? |
|---|---|---|---|
| Schuler | 84.4 min | Tilt ↔ velocity through gravity and transport rate | Yes — oscillatory, bounded |
| Foucault | 24 h / sin L | Earth rotation modulating the Schuler oscillation — it appears as a slow envelope on the 84-minute ringing | Yes — a modulation |
| Vertical | τ ≈ 570 s | Altitude error → weaker modelled gravity → apparent upward acceleration → larger altitude error | No — exponential divergence |
The vertical channel deserves its own equation because its sign is the opposite of the horizontal case:
$$ \delta\ddot h = \frac{2g}{R}\,\delta h \quad\Longrightarrow\quad \delta h(t)\sim e^{t/\tau},\qquad \tau=\sqrt{\frac{R}{2g}}\approx570\ \mathrm s $$Positive feedback, so errors double every few minutes. Every terrestrial INS therefore constrains height externally — a baro-altimeter in flight, the surveyed height during alignment, GNSS when available. "An INS drifts slowly" describes the horizontal channels only.
8.7 Damping it, and why internal damping is a trade
The oscillation is undamped because the loop has no dissipation. Two ways to add some, and they are not equivalent:
Internal damping — trades, does not fix
Feed the system's own velocity error back into the loop. The oscillation decays, but the system now settles onto a steady-state offset instead of oscillating about the right answer. You have exchanged a bounded oscillation for a bounded bias — sometimes desirable (a ship's INS wants a quiet output), but no information was added.
External velocity aiding — the only real fix
An independent velocity reference — GNSS, Doppler, odometry, or a zero-velocity constraint while stationary — supplies new information, which both damps the loop and removes the error. This is why the ZUPT of §6.4 works so well and why GNSS-INS is the workhorse in flight.
A fuller treatment, including the full menu of suppression methods and the Foucault modulation, is on Schuler oscillation in strapdown INS.
9 · Calibration — where the numbers come from
Every coefficient in §1.2 and every entry in $P_0$ and $Q$ traces to a measurement made on a bench. This is the part of inertial navigation that is least glamorous and most decisive.
9.1 Allan variance — separating the noise processes
Take a long static log, split it into bins of length $\tau$, and compute the variance of the differences of adjacent bin averages:
$$ \sigma_A^2(\tau) = \frac{1}{2(N-1)}\sum_{k=1}^{N-1}\big(\bar y_{k+1}-\bar y_k\big)^2, \qquad \bar y_k = \frac{1}{\tau}\int_{t_k}^{t_k+\tau}\! y(t)\,\mathrm dt $$The differencing is what makes this useful: it is insensitive to a constant offset, so what remains is purely the noise structure. Each physical process contributes a known power of $\tau$, so plotting $\sigma_A(\tau)$ on log-log axes turns identification into reading slopes:
| Slope | Process | Read as | Goes into |
|---|---|---|---|
| $-1$ | Quantization noise | $\sqrt3\,Q/\tau$ | Usually negligible in the filter |
| $-\tfrac12$ | White noise — ARW (gyro), VRW (accel) | $N/\sqrt\tau$; read $N$ at $\tau=1$ s | $Q$ — the dominant process-noise term |
| $0$ | Bias instability (flicker floor) | The minimum of the curve, $\times\sqrt{2\ln2/\pi}$ | FOGM steady-state σ, and the best achievable averaging |
| $+\tfrac12$ | Rate random walk | $K\sqrt{\tau/3}$ | $Q$ for the bias state |
| $+1$ | Rate ramp | $R\,\tau/\sqrt2$ | Usually a thermal trend to be removed |
The total is the root-sum-square of the terms, which gives the curve its characteristic bathtub shape. The minimum is the single most quoted number — it is the bias instability, and the $\tau$ at which it occurs is the longest averaging time that still helps. Averaging beyond it makes things worse, because bias wander has started to dominate the white noise you were trying to average down.
9.2 Rate-table testing — scale factor and misalignment
A precision turntable applies a known angular rate, which is the only way to observe a parameter that multiplies the input. Mount the unit, command a rate, and regress output against input:
$$ \tilde\omega_i = (1+S_i)\,\omega^{\text{cmd}}_i + b_i + \sum_{j\ne i} M_{ij}\,\omega^{\text{cmd}}_j + \eta $$The procedure, and the reason for each step:
- Multiple rate magnitudes. Scale factor is the slope and bias the intercept of output-vs-input. A single rate gives one point, and infinitely many (slope, intercept) pairs pass through one point — the two are unidentifiable. This is the single most important thing about the test.
- Both directions. Reversing the rate flips the sign of the scale-factor contribution while the bias stays put, which separates them robustly and also exposes scale-factor asymmetry — a different gain for positive and negative rates, common in some technologies.
- Rates spanning the operational range. Scale factor is not perfectly linear; testing only at low rate tells you nothing about behaviour at the rates the vehicle will actually see.
- Each axis on the table axis in turn. Commanding rate about one axis while observing the others gives the off-diagonal misalignment terms $M_{ij}$ directly.
- Least squares over all points. With $n$ rates in 2 directions you have $2n$ equations for a handful of parameters — solve in the least-squares sense, and the residual is your confidence in the result.
Drag "rates used" down to 1 in the sim below and watch the estimate become meaningless — that is the degeneracy, and it is why an acceptance procedure specifies a rate schedule:
9.3 Multi-position (tumble) testing — accelerometer bias and scale
Gravity is a free, extremely stable, precisely known 1 g input. Rotating the unit through known orientations projects it onto the sensing axes in known ways:
$$ \tilde{\mathbf f}^b_{(m)} = (I+S_a+M_a)\,C^b_{n,(m)}\,\mathbf g^n + \mathbf b_a + \boldsymbol\eta $$Stack the positions and solve. The classic six-position test puts each axis alternately up and down, which is elegant because the sum and difference of an up/down pair separate the two parameters immediately:
$$ b_a = \frac{\tilde f_{\text{up}} + \tilde f_{\text{down}}}{2}, \qquad 1 + S_a = \frac{\tilde f_{\text{up}} - \tilde f_{\text{down}}}{2g} $$The bias is the average of the two readings and the scale factor comes from their difference. More positions (12, 24) add redundancy and expose misalignment and non-linearity. Note that this works for exactly the reason a static alignment cannot separate bias from tilt (§6.7): rotating the sensor modulates a sensor-fixed error while the reference stays put. Geometry is what breaks the degeneracy.
9.4 Repeatability, and thermal
Two more tests that do not fit the above pattern but matter more than either:
- Turn-on repeatability. Power cycle many times, re-estimating the bias each time. The scatter of those estimates is what $P_0$ must contain (§6.5). A unit can have superb in-run stability and poor repeatability, and for a system that aligns fresh before every mission, repeatability is what you actually care about.
- Thermal calibration. Map bias and scale factor against temperature, then compensate in real time from the unit's own temperature sensors. Biases are strongly temperature-dependent, and a thermal gradient across the unit is a different and harder problem than a uniform temperature — which is why warm-up transients get their own specification.
9.5 From test data to filter parameters
| Filter quantity | Comes from | Test |
|---|---|---|
| $Q$ white-noise terms | ARW, VRW coefficients | Allan variance, slope −½ at τ=1 s |
| $Q$ bias-state terms | FOGM σ and τ | Allan variance minimum and its location |
| $P_0$ bias blocks | Turn-on repeatability | Many-power-cycle test |
| $P_0$ tilt block | $b_a/g$ from accel repeatability | Tumble + repeatability |
| Compensation $\hat S$, $\hat M$ | Scale factor, misalignment | Rate table, tumble |
| Consider-parameter $P_{cc}$ | Un-estimated residuals | Whatever the above leaves over |
The bench-procedure view of all of this, with the test-design reasoning, is on IMU acceptance testing.
10 · Grades of IMU
Representative error levels by grade — order-of-magnitude, vendor-typical:
| Grade | Gyro bias | Gyro ARW | Accel bias | Unaided drift | Self-align? | Typical technology |
|---|---|---|---|---|---|---|
| Consumer MEMS | 10–100 °/h | 0.5–2 °/√h | 1–50 mg | km in seconds–minutes | No | Vibratory MEMS |
| Industrial MEMS | 1–10 °/h | 0.1–0.3 °/√h | 0.5–3 mg | tens–hundreds m/min | No | High-grade MEMS |
| Tactical | 0.1–1 °/h | 0.02–0.1 °/√h | 0.1–1 mg | ~1 nmi/h aided | Marginal | FOG, high-end MEMS |
| Navigation | 0.001–0.01 °/h | 0.002–0.02 °/√h | 10–50 µg | ~1 nmi/h unaided | Yes, minutes | RLG, FOG, HRG |
| Strategic | < 0.001 °/h | < 0.001 °/√h | < 1–10 µg | metres/h | Yes, precise | RLG, ESG, HRG |
Conversions: 1 °/h = 4.848×10⁻⁶ rad/s; 1 mg = 9.807×10⁻³ m/s²; 1 nmi = 1852 m. Earth rate is 15.041 °/h — a gyro must resolve well below that to gyrocompass at all, which is the practical definition of "navigation grade." Part-level detail is on Hardware — IMUs.
The gyrocompassing limit is worth seeing directly. Push latitude toward the pole and watch achievable heading accuracy collapse no matter how long you average, because the north-pointing signal is only $\Omega\cos L$:
10.1 A worked example: the HG9900 class
The Honeywell HG9900 is a useful concrete anchor for the "navigation grade" row above, because it is the unit actually flown on launch vehicles and its broad characteristics are published. It pairs ring-laser gyros with precision quartz resonant accelerometers in a single sealed enclosure with its own processor, and it is the sensor the whole of §5–§8 is implicitly written about.
| Property | Representative figure | Consequence for the software above |
|---|---|---|
| Gyro technology | Ring-laser (RLG) | No moving parts, no g-sensitivity worth modelling, and output is naturally an angle increment — the interferometer counts fringes, which is $\Delta\theta$ (§1.1). |
| Accelerometer technology | Quartz resonant / vibrating beam | Frequency output integrated to a velocity increment. Excellent scale-factor stability, which is why scale factor is worth carrying as an estimated state (§6.3). |
| Gyro bias stability | ≈ 0.003 °/h | Five thousand times smaller than Earth rate, so gyrocompassing closes comfortably — this is what makes self-alignment in minutes possible at all. |
| Angle random walk | ≈ 0.002 °/√h | Sets the noise floor that fine alignment asymptotes to (§6.5), and the $Q_\theta$ block. |
| Accel bias stability | ≈ 25 µg | Small enough that leaving accel bias as a consider state still closes the flyout budget. |
| Accel scale factor | tens of ppm | The dominant free-inertial position error for this grade — hence estimated, not considered. |
| Output rate | a few hundred Hz | Several IMU messages per control cycle, all of which must be integrated (§1.3). |
| Interface | Serial / bus, with built-in test | Supplies the BIT word that drives the health logic below. |
Figures are order-of-magnitude, from published product literature; exact numbers are configuration- and variant-dependent and belong in the vendor's specification, not a blog. What matters here is the ratio between them, because that is what selects the estimated states.
10.1.1 Health monitoring, and why it belongs in the sensor path
A navigation-grade unit reports its own health, and the software layer that consumes increments is also the natural place to police it. Four independent checks, each with a distinct failure signature:
| Check | Detects | Response |
|---|---|---|
| Built-in test word | Internal fault the sensor itself has diagnosed — laser dropout, temperature excursion, power rail | Latch invalid after $N$ consecutive failures; a single transient does not condemn the unit |
| Sequence number gap | Dropped message on the bus | Reuse the previous sample, count the gap, latch stale past a threshold |
| Non-finite data | NaN or Inf anywhere in the message | Reject the sample outright — a single NaN integrated once poisons the state permanently |
| Monotonic timestamp | Clock rollback, replayed or reordered packet | Reject; a negative $\Delta t$ integrates the solution backwards |
Note the asymmetry between the checks: the count-based ones tolerate transients because bus glitches are expected and harmless if brief, while the non-finite and timestamp checks reject immediately. The difference is recoverability. A missed message costs you one interval of information. A NaN integrated into the attitude quaternion, or a negative $\Delta t$, corrupts the state in a way no amount of subsequent good data will repair — the strapdown has no mechanism to un-integrate.
11 · Bounding the drift
An IMU is a relative sensor: excellent over seconds, unbounded over hours. It is therefore always fused with an absolute, lower-rate reference through an estimator — the IMU propagates the state at high rate, and GNSS, a star tracker, a zero-velocity constraint or terrain matching bounds the error. In GPS-denied conditions this is the backbone of the alt-PNT cascade; on spacecraft the gyro plus star-tracker pair is the MEKF; on the pad it is the zero-velocity update of §6.3.
12 · Further reading
- P. G. Savage, Strapdown Analytics, 2nd ed., Strapdown Associates, 2007 — the definitive reference for mechanization, coning/sculling algorithms and error propagation.
- P. D. Groves, Principles of GNSS, Inertial, and Multisensor Integrated Navigation Systems, 2nd ed., Artech House, 2013 — Ch. 4–5 (mechanization, error dynamics), Ch. 15 (alignment).
- D. H. Titterton and J. L. Weston, Strapdown Inertial Navigation Technology, 2nd ed., IET, 2004 — §10 alignment, §12 testing and calibration.
- J. A. Farrell, Aided Navigation: GPS with High Rate Sensors, McGraw-Hill, 2008 — error-state filter design and observability.
- IEEE Std 952-2020 — inertial sensor error model terminology and the Allan-variance form used here. IEEE Std 647-2006 (gyro test procedures), IEEE Std 1293-2018 (accelerometer test procedures).
- NASA/TP-2018-219822, Navigation Filter Best Practices — Joseph form, FOGM bias models, consider filters, underweighting. Summarised on this site.
- M. S. Grewal, L. R. Weill, A. P. Andrews, Global Positioning Systems, Inertial Navigation and Integration, 3rd ed., Wiley, 2013 — worked alignment and calibration examples.
Related pages: Attitude & rotations · Fine alignment · Ground-align drift test · Schuler oscillation · IMU acceptance testing · Filtering · EKF · GNSS · Hardware — IMUs.