Multi-Sensor Target Tracking

Estimator

Loading…

Telemetry

Time
n/a
Track state
n/a
Position error
n/a
RMSE to date
n/a
Velocity error
n/a
1σ uncertainty
n/a
Ellipsoid drawn at
n/a
NEES (ideal 6)
n/a
NIS/dof (ideal 1)
n/a
0% n/a
Altitude
n/a
Ground speed
n/a
Radar detections
n/a
IR detections
n/a

Legend

  • Ground truth (solid)
  • Fused EKF track (dashed)
  • Maneuver window
  • Radar site & beam
  • IR site & bearing ray
  • Uncertainty ellipsoid
  • Truth-to-estimate error
  • Filter over-confident (NEES > gate)

Drag to orbit · scroll to zoom · shift-drag to pan

Space play/pause · step frame · HomeEnd jump to ends

About this project

Tracking a maneuvering target from two imperfect sensors

A synthetic simulation of the estimation problem behind air surveillance. A target flies a path you never get to observe directly, two sensors report noisy and incomplete measurements of it, and a filter has to reconstruct where the target is while being honest about how sure it is.

The setup

A target enters at about 219 m/s, cruises for a while, then pulls a 24.7 m/s² turn for eight seconds starting at t = 25 s. Two sensors watch it, and neither one is enough on its own:

  • Radar, at 10 Hz, measures range, azimuth and elevation, but it only detects the target 93% of the time.
  • Infrared, at 20 Hz, measures bearing very precisely, but it cannot measure range at all, and it degrades with distance through atmospheric attenuation.

Fusing the two beats radar alone by roughly 36% in position error, because the IR sensor's sharp angles pin down exactly the directions radar measures worst.

The interesting failure

Accuracy is the obvious thing to measure, but it isn't the dangerous one. A filter with large errors is fine as long as it reports large uncertainty. A filter with small errors is dangerous if it claims even smaller ones. NEES measures that directly, by normalizing the true error against the covariance the filter itself claims, and a trustworthy 6-state filter averages 6.

A single constant-velocity Kalman filter has to commit to one guess about how hard the target might maneuver. During the turn, that guess is badly wrong. Its reported uncertainty actually contracts while its error grows eightfold, so it isn't just imprecise, it's confidently wrong. NEES peaks near 1470 against an ideal of 6.

The fix: an adaptive model bank

An interacting multiple model filter refuses to make that choice. It runs several filters in parallel, one tuned for quiet cruise and one for a hard maneuver, and lets each measurement vote on which is currently right. The part that matters is that the combined uncertainty carries a term for how much the models disagree, so the moment a maneuver starts the reported uncertainty grows, before any single model has had time to adapt.

Baseline scenario, identical measurements fed to both filters
MetricSingle filterModel bank
Mean NEES (ideal 6)174.184.33
Peak NEES147045
Position error (RMSE)29.46 m10.35 m
Worst 5% of frames75.40 m18.27 m
Frames over-confident23.9%3.7%

Across 200 randomized runs, 186 of the 200 single-filter runs came out badly over-confident. None of the model-bank runs did.

The model bank is not free, though, and the Benign cruise scenario is there to show the bill. It is the baseline flight with the maneuver taken out and nothing else changed, so the constant-velocity assumption genuinely holds. On that run the single filter is the better estimator: mean NEES 3.67 against 2.94, and 8.26 m of position error against 9.28 m. With no maneuver to detect, the disagreement term just inflates the covariance for nothing.

Reading the scene

The Scenario menu picks which flight to replay and the EKF/IMM toggle picks which filter's recording of that same flight to show, so switching between them compares the two estimators rather than two different flights. Scrub to the turn at t = 25 s and watch the purple uncertainty ellipsoid as you flip between them.

  • The path the target actually flew, which the filter never sees
  • What the filter believes, built only from noisy measurements
  • The filter's claimed uncertainty, exaggerated by the Scale control so it stays visible at this range
  • Stretches where the filter was provably over-confident

On a model-bank run, the Maneuver model meter shows the filter's own live belief that the target is turning. It climbs from about 30% to nearly 90% within a second of the real maneuver starting.

How it is built

The simulation and both estimators are dependency-free C++20, and the analysis and plots are Python. This viewer is plain JavaScript with canvas 2D: no framework, no build step, no dependencies. It replays recorded CSV output rather than driving the simulation, so every frame you see here is reproducible from a scenario file plus a seed.

This is a portfolio-grade synthetic model, not an operational sensor simulation. It deliberately leaves out Earth curvature, terrain, clutter, false alarms, data association and sensor bias.