Probability for Robotics · Theory · M7
M7-T2 — Deriving the Multivariate Kalman Filter
With several state variables, variances become a covariance matrix and the gain a matrix, and unmeasured quantities are corrected through the correlations.
Real robots have states with several components: position and velocity, a pose, a bias. The scalar derivation carries over line by line once variances become covariance matrices, and it brings a new effect with it: a sensor that sees only some components still corrects the others, through the correlations the model creates between them. This lesson derives the matrix filter and demonstrates that effect with a position sensor that never sees velocity.
Learning objectives
After this lesson, you should be able to:
- Write the linear-Gaussian state-space model with F, Q, H and R, and say what each matrix means physically.
- Derive the matrix prediction and correction from the Bayes filter and from conditioning a joint Gaussian.
- Compute the innovation covariance S and the gain K = P Hᵀ S⁻¹, and explain K row by row.
- Explain how an unmeasured state is estimated through the cross-covariance.
The intuition
A robot drives along a corridor at about 1 m/s. Its state is two numbers: position and velocity. Its sensor reports position only, with 20 cm of noise. Velocity is never measured, yet the filter should know it. How?
The model supplies the link: over a step of 0.5 s the position changes by velocity times 0.5. A wrong velocity estimate therefore produces a growing position error, and a position error carries information about the velocity error. The filter keeps a covariance matrix whose off-diagonal entry records exactly this: after a prediction step, errors in position and velocity are correlated (here with a correlation of about 0.7). When a reading shows the robot further along than predicted, the correlation says that the velocity was probably underestimated too, and the filter raises it.
This is the main practical power of the Kalman filter: you measure what is easy to measure and estimate what is useful. Wheel speed from encoders, heading rate from the gyro, a bias in the gyro from the heading error: all are corrected through the model and the cross-covariances.
The scalar rule “move towards the reading by a fraction K” becomes a vector rule: each state variable moves by its own fraction of the innovation, and the fractions are set by how correlated that variable is with the measured one.
Definitions
- State
- Everything the filter estimates. Here position and velocity.
- Transition
- How the state evolves without noise: . For constant velocity .
- Process noise
- Covariance of : how much the state is disturbed per step. Positive semi-definite.
- Measurement
- , . selects what is measured: for position only.
- Innovation
- and its covariance .
- Gain
- An matrix mapping the innovation into a correction of every state variable.
Derivation: conditioning a joint Gaussian
The prediction is the linear propagation of module 4. The correction can be derived by writing the joint distribution of the state and the measurement and conditioning on the measurement.
The prior state is Gaussian, and is a linear function of it plus independent noise. Its covariance with the state is .
The conditioning formula for a joint Gaussian (conditioning lesson of module 4).
Substituting the blocks, with . The gain is the cross-covariance divided by the innovation covariance: how much the measurement tells about each state variable, per unit of its uncertainty.
The conditional covariance: the prior minus the information the reading carries. It never increases the uncertainty.
Why the unmeasured variable moves
Write and . Then and the gain is
The velocity changes by times the position innovation. If the velocity would never be corrected. The model creates the correlation, because adds to the position: in the prediction , which is positive whenever the velocity is uncertain.
A state variable is observable through a sensor if the model correlates it with something the sensor sees. If the model does not link them, no filter can estimate it: that is the subject of the last lesson of the module.
A worked example
The robot of the figure: a state of position and velocity, s, acceleration noise of standard deviation 0.05 m/s per √s, a position sensor with m², and a poor start with identity covariance. The true velocity is about 1 m/s.
- Step 1. The reading is 0.7 m from a true position of 0.513 m. The gain is : the position takes 97% of the innovation; the velocity estimate moves from 0 to 0.28 m/s, with a standard deviation still large (0.90 m/s) because one reading says little about the velocity.
- Step 2. One step later the correlation is 0.66 and the velocity gain jumps to 1.42 (in m/s per metre of innovation): with two positions the filter can see a slope. The velocity estimate is 0.67 m/s and its standard deviation 0.46.
- Step 5 to 20. The velocity estimate reaches 0.85, then 1.01 and 1.11 m/s (truth 1.02, 1.12 and 1.09), with a standard deviation of 0.073 m/s. The position gain falls from 0.97 to 0.34 and the velocity gain from 0.39 to 0.14.
- Honest uncertainty. Over 300 runs the root-mean-square position error at step 20 is 0.120 m (claimed 0.117), and the velocity error 0.068 m/s (claimed 0.073).
import math
from robotprob import Rng, kf_predict, kf_update, mean
dt, sq, r = 0.5, 0.05, 0.04
F = [[1.0, dt], [0.0, 1.0]] # position += velocity * dt
H = [[1.0, 0.0]] # only the position is measured
q = sq * sq
Q = [[q * dt**3 / 3, q * dt**2 / 2], # white-noise acceleration: errors in position and velocity are correlated
[q * dt**2 / 2, q * dt]]
R = [[r]]
def run(seed, steps=20):
rng = Rng(seed)
pos, vel = 0.0, 1.0 # the truth
x, P = [0.0, 0.0], [[1.0, 0.0], [0.0, 1.0]] # the belief: no idea of the velocity
out = []
for t in range(1, steps + 1):
vel += rng.gauss(0.0, sq * math.sqrt(dt))
pos += vel * dt
z = pos + rng.gauss(0.0, math.sqrt(r))
x, P = kf_predict(x, P, F, Q)
x, P, y, S, K = kf_update(x, P, [z], H, R)
out.append((t, pos, vel, z, x, P, K))
return out
o = run(5)
print('step true pos est pos true vel est vel std pos std vel corr gain(pos,vel)')
for t, pos, vel, z, x, P, K in o:
if t in (1, 2, 3, 5, 10, 20):
c = P[0][1] / math.sqrt(P[0][0] * P[1][1])
print(str(t).rjust(4), str(round(pos,3)).rjust(9), str(round(x[0],3)).rjust(8), str(round(vel,3)).rjust(9), str(round(x[1],3)).rjust(8), str(round(math.sqrt(P[0][0]),3)).rjust(8), str(round(math.sqrt(P[1][1]),3)).rjust(8), str(round(c,2)).rjust(5), (round(K[0][0],3), round(K[1][0],3)))
ev=[];ep=[]
for s in range(1,301):
t,pos,vel,z,x,P,K=run(s)[-1]
ev.append(x[1]-vel); ep.append(x[0]-pos)
print('300 runs: rms pos error',round(math.sqrt(mean([e*e for e in ep])),4),' claimed',round(math.sqrt(o[-1][5][0][0]),4))
print('rms vel error',round(math.sqrt(mean([e*e for e in ev])),4),' claimed',round(math.sqrt(o[-1][5][1][1]),4))step true pos est pos true vel est vel std pos std vel corr gain(pos,vel) 1 0.513 0.7 1.026 0.28 0.197 0.898 0.09 (0.969, 0.388) 2 1.003 1.079 0.98 0.67 0.186 0.463 0.66 (0.865, 1.416) 3 1.479 1.493 0.953 0.76 0.177 0.265 0.76 (0.784, 0.888) 5 2.499 2.396 1.024 0.852 0.154 0.13 0.79 (0.591, 0.394) 10 5.185 5.04 1.118 1.011 0.123 0.075 0.68 (0.38, 0.158) 20 10.662 10.716 1.093 1.113 0.117 0.073 0.67 (0.343, 0.143) 300 runs: rms pos error 0.1201 claimed 0.1172 rms vel error 0.0681 claimed 0.0733
kf_predict(x, P, F, Q) and kf_update(x, P, z, H, R) work on lists of lists; the update also returns the innovation, its covariance S and the gain K.In robotics
Tracking with a motion model
A constant-velocity model with position readings is the standard tracker for moving objects: other cars, pedestrians, a ball. The Perception course builds the intuition in Simple Filtering and Kalman Filter Intuition, and the UAV course applies the same matrix filter to a vehicle in Kalman Filter.
Sensor fusion and biases
Adding a gyro-bias state to a heading filter lets a heading sensor correct the bias even though the bias is never observed directly: the same cross-covariance mechanism. The state grows, the filter does not change.
Choosing Q
The process noise matrix encodes how the state can deviate from the model. For a constant-velocity model the white-noise-acceleration form above is physically motivated: its off-diagonal entries say that acceleration noise perturbs both position and velocity together. A diagonal Q is simpler and often adequate, but it gets the correlations wrong. M7-T3: Innovation, Gain and Tuning Q and R gives the practical tuning recipe.
Cost
The filter costs about per update, trivial for n of 2 to 20 on an embedded processor. It becomes expensive for the thousands of landmarks of SLAM, which is why mapping uses sparse or information forms (module 11).
Common misconceptions
“A state that is not measured cannot be estimated.”
It can, if the model links it to what is measured: velocity from positions, a bias from a heading error. It cannot if there is no link (the observability question).
“The gain matrix is a design choice.”
It is computed. It follows from F, Q, H, R and the current covariance; what you choose are Q and R.
“Only the diagonal of P matters.”
The diagonal gives the variances, but the off-diagonal entries carry the information that corrects unmeasured states. Dropping them (a diagonal P) breaks the mechanism and makes the filter overconfident.
“P = (I − KH)P̄ is always safe.”
It is exact only for the optimal K and in exact arithmetic. With rounding it can lose symmetry or positive definiteness; the Joseph form is safe, which is why robotprob uses it.
Key takeaways
- The matrix filter is the scalar one with matrices: predict with F and Q, correct with the gain K = P̄Hᵀ S⁻¹.
- The correction is the conditional of a joint Gaussian: the prior minus the information carried by the measurement.
- The off-diagonal terms of P are what let a sensor correct states it does not measure.
- Unmeasured states are estimated only if the model correlates them with measured ones.
- Use the Joseph form for the covariance update, and check claimed against real errors.
References and further reading
Each source is marked free or paid. Free to read does not mean free to reuse: the course resources page lists every source with its licence.
- T. D. Barfoot, State Estimation for Robotics, 2nd edition, 2024 , chapter 3 (Linear-Gaussian Estimation) derives the filter from a batch problem and from Bayes. Free to read as the author’s PDF; the book is copyrighted.
- S. Särkkä, Bayesian Filtering and Smoothing, Cambridge University Press, 2013, chapter 4 (Bayesian filtering equations and exact solutions: the Kalman filter). Paid book; the author also hosts a free PDF on his page.
- S. Thrun, W. Burgard and D. Fox, Probabilistic Robotics, MIT Press, 2005, section 3.2. Paid book.
- C. Stachniss, “Kalman Filter & EKF” (video lecture) . Free to watch.
Knowledge check
Three questions. Write an answer, then reveal the explanation. Your answers stay in your browser.
Question 1
A position sensor with r = 0.04 gives a reading of 3.0 m. The prediction is x̄ = (2.8 m, 1.0 m/s) with covariance entries pxx = 0.04, pxv = 0.02, pvv = 0.05. Compute the gain and the updated state.
Explanation
S = pxx + r = 0.08. K = (0.04, 0.02) / 0.08 = (0.5, 0.25). The innovation is 3.0 − 2.8 = 0.2. The position becomes 2.8 + 0.5 × 0.2 = 2.9 m and the velocity 1.0 + 0.25 × 0.2 = 1.05 m/s. The velocity moved although it was not measured, because pxv is positive: a position that is further than predicted suggests a velocity that is higher than predicted.
Question 2
The initial covariance of the example is the identity, so position and velocity start uncorrelated. Why does the velocity estimate still move at the first update, and why is its gain at step 2 much larger?
Explanation
The prediction step comes before the first update, and it adds Δt·pvv to pxv: the position error grows with the velocity error, so a correlation (0.09 in the log) exists when the first reading arrives, and the velocity gain is 0.39 (the estimate moves from 0 to 0.28 m/s). At step 2 the correlation has built up to 0.66 and the velocity gain is 1.42, because with two positions the filter can effectively see a slope. A filter whose P stayed diagonal could never correct the velocity.
Question 3
A colleague simplifies the filter by keeping only the diagonal of P after every step. What happens, and why?
Explanation
The off-diagonal entries are what carry information from the measured variable to the unmeasured one. With a diagonal P the velocity gain is exactly zero, so the velocity estimate never moves from its initial value, and the filter is wrong about the velocity (and then about the position, which keeps being predicted with a wrong velocity). Moreover the diagonal of P alone understates the true uncertainty, so the filter would also be overconfident.
What’s next
The filter is derived. The next lesson looks at what it computes at run time (the innovation, the gain) and at how to choose the two matrices Q and R that you must supply.
Related content
Nothing below is required to finish this lesson.
- BeforeM7-T1: The Kalman Filter in One Dimension
Derive the scalar Kalman filter from the fusion of two Gaussians and explain the gain as a ratio of variances.
Other courses on this site treat neighbouring topics from their own angle:
Get notified when the next lesson and new labs are released.
One email per new lesson or lab.