← antimony labs

You almost never measure the full state. A drone has a barometer (altitude) but not a clean rate-of-climb. A motor has an encoder (angle) but not a clean angular velocity. A robot arm has joint sensors but no direct measurement of acceleration. To run any controller that needs all the states, you must estimate the unmeasured ones from what you can see. That estimator is the observer.

What you'll see in the plot. A mass-spring plant starts at and oscillates. Three traces overlay its position on the same time axis:

The L sliders are the observer gains — how strongly the estimate trusts the measurement vs. its own model. Crank L high: fast convergence, but noise pours through. Crank L low: smooth but sluggish. The Kalman filter is the principled choice that picks the optimal L for the given noise level — which we'll cover at the end.

Estimate what you can't directly measure

Luenberger RMS err
open-loop RMS err
settling (Luenberger)
init mismatch x̂(0) ≠ x(0)
what to try
  • With , the Luenberger trace is just an open-loop sim — it never converges. Bump L₁ up; convergence appears.
  • Crank both L's high. Convergence is faster — but the noise pours through. Faster observer = louder estimate. Trade-off.
  • Slide the noise σ up. Notice that the Luenberger trace stays close to truth, just visibly noisier. A Kalman filter is a Luenberger observer whose L is recomputed each step to minimize the noise-vs-speed trade-off automatically.
show the math

Plant: with measurement , is noise. Observer (Luenberger):

Estimation error evolves as . Pick L so that has stable eigenvalues — fast and deep into the left-half-plane = faster convergence but more noise. The Kalman filter solves this by minimizing the steady-state covariance of e.