Lesson 5 · Inertial state estimation · 30–45 minutes first study · 15 minutes revision

The noise preintegration carries

One covariance, propagated a sample at a time, and why it decides who wins.

The deltas tell the solver what the IMU says happened. The solver also needs to know how much to believe it: that's the 9×9 covariance \(\Sigma_{ij}\) of the deltas. Its inverse is the weight on the IMU residual, and in glass-lio it's what gets set against the LiDAR. This lesson is how that covariance is built, one sample at a time. It's the second half of the course's uncertainty-propagation goal, and the answer to an interview question you should expect: how do you weigh the IMU against another sensor?

0 · Warm-up, from memory

The position line of eq. (31), from lesson 2. The noise update in this lesson has exactly its shape.

From memory: write the position line of eq. (31), with noise dropped.

1 · Why a covariance at all

Least squares weights each residual by its inverse covariance. Forster calls modelling it "of paramount importance… the inverse noise covariance is used to weight the terms in the optimization."Forster et al., On-Manifold Preintegration…, §VI-B. glass-lio does exactly that. The IMU factor's weight is the inverse of the preintegration covariance, while each LiDAR point is whitened by lidar_sigma:tight_registration.cpp, lines 118–129. glass-lio also adds the previous state's own uncertainty, \(\mathbf{J}_i\mathbf{P}_i\mathbf{J}_i^{\top}\), which marginalizes an independent Gaussian perturbation of x_i from this one linearized factor. The LiDAR side is at lines 64–70.

const Eigen::Matrix<double, 9, 9> sigma_eff =
  pre.covariance() + Ji * xi_cov * Ji.transpose();
Eigen::Matrix<double, 9, 9> imu_information =
  sigma_eff.inverse() * params.imu_prior_weight;

This matrix helps set the balance with LiDAR. The covariance inflation is exact for that local linear Gaussian model with independent noise; it is not the marginalization of every historical factor or a proof of consistency of the whole estimator.

2 · The noise is linear, so propagate it linearly

Forster writes each delta as "the (to-be-estimated) state 'plus' a random noise", stacked as \(\boldsymbol{\eta}^{\Delta} = [\delta\boldsymbol{\phi};\ \delta\mathbf{v};\ \delta\mathbf{p}]\), and shows that, to first order, this is "a linear function of the IMU measurement noise". That makes the covariance "a simple linear propagation". Better still, it can be done iteratively: "as a new IMU measurement arrive[s] we only update \(\Sigma_{ij}\), rather than recomputing it from scratch."Forster §VI-A (eq. 38) and §VI-B (eqs. 39–43). The iterative form is Appendix IX-A.

3 · One sample at a time

With \(\mathbf{a}_k \doteq \tilde{\mathbf{a}}_k - \mathbf{b}^{a}\) and the raw IMU noise \(\boldsymbol{\eta}^{d}_k = [\boldsymbol{\eta}^{gd}_k;\ \boldsymbol{\eta}^{ad}_k]\), each sample updates the noise, and so the covariance, like this:Forster Appendix IX-A, eqs. (59)–(63), written there from \(j-1\) to \(j\); here from \(k\) to \(k+1\). \(\Delta\tilde{\mathbf{R}}_{k,k+1}\) is this step's rotation, and \(\Delta\tilde{\mathbf{R}}_{ik}\) the rotation accumulated before it.

$$ \begin{aligned} \boldsymbol{\eta}^{\Delta}_{i,k+1} &= \mathbf{A}_k\,\boldsymbol{\eta}^{\Delta}_{ik} + \mathbf{B}_k\,\boldsymbol{\eta}^{d}_k\\ \Sigma_{i,k+1} &= \mathbf{A}_k\,\Sigma_{ik}\,\mathbf{A}_k^{\top} + \mathbf{B}_k\,\Sigma_{\eta}\,\mathbf{B}_k^{\top}, \qquad \Sigma_{ii} = \mathbf{0} \end{aligned} \tag{63} $$
$$ \mathbf{A}_k = \begin{bmatrix} \Delta\tilde{\mathbf{R}}_{k,k+1}^{\top} & \mathbf{0} & \mathbf{0}\\ -\Delta\tilde{\mathbf{R}}_{ik}\,\mathbf{a}_k^{\wedge}\,\Delta t & \mathbf{I} & \mathbf{0}\\ -\tfrac{1}{2}\Delta\tilde{\mathbf{R}}_{ik}\,\mathbf{a}_k^{\wedge}\,\Delta t^{2} & \mathbf{I}\,\Delta t & \mathbf{I} \end{bmatrix} \qquad \mathbf{B}_k = \begin{bmatrix} \mathbf{J}_r^{k}\,\Delta t & \mathbf{0}\\ \mathbf{0} & \Delta\tilde{\mathbf{R}}_{ik}\,\Delta t\\ \mathbf{0} & \tfrac{1}{2}\Delta\tilde{\mathbf{R}}_{ik}\,\Delta t^{2} \end{bmatrix} $$

It starts at zero because an empty interval has measured nothing yet. The raw noise covariance \(\Sigma_{\eta}\) comes from the datasheet densities, turned into discrete-time noise exactly as in lesson 2: \(\sigma^{2}/\Delta t\).

Here \(\mathbf{J}_r^k=\mathbf{J}_r((\tilde{\boldsymbol{\omega}}_k-\mathbf{b}^g)\Delta t)\) is the right Jacobian of SO(3): it converts an additive error in a rotation vector into a small right-multiplied rotation. It tends to \(\mathbf{I}\) near zero.

The covariance recursion assumes the new measurement noise is independent of the accumulated error. The densities use the convention \(Q_d=\operatorname{diag}(\sigma_g^2\mathbf I,\sigma_a^2\mathbf I)/\Delta t\). This 9×9 matrix conditions on the chosen integration biases; it does not include their uncertainty or random walk.

4 · Read it like eq. (31)

Don't memorise A and B as matrices. Read them row by row, and they're the warm-up's equation, linearised:

glass-core builds exactly these blocks, term for term:preintegration.cpp, lines 40–68. It runs before the state update in the same loop: "it linearises about the CURRENT state, so it needs dR before we advance it." That's the update-order trap from lesson 2, again.

A.block<3, 3>(0, 0) = dRk.matrix().transpose();
A.block<3, 3>(3, 0) = -dR_mat * a_hat * dt;
A.block<3, 3>(6, 0) = -0.5 * dR_mat * a_hat * dt * dt;
A.block<3, 3>(6, 3) = Eigen::Matrix3d::Identity() * dt;

B.block<3, 3>(0, 0) = Jr * dt;
B.block<3, 3>(3, 3) = dR_mat * dt;
B.block<3, 3>(6, 3) = 0.5 * dR_mat * dt * dt;

cov_ = A * cov_ * A.transpose() + B * Q * B.transpose();

5 · Accumulating noise is not a monotonicity theorem

Each sample adds a positive semidefinite term \(\mathbf B\Sigma_\eta\mathbf B^\top\) to the propagated covariance \(\mathbf A\Sigma\mathbf A^\top\). This does not imply \(\Sigma_{k+1}-\Sigma_k\succeq0\): propagation rotates and couples errors, so individual directional variances need not increase at every step.

For example, let \(\Sigma=\operatorname{diag}(4,1)\), let \(A\) rotate by 90°, and add \(Q=0.1I\). Then \(A\Sigma A^\top+Q=\operatorname{diag}(1.1,4.1)\). The first variance fell despite fresh noise. Longer inertial dead reckoning generally accumulates error, but that practical trend is not an ordering of every covariance matrix or its inverse.

In the simpler scalar model \(v_{k+1}=v_k+\eta_k\Delta t\), with independent \(\operatorname{Var}(\eta_k)=\sigma_a^2/\Delta t\), the variance is exactly \(\sigma_a^2T\). Doubling \(T\) doubles that variance and halves its information. State the model before drawing this conclusion.

Noise densities are physical parameters to measure or obtain from a suitable sensor specification. Validate their units, bandwidth assumptions, and the resulting residual statistics. Datasheet range noise alone is not the full point-to-plane residual uncertainty: plane fitting, deskew errors, and correlated returns also matter. The historical glass-lio settings are calibration choices for those experiments, not universal constants.

Say it at a whiteboard

"Preintegration's noise is a linear function of the IMU's white noise, so I propagate its 9×9 covariance over \([\delta\boldsymbol{\phi}, \delta\mathbf{v}, \delta\mathbf{p}]\) one sample at a time: \(\Sigma \leftarrow \mathbf{A}\Sigma\mathbf{A}^{\top} + \mathbf{B}\Sigma_{\eta}\mathbf{B}^{\top}\), starting from zero, with the datasheet densities turned into discrete covariances \(\sigma^{2}/\Delta t\). A and B are eq. (31) linearised, plus one coupling: an orientation error tilts the specific force. The inverse of that covariance weights the IMU residual. Dead reckoning generally accumulates uncertainty, but propagation does not guarantee monotonic growth in every direction."

6 · Practice

From memory, no scrolling. The last question comes from lesson 4.

Why can \(\Sigma_{ij}\) be computed by linear propagation at all?

What is \(\Sigma_{ii}\), the covariance at the very start of the interval?

In the velocity row of \(\mathbf{A}_k\), where does the \(-\Delta\tilde{\mathbf{R}}_{ik}\,\mathbf{a}_k^{\wedge}\,\Delta t\) block come from?

For scalar velocity driven only by independent white accelerometer noise, \(\operatorname{Var}(v)=\sigma_a^2T\). Double \(T\): what happens to its inverse-variance weight?

From lesson 4. In eq. (44), which delta's bias correction is not a plain addition?

From memory: write the covariance recursion, with its starting value and the discrete IMU noise covariance. Then say in one sentence what its inverse is used for. Stretch: write \(\mathbf{B}_k\).

Apply it: complete the practical worksheet exercise before moving on. Derive an answer and test it on the supplied inputs.