Kalman filter playground
Tune a Kalman filter live and watch it work — a 1-D value, 2-D tracking with constant-velocity and constant-acceleration models, an extended Kalman filter for a range–bearing sensor, GPS + accelerometer fusion, and complementary filter against Kalman for tilt (with your phone's sensors) — stepping through predict and update with every matrix shown, covariance ellipses, innovations and NIS/NEES consistency against chi-square bounds.
Added
How to use it
A Kalman filter keeps an estimate of a state and of how unsure it is about it (the covariance P). Each
step it predicts with a model of how the state moves, growing P by the process noise Q, then
updates with a measurement, trusting it in proportion to its noise R. Everything here is a
simulation with a known truth, so you can see when the filter is right, when it is wrong, and
whether it knows which. Each scenario has its own tab and address — /tools/kalman/#2d, #ekf,
#fusion, #tilt.
How to use it
-
Step ▸ moves through the filter half a step at a time: first the prediction (x̂⁻, P⁻, a dashed ellipse), then the update (y, S, K, x̂, P, a solid ellipse). The This step panel shows every matrix with its numbers; open The model for F, Q, H, R (and B where there is a control input). ▶ Run plays the whole run, the slider jumps to any step.
-
Drag the Q and R sliders: the same truth and the same noisy measurements are filtered again at once, so you see only what the tuning changes. New noise draws a fresh run.
-
Innovation plots show y = z − H x̂⁻ against ±2√S: about 95 % of points should sit inside. NIS (normalised innovation squared, yᵀS⁻¹y) should average the measurement’s dimension; the dashed lines are its 95 % chi-square bounds and the shaded band the bounds for a 20-step mean. NEES does the same for the estimation error, which needs the truth. A mean above the band means the filter is overconfident (Q or R too small); below means it is too timid.
The tabs
-
1-D — a constant value or a random walk measured with noise. With Q = 0 the gain falls as 1/k (the running mean); with Q > 0 it settles at the steady-state gain K∞, shown for comparison.
-
2-D tracking — a target that drives straight and then turns, or drifts at random. Choose a constant-velocity or constant-acceleration model; Q comes from white acceleration (or jerk) noise of the density you set. Turn Q down and watch the estimate overshoot the corners and NIS explode; turn it up and the estimate gets as noisy as the measurements.
-
Range–bearing EKF — a radar measures range and bearing. The extended Kalman filter linearises the measurement about each prediction (the Jacobian H is shown each step) and wraps the bearing innovation to ±180°. The shaded arc is the true shape of one measurement’s uncertainty; when it is long and curved — big bearing noise, distant target — the Gaussian ellipse fits it badly and the filter becomes inconsistent.
-
GPS + accelerometer — 50 Hz accelerometer readings drive the prediction as a control input; GPS fixes arrive once a second. Between fixes the uncertainty grows, at each fix it drops. Put the accelerometer bias in the state and the fixes teach the filter to subtract it; take it out and see the track lean.
-
Tilt — a gyro (smooth, biased) and an accelerometer (noisy, upset by knocks). A complementary filter blends them with a fixed time constant; a two-state Kalman filter (angle and gyro bias) works out the blend and the bias. On a phone, Use this phone’s sensors runs both filters on your phone’s own gyro and accelerometer — tilt it forwards and back. iPhones ask for permission first. For a level and an inclinometer see compass and level.
Related tools
-
Control systems — transfer functions, poles and state space, the other half of a control loop.
-
PID loop simulator — what to do with the estimate once you have it.
-
ODE solver — the continuous-time models behind F.
-
The maths of machine learning — least squares; a Kalman filter on a state that doesn’t move is recursive least squares.
How it works
The engine, kalman-core.js, is plain JavaScript with no libraries: small dense matrices
(Gauss–Jordan inverse, Cholesky), a seeded random generator, and the filter. The covariance update
uses the Joseph form, P = (I − KH)P⁻(I − KH)ᵀ + KRKᵀ, which stays symmetric and positive definite
for any gain. Chi-square bounds come from the regularised incomplete gamma function. Its tests
check that the scalar filter reaches the analytic steady-state gain, that P stays positive
definite over long runs, that a correctly tuned filter’s mean NIS and NEES match their degrees of
freedom, that the EKF’s Jacobian matches finite differences, and that the bearing wraps across
±180°.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.