← Demos

Kalman · LQR

A 1 kg puck on an air table, pushed by two thrusters and watched by a noisy overhead camera. An LQR controller steers it from a Kalman filter estimate. Both gains come from Riccati equations solved live in your browser. Click or drag on the table to move the target.

  • True puck
  • Kalman estimate, 95% ellipse
  • Camera measurements
  • Target
Estimation error x · ±2σ from P
Thrust Fx, Fy · limits dashed
Tracking error
–
Estimation error
–
Raw camera error
–
Mean NIS
–
Equations

Plant

State is position and velocity, input is thrust, and the camera sees position only. Drag c slows the puck, and random force w (air currents, a bumpy table) pushes it around.

Zero-order hold over one sample Δt, computed from one matrix exponential:

LQR

Minimise the infinite-horizon quadratic cost of tracking error and thrust:

The optimal cost-to-go is x̃⊤Px̃, where P solves the discrete algebraic Riccati equation (DARE):

The feedforward uff = m aref + c vref carries moving targets. Thrust is clipped at ±Fmax per axis, which LQR does not know about.

Kalman filter

Predict with the model, then correct with the camera:

The prior covariance converges to the solution of the dual DARE, swapping A→A⊤, B→C⊤, Q→W, R→V:

A consistent filter has mean normalised innovation squared ν⊤S−1ν = 2 (two measured axes). Detune the model noise to see it drift away from 2.

Solvers and the continuous limit

The DARE is solved with the structure-preserving doubling algorithm. With G = BR−1B⊤, each step doubles the Riccati horizon:

Starting from A0 = A, G0 = G, H0 = Q, Hj → P. For comparison, the continuous ARE is solved with the matrix sign function of the Hamiltonian:

As Δt → 0 the sampled gain K approaches Kc. Make Δt large and watch them part.

Matrices, live