Skip to the lesson
FixTheRobot Explore Robotics / Probability for Robotics / M7 Kalman Filter / M7-T1

Probability for Robotics · Theory · M7

M7-T1 — The Kalman Filter in One Dimension

Prediction adds a little variance. The correction mixes in the reading with a weight set by how much each side is trusted.

  • Lesson 1 of 4
  • Intermediate
  • Module 7: Kalman Filter
  • Theory
  • About 15 minutes to read

The Kalman filter is the Bayes filter for the case where everything is Gaussian and linear, and in one dimension it fits on a line of code per step. This lesson derives it from the two tools of module 4 (the variance of a sum and the fusion of two Gaussians), runs it on a robot with a noisy position sensor, and finds the number that makes it work: the gain, the fraction of each new surprise that the filter lets into its estimate.

Learning objectives

After this lesson, you should be able to:

  • Write the scalar Kalman filter (prediction and correction) and explain each line in terms of means and variances.
  • Derive it from the Bayes filter with Gaussian beliefs, using the variance of a sum and the fusion of Gaussians.
  • Interpret the Kalman gain as a ratio of variances, and compute the steady-state gain and variance.
  • Compare the filter with dead reckoning and with the raw sensor on a simulated run.

The intuition

A robot on a rail is commanded to move 0.5 m per step. Its motion is noisy (a standard deviation of 10 cm per step), so after the command it knows where it is a little less well. A position sensor then gives a reading with a standard deviation of 20 cm. What should the robot believe?

  • If it relied on the commands alone (dead reckoning), its uncertainty would grow without limit: after 30 steps the standard deviation is 1.14 m.
  • If it relied on the sensor alone, the error would stay at 20 cm, however many readings it takes: it throws the previous ones away.
  • The Kalman filter keeps both: it predicts with the command, then moves its estimate towards the reading by a fraction K of the disagreement. After a few steps its standard deviation is 12.5 cm, better than the sensor and than the motion alone.
A scalar Kalman filter: its error against the raw readings, and its gain settlingLeft: error against the true position over 30 steps. Orange dots are the errors of the raw readings, scattered up to about 0.4 metres. The blue line is the error of the Kalman estimate, staying within a shaded band of plus and minus two standard deviations that narrows from 0.4 metres to 0.25 metres in the first few steps. Right: the Kalman gain falls from 0.96 at step 1 to 0.39 by step 10 and stays there; the standard deviation of the estimate falls from 0.2 to 0.125 metres.051015202530-0.8-0.400.40.8steperror (m) raw readingsfiltershaded: ±2σ 05101520253000.250.50.751stepgain K and std (m) gain K → 0.39std → 0.125 m
Left: errors of the raw readings (orange) and of the Kalman estimate (blue) over 30 steps, with the filter’s own ±2σ band. Right: the gain K and the standard deviation settle after about eight steps.

The two panels show what the filter does. At the first step the prior is poor (a standard deviation of 1 m) so the gain is 0.96: the filter nearly copies the reading. As the estimate becomes good, the gain falls to 0.39 and the filter increasingly trusts its prediction, nudging towards each reading rather than jumping to it. The gain settles because the two sources of uncertainty balance: each prediction adds 0.01 m² of variance, each correction removes some, and the filter reaches a state where the two cancel.

The gain is the whole story. It is large when the filter is unsure and the sensor is good, small when the filter is confident or the sensor is poor. In one line:

K = (my uncertainty) / (my uncertainty + the sensor’s uncertainty). The new estimate is the prediction plus K times the surprise.

Definitions

Belief N(μt,σt2)\mathcal{N}(\mu_t, \sigma_t^2)
The Kalman filter holds the belief as a Gaussian: a mean (the estimate) and a variance (its uncertainty).
Motion model
xt=xt−1+ut+wtx_t = x_{t-1} + u_t + w_t, with wt∼N(0,q)w_t \sim \mathcal{N}(0, q): the commanded displacement plus noise of variance qq (the process noise).
Measurement model
zt=xt+vtz_t = x_t + v_t, with vt∼N(0,r)v_t \sim \mathcal{N}(0, r): the position plus noise of variance rr (the measurement noise).
Innovation νt\nu_t
zt−μˉtz_t - \bar\mu_t: the surprise, the reading minus what the filter predicted.
Kalman gain KtK_t
The fraction of the innovation that is added to the estimate. Between 0 and 1.
Prior / posterior
μˉt,σˉt2\bar\mu_t, \bar\sigma_t^2 (after the prediction) and μt,σt2\mu_t, \sigma_t^2 (after the correction).
Prediction
μˉt=μt−1+ut,σˉt2=σt−12+q\bar\mu_t = \mu_{t-1} + u_t, \qquad \bar\sigma_t^2 = \sigma_{t-1}^2 + q
The mean moves with the command. The variance grows by the process noise.
Correction
Kt=σˉt2σˉt2+r,μt=μˉt+Kt (zt−μˉt),σt2=(1−Kt) σˉt2K_t = \frac{\bar\sigma_t^2}{\bar\sigma_t^2 + r}, \qquad \mu_t = \bar\mu_t + K_t\,(z_t - \bar\mu_t), \qquad \sigma_t^2 = (1 - K_t)\,\bar\sigma_t^2
The gain is the prediction’s share of the total variance. The variance shrinks by the factor 1 − K.
Steady state
σˉ∞2=q+q2+4qr2,K∞=σˉ∞2σˉ∞2+r\bar\sigma_\infty^2 = \frac{q + \sqrt{q^2 + 4qr}}{2}, \qquad K_\infty = \frac{\bar\sigma_\infty^2}{\bar\sigma_\infty^2 + r}
The variance and gain to which the filter converges for constant q and r.

Derivation: from the Bayes filter with Gaussians

Assume the belief at time t−1t-1 is N(μt−1,σt−12)\mathcal{N}(\mu_{t-1}, \sigma_{t-1}^2). The Bayes filter has two steps; each can be done exactly because the Gaussian is closed under the operations involved.

Prediction: a sum of independent Gaussians

  1. xt=xt−1+ut+wtx_t = x_{t-1} + u_t + w_t

    The new position is the old position plus the (known) command plus noise. xt−1x_{t-1} (the belief) and wtw_t (the noise) are independent.

  2. E[xt]=μt−1+ut,Var(xt)=σt−12+q\mathbb{E}[x_t] = \mu_{t-1} + u_t, \qquad \mathrm{Var}(x_t) = \sigma_{t-1}^2 + q

    Means add, and variances of independent quantities add (the variance lesson). A constant utu_t shifts the mean and has no variance.

  3. bel‾(xt)=N(μt−1+ut,  σt−12+q)\overline{\mathrm{bel}}(x_t) = \mathcal{N}\bigl(\mu_{t-1} + u_t,\; \sigma_{t-1}^2 + q\bigr)

    A sum of independent Gaussians is Gaussian (the convolution derivation of the variance lesson), so the predicted belief is again a Gaussian. This is the law of total probability evaluated exactly.

Correction: fusion of two Gaussians

As a function of xtx_t, the likelihood of the reading is p(zt∣xt)=N(zt;xt,r)p(z_t \mid x_t) = \mathcal{N}(z_t; x_t, r), which is a Gaussian in xtx_t centred at ztz_t with variance rr. Bayes' rule multiplies it by the predicted belief.

  1. bel(xt)  ∝  N(xt;μˉt,σˉt2)    N(xt;zt,r)\mathrm{bel}(x_t) \;\propto\; \mathcal{N}\bigl(x_t; \bar\mu_t, \bar\sigma_t^2\bigr)\;\; \mathcal{N}\bigl(x_t; z_t, r\bigr)

    Bayes’ rule (correction step of the Bayes filter): predicted belief times likelihood.

  2. bel(xt)=N(μt,σt2),1σt2=1σˉt2+1r,μt=σt2(μˉtσˉt2+ztr)\mathrm{bel}(x_t) = \mathcal{N}(\mu_t, \sigma_t^2),\quad \dfrac{1}{\sigma_t^2} = \dfrac{1}{\bar\sigma_t^2} + \dfrac{1}{r},\quad \mu_t = \sigma_t^2\Bigl(\dfrac{\bar\mu_t}{\bar\sigma_t^2} + \dfrac{z_t}{r}\Bigr)

    The product of two Gaussians is a Gaussian, found by completing the square (the fusion lesson). Precisions add.

  3. Kt=σˉt2σˉt2+r,μt=μˉt+Kt(zt−μˉt),σt2=(1−Kt) σˉt2K_t = \dfrac{\bar\sigma_t^2}{\bar\sigma_t^2 + r}, \quad \mu_t = \bar\mu_t + K_t(z_t - \bar\mu_t), \quad \sigma_t^2 = (1 - K_t)\,\bar\sigma_t^2

    The gain form of the same formulas: the estimate moves towards the reading by a fraction KtK_t of the difference.

The steady state

Let pp be the predicted variance. After a correction the variance is (1−K)p=pr/(p+r)(1-K)p = pr/(p + r), and the next prediction adds qq. In steady state the predicted variance reproduces itself:

  1. p=p rp+r+qp = \dfrac{p\,r}{p + r} + q

    The variance after correction plus the process noise gives the next predicted variance. A fixed point of the recursion.

  2. p2−q p−q r=0    ⇒    p=q+q2+4qr2p^2 - q\,p - q\,r = 0 \;\;\Rightarrow\;\; p = \dfrac{q + \sqrt{q^2 + 4qr}}{2}

    Multiply out and solve the quadratic (the positive root). This is the scalar algebraic Riccati equation.

  3. q=0.01,  r=0.04:p=0.01+0.0001+0.00162=0.0256,K∞=0.02560.0256+0.04=0.390q = 0.01,\; r = 0.04: \quad p = \dfrac{0.01 + \sqrt{0.0001 + 0.0016}}{2} = 0.0256, \quad K_\infty = \dfrac{0.0256}{0.0256 + 0.04} = 0.390

    The numbers of the example. The variance after correction is (1−K∞)p=0.0156(1 - K_\infty)p = 0.0156, a standard deviation of 0.125 m.

The Kalman gain is the prediction’s share of the total variance. If the sensor is perfect (r → 0) K → 1 and the filter copies it; if the sensor is useless (r → ∞) K → 0 and the filter ignores it.

A worked example

The robot of the figure: command u=0.5u = 0.5 m per step, q=0.01q = 0.01 m² (10 cm) of motion noise, r=0.04r = 0.04 m² (20 cm) of sensor noise, and a poor initial belief N(0,1)\mathcal{N}(0, 1). One simulated run of 30 steps, then 500 runs.

  1. Step 1. Prediction: μˉ=0.5\bar\mu = 0.5, σˉ2=1.01\bar\sigma^2 = 1.01. Gain: K=1.01/1.05=0.962K = 1.01/1.05 = 0.962. The reading is 1.238 (truth 0.620), so the estimate jumps to 0.5+0.962×0.738=1.210.5 + 0.962 \times 0.738 = 1.21 with a standard deviation of 0.196 m: the filter has taken nearly all of the reading, because its own prior was nearly worthless.
  2. Steps 2 and 3. The gain falls to 0.548 and 0.444, and the standard deviation to 0.148 and 0.133 m.
  3. From step 5 on. The gain is 0.397, then 0.390 from step 10: the steady-state value 0.39040.3904. The standard deviation settles at 0.125 m, below the sensor's 0.2 m and far below the 1.14 m that dead reckoning would have reached after 30 steps.
  4. Is the claim true? Over 500 runs the root-mean-square error of the filter at step 30 is 0.126 m, while it claims 0.125 m. The raw readings have an error of 0.199 m. The filter is both better than the sensor and honest about it.
import math
from robotprob import Rng, kalman1d_predict, kalman1d_update, mean

q, r = 0.01, 0.04                               # process noise and measurement noise (variances, m^2)
u = 0.5                                         # the commanded step

def run(seed, steps=30):
    rng = Rng(seed)
    x = 0.0                                     # the true position
    mu, var = 0.0, 1.0                          # the belief: a poor initial guess
    rows = []
    for t in range(1, steps + 1):
        x += u + rng.gauss(0.0, math.sqrt(q))   # the robot moves, with noise
        z = x + rng.gauss(0.0, math.sqrt(r))    # the sensor reads, with noise
        mu, var = kalman1d_predict(mu, var, u, q)
        mu, var, k = kalman1d_update(mu, var, z, r)
        rows.append((t, x, z, mu, var, k))
    return rows

rows = run(11)
print('step   truth  reading  estimate  std   gain')
for t, x, z, mu, var, k in rows:
    if t in (1, 2, 3, 5, 10, 20, 30):
        print(str(t).rjust(4), str(round(x, 3)).rjust(7), str(round(z, 3)).rjust(7), str(round(mu, 3)).rjust(8), str(round(math.sqrt(var), 3)).rjust(6), str(round(k, 3)).rjust(6))

p_bar = (q + math.sqrt(q * q + 4 * q * r)) / 2  # the steady state
k_inf = p_bar / (p_bar + r)
print('steady state: gain', round(k_inf, 4), ' std after the update', round(math.sqrt((1 - k_inf) * p_bar), 4), ' reading std', math.sqrt(r), ' dead reckoning after 30 steps', round(math.sqrt(1 + 30 * q), 3))

errs, errs_raw = [], []
for seed in range(1, 501):                      # is the filter's own claim about its accuracy true?
    t, x, z, mu, var, k = run(seed)[-1]
    errs.append(mu - x)
    errs_raw.append(z - x)
print('500 runs, step 30: rms error of the filter', round(math.sqrt(mean([e * e for e in errs])), 4), ' filter std claims', round(math.sqrt(rows[-1][4]), 4), ' rms error of the raw reading', round(math.sqrt(mean([e * e for e in errs_raw])), 4))
step   truth  reading  estimate  std   gain
   1    0.62   1.238     1.21  0.196  0.962
   2   1.293   1.581    1.639  0.148  0.548
   3    1.91   1.935    2.049  0.133  0.444
   5   3.045   2.844    2.916  0.126  0.397
  10   5.284   4.959    5.253  0.125   0.39
  20  10.657  10.719    10.66  0.125   0.39
  30  15.142  15.241   15.356  0.125   0.39
steady state: gain 0.3904  std after the update 0.125  reading std 0.2  dead reckoning after 30 steps 1.14
500 runs, step 30: rms error of the filter 0.1261  filter std claims 0.125  rms error of the raw reading 0.1988
kalman1d_predict(mean, var, u, q) and kalman1d_update(mean, var, z, r) are the two steps. The robot is simulated, so its true position is known and the filter’s claim can be tested.

In robotics

Everywhere a quantity is tracked with a model and a sensor

The scalar filter is the template for fusing a model with a measurement: a battery's state of charge (current integration plus voltage), a motor's temperature, the altitude of a drone from a barometer and an integrated acceleration, the temperature of a heater. In each, a model predicts and a sensor corrects, and the filter weighs them by their variances. The UAV course derives the same filter from a different starting point in Kalman Filter and implements it in Implement a Kalman Filter in Python, and the Perception course shows the intuition for tracking in Simple Filtering and Kalman Filter Intuition.

Two knobs: q and r

Only the ratio of the process noise q to the measurement noise r matters for the steady-state gain: K∞K_\infty depends on q/rq/r. A large ratio means “the model is unreliable, trust the sensor” and gives a gain near 1 and a fast, noisy filter. A small ratio means “trust the model” and gives a small gain and a smooth, slow one. M7-T3: Innovation, Gain and Tuning Q and R shows how to choose them from data.

A free uncertainty estimate

The variance the filter carries is a prediction of its own error, and it needs no ground truth to be computed. It tells downstream software how much to trust the estimate, widens when readings stop arriving, and can drive decisions: a robot that waits for σ<5\sigma < 5 cm before docking, for example. Whether it can be believed is the subject of the last lesson of this module.

The gain schedule is not tuned

Unlike the fixed gain of a complementary filter, the Kalman gain is computed from the variances at every step and changes as information accumulates: large at the start, small later, and large again after a gap in the readings (since the variance grows during the gap). That adaptivity is the reason to use the filter instead of a constant-gain blend.

One dimension is the basis for more

Every ingredient generalises: variances become covariance matrices, the gain a matrix, and the ratio a matrix inverse. The structure, predict then correct with a gain, is unchanged.

Common misconceptions

“The Kalman filter averages the readings.”

It averages the prediction and the reading with weights set by their variances, and the weights change from step to step. A plain average of readings treats all of them equally and has no model: it could not follow a moving robot.

“A small gain means the filter is ignoring the sensor.”

It means the filter trusts its prediction more than the next reading, because the prediction is accurate. The sensor is still used at every step; it just corrects less each time. The gain rises again whenever the filter’s uncertainty rises.

“The filter’s variance is the error of the estimate.”

It is the filter’s claim about the error, computed from q and r. If q or r is wrong, the claim is wrong. Compare it with real errors (as in the 500-run check) before trusting it.

“The estimate can never be worse than the sensor.”

With correct models it is better. With a mis-specified model (a q that is too small for a robot that really slips, say) the filter trusts its prediction too much, lags behind the truth and can be worse than the raw sensor. Module 7 ends with how to tell.

Key takeaways

  1. Prediction adds the command to the mean and the process variance q to the variance. The belief spreads at every step.
  2. Correction: K = σ̄²/(σ̄² + r), μ = μ̄ + K(z − μ̄), σ² = (1 − K)σ̄². The gain is the prediction’s share of the total variance.
  3. Both steps are exact for Gaussians because sums and products of Gaussians stay Gaussian. The filter is the Bayes filter solved in closed form.
  4. The variance and gain converge to a steady state set by q and r: p = (q + √(q² + 4qr))/2. The estimate beats both dead reckoning and the raw sensor.
  5. The filter’s variance is its own claim about its accuracy, correct only if q and r are. Check it 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.

Knowledge check

Three questions. Write an answer, then reveal the explanation. Your answers stay in your browser.

Question 1

A scalar filter has a predicted variance of 0.09 m² and a measurement variance of 0.01 m². What is the gain, and what are the posterior variance and the new estimate if the prediction is 5.00 m and the reading is 5.30 m?

Explanation

K = 0.09 / (0.09 + 0.01) = 0.9, so the filter takes 90% of the innovation. Estimate = 5.00 + 0.9 × 0.30 = 5.27 m. Posterior variance = (1 − 0.9) × 0.09 = 0.009 m², a standard deviation of 0.095 m, slightly better than the sensor’s 0.1 m. The sensor is nine times more precise than the prediction, so it dominates.

Question 2

Compute the steady-state gain and the steady-state posterior variance for q = 0.0004 m² and r = 0.01 m². Compare with q = 0.01 and r = 0.01 and say how the filter behaves differently.

Explanation

For q = 0.0004, r = 0.01: p = (0.0004 + √(1.6e-7 + 1.6e-5)) / 2 = (0.0004 + 0.004024) / 2 = 0.002212, K = 0.002212 / 0.012212 = 0.181, posterior variance (1 − 0.181) × 0.002212 = 0.00181 (σ = 0.043 m). For q = r = 0.01: p = (0.01 + √(1e-4 + 4e-4)) / 2 = (0.01 + 0.02236) / 2 = 0.01618, K = 0.618, posterior variance 0.00618 (σ = 0.079 m). With the smaller process noise the filter trusts its model, uses a small gain (0.18) and is smoother and more accurate (4.3 cm against 7.9 cm); with equal noises it leans on the readings (K = 0.62) and follows quickly but is noisier.

Question 3

A teammate sets the measurement variance r far too small (they trust the sensor 10 times more than they should). Describe what happens to the gain, the filter’s claimed variance and its real error.

Explanation

A too-small r makes the gain larger than it should be: the filter chases every reading, so its estimate inherits most of the sensor noise and is noisier than a correctly tuned filter. Its claimed variance, which is computed from r, is too small: the filter says it is more accurate than it is. The real error is larger than claimed (the filter is overconfident), which a comparison of the real error with the claimed standard deviation or the consistency tests of the last lesson of this module would reveal. The reverse mistake (r too large) gives a sluggish filter that lags behind the truth.

What’s next

The scalar filter showed the idea. The next lesson derives the filter for a state with several components, where the variances become a covariance matrix and the gain a matrix.

Practice this lesson

1D Kalman Filter

Rover drives along a rail with a noisy range sensor and slipping wheels. Implement predict and update, tune Q and R, and prove with the innovation that the filter is consistent.

Next lesson

M7-T2 — Deriving the Multivariate Kalman Filter

Derive the matrix prediction and update equations from the conditioning of a joint Gaussian, and state the assumptions.

Nothing below is required to finish this lesson.

  • Lab
    M7-L1: 1D Kalman Filter

    Rover drives along a rail with a noisy range sensor and slipping wheels. Implement predict and update, tune Q and R, and prove with the innovation that the filter is consistent.

Other courses on this site treat neighbouring topics from their own angle: