Learnsy lesson 2 · standalone TypeScript app

Kalman Filters

A delivery robot has two imperfect sensors: jumpy GPS, and wheels that slowly lie about distance. A Kalman filter blends both into one best guess of where the robot is — and how sure it is about that guess.

Interactive simulator

Watch four ways of tracking the same robot. Blue dots are raw GPS. The teal line is the Kalman filter. Try a preset, then move the sliders and see what breaks.

The story in one minute
  1. The robot drives along a street for 12 seconds.
  2. Blue dots = GPS fixes (often wrong by a meter or two).
  3. In the yellow band, buildings block GPS — only the wheels keep counting.
  4. Teal line = Kalman best guess. The soft band around it is “how unsure we are.”

How to read the charts

  • Blue dots jump around — that is messy GPS, not the true path.
  • Orange dashed is a simple average of recent GPS. It lags when speed changes and freezes when GPS disappears.
  • Red dashed uses only the wheels. Smooth, but it slowly walks away from truth.
  • Teal is Kalman: wheels between GPS fixes, GPS corrections when available. The green band widens when GPS is gone (less certainty).
  • Bottom chart: purple is estimated speed; red is “how unsure about position” (higher = less confident).

What problem is this solving?

You never see the robot's true position. You only get two imperfect clues:

  • GPS — “you are roughly here,” but the reading jumps around and sometimes vanishes near buildings.
  • Wheels (odometry) — “I rolled this far,” which is smooth second-to-second, but a small speed error piles up over time.

A Kalman filter keeps a running best guess of position and speed, updates it every step, and also tracks how unsure that guess is.

The mental model

Think of it as a careful navigator, not a fancy smoother:

  • Between GPS fixes: “Keep going based on the wheels.”
  • When GPS arrives: “Nudge the guess toward this new reading — but only as much as we trust GPS.”
  • When GPS is gone: keep coasting on wheels, and admit the guess is getting less reliable (the green band gets wider).

That is why it can beat a simple average: averages only look at recent GPS, so they stall when GPS disappears.

Q — how messy is motion?

How much the wheels might be wrong (slip, bumps, sudden speed changes). Higher Q = “don't trust the wheels too much; listen more to GPS.”

R — how noisy is GPS?

How much scatter you expect in each GPS fix. Higher R = “don't trust each blue dot too much; lean on the wheels.”

Uncertainty band

The soft green region around the teal line. Wider = the filter is less sure. It usually grows during GPS outages and shrinks when good GPS returns.

Why not just use a simpler method?

Kalman is worth the extra machinery when you have a useful motion model and noisy measurements that arrive over time. It is not automatically best for every signal.

MethodWhat it doesHow it fails here
Raw GPSPlot every GPS reading as truth.The path jumps around with every noisy blue dot.
Moving averageSmooth recent GPS readings.Lags when speed changes; freezes when GPS disappears.
Wheels only (dead reckoning)Integrate wheel speed from the start.Looks smooth, then slowly walks off the true path.
Kalman filterBlend wheels + GPS and track uncertainty.Needs sane Q/R settings and a model that is “close enough.”

FAQ

Why track speed if GPS only reports position?

Knowing roughly how fast you are going lets the filter keep predicting between GPS fixes. When a GPS reading finally arrives, it can correct both “where am I?” and “how fast am I going?”

What is the Kalman gain, in plain English?

It is the automatic mix knob: how much to trust the new GPS reading versus the current guess. Unsure filter + clean GPS → trust GPS more. Confident filter + noisy GPS → trust GPS less.

What happens when GPS drops out?

There is nothing to correct with, so the filter keeps using the wheels. The teal line continues, but the green uncertainty band grows because no new evidence is arriving.

Why does “trust the wheels too much” look smooth but wrong?

Very low Q means “I believe the motion model almost completely.” If the wheels are biased, the filter resists GPS corrections and recovers slowly after GPS returns. Try the Overtrust wheels preset.

TypeScript sketch

Same idea in code: predict with the motion model, then (if GPS exists) correct toward the measurement. Q and R are the messiness knobs from the simulator.

function step(z: number | null, dt: number) {
  // Predict from constant velocity.
  x = F(dt).mul(x);
  P = F(dt).mul(P).mul(F(dt).transpose()).add(Q(dt));

  if (z === null) return x;

  // Correct with position measurement.
  const y = z - H.mul(x);
  const S = H.mul(P).mul(H.transpose()).add(R);
  const K = P.mul(H.transpose()).mul(S.inverse());
  x = x.add(K.mul(y));
  P = I.sub(K.mul(H)).mul(P);
  return x;
}

Practical warnings

  • Bad Q or R can still produce a pretty line that is quietly wrong — or overconfident.
  • Watch the uncertainty band, not only the teal estimate. A smooth line with a huge band is not “sure.”
  • This demo assumes roughly constant speed between small changes. Big accelerations only work if Q is large enough to absorb the surprise.
  • Real robots often reject absurd GPS spikes before feeding them into the filter.