Skip to content

About

๐Ÿ›ฐ๏ธ๐ŸŸข A 2D synthetic radar target tracking simulation and trajectory estimation system powered by Kalman Filtering in C++.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

RadarTrackingSim banner

RadarTrackingSim

C++ CMake Kalman Filter Radar License

A clean, object-oriented C++ simulation of a single-target 2D radar tracking system, built to demonstrate synthetic radar measurement generation, Gaussian sensor noise, and Kalman Filterโ€“based state estimation.

Tracking result Ground truth trajectory (solid), noisy radar measurements (scattered dots), and the Kalman Filter's estimate (dashed) for a single maneuvering air target.

Tip

๐ŸŸข Radar screen convention: in this README, radar/tracking-related highlights use the classic phosphor radar green (#39FF14) โ€” the same color long associated with analog radar and sonar displays.


Table of Contents

  1. Overview
  2. Why This Project Exists
  3. Architecture
  4. Class Design
  5. The Math: Kalman Filter
  6. Results
  7. Project Structure
  8. Building the Project
  9. Running the Simulation
  10. Visualizing the Results
  11. Configuration
  12. Roadmap (Future Versions)
  13. License

Overview

RadarTrackingSim simulates the core pipeline of a radar tracking system for a single air target moving in a 2D plane:

  1. ๐Ÿ›ฐ๏ธ A target moves through space with a (slightly curving) constant-velocity motion model.
  2. ๐Ÿ“ก A synthetic radar "observes" the target's true position and adds realistic Gaussian measurement noise.
  3. ๐Ÿงฎ A Kalman Filter consumes the noisy measurements and produces a smoothed, statistically optimal estimate of the target's position and velocity.
  4. ๐Ÿ“Š The full run (true position, noisy measurement, filtered estimate) is exported to CSV and visualized with professional charts.

This is V1 of the project โ€” intentionally scoped to a single target and a linear, constant-velocity Kalman Filter, so that the fundamental building blocks are easy to read, test, and extend.

Why This Project Exists

Radar tracking is a classic application of estimation theory. Real radars never see the "true" position of a target โ€” they see a noisy measurement corrupted by thermal noise, atmospheric effects, and quantization. The Kalman Filter is the textbook solution for recovering a clean state estimate from this noisy stream, and it remains the foundation of far more sophisticated tracking systems used in aviation, defense, and autonomous vehicles.

This project builds that pipeline from scratch, in modern C++, with:

  • No hidden "black box" math โ€” the Kalman Filter's matrix algebra is implemented explicitly and commented step by step.
  • A clean separation of concerns between the physical simulation (Target), the sensor model (Radar), and the estimator (KalmanFilter).
  • A CMake build system so it compiles the same way on any platform with a C++17 compiler.

Note

This project is a learning-oriented reference implementation, not a certified/operational tracking system. It's meant to make the Kalman Filter's math tangible by actually running it end-to-end.

Architecture

Architecture diagram

Each simulation step flows through four collaborating classes:

  • Target advances the true (ground-truth) position and velocity of the aircraft using its motion model.
  • Radar takes that true position and returns a noisy measurement by adding zero-mean Gaussian noise to each axis.
  • KalmanFilter predicts the next state from its internal model, then corrects that prediction using the noisy radar measurement.
  • Simulation orchestrates the loop, collects every step's data, and exports it to CSV for plotting.

Class Design

Class Responsibility
Vector2D Minimal 2D vector/point type used throughout the project (position, velocity).
Target Owns the ground-truth kinematic state of the aircraft. Supports constant-velocity motion with an optional turn rate for a more realistic, curved flight path.
Radar ๐ŸŸข Synthetic sensor. Converts a true position into a noisy measurement using std::normal_distribution (Gaussian/white noise).
KalmanFilter ๐Ÿงฎ Implements a 4-state (x, y, vx, vy) linear Kalman Filter with explicit predict() and update() steps. All matrix operations (multiplication, transpose, 2ร—2 inversion) are hand-written for full transparency โ€” no external linear algebra library is required.
Simulation Orchestrates the per-step pipeline (Target โ†’ Radar โ†’ KalmanFilter), records results, and exports them to CSV.

This separation means each class can be unit-tested, replaced, or extended independently โ€” for example, swapping in an Extended Kalman Filter later only touches the KalmanFilter class.

The Math: Kalman Filter

The filter tracks a 4-dimensional state vector:

X = [ x, y, vx, vy ]แต€

Prediction step (uses the motion model to project the state forward by dt):

X_k = F ยท X_(k-1)
P_k = F ยท P_(k-1) ยท Fแต€ + Q

Update step (corrects the prediction using the new noisy measurement Z):

y = Z - H ยท X_k                (innovation / residual)
S = H ยท P_k ยท Hแต€ + R           (innovation covariance)
K = P_k ยท Hแต€ ยท Sโปยน             (Kalman gain)
X_k = X_k + K ยท y              (corrected state)
P_k = (I - K ยท H) ยท P_k        (corrected covariance)

Where:

  • F is the constant-velocity state transition matrix (position updated by velocity ร— dt).
  • H is the measurement matrix, selecting the position components (x, y) from the state.
  • Q is the process noise covariance (models unpredictable target maneuvers).
  • R is the measurement noise covariance (matches the radar's known noise level).
  • P is the state covariance matrix (the filter's own uncertainty about its estimate).

All of this is implemented by hand in KalmanFilter.cpp using fixed-size arrays โ€” readable, dependency-free, and easy to step through in a debugger.

Results

Running the default configuration (200 steps, dt = 0.5s, radar noise ฯƒ = 25m) produces the following error comparison:

Error over time

Important

In this run, the Kalman Filter reduces the average position error by roughly 45โ€“50% compared to the raw, unfiltered radar measurements โ€” while also producing a visibly smoother trajectory (see the trajectory plot above).

Exact numbers vary slightly between runs unless a fixed random seed is used (V1 defaults to a fixed seed of 42 for reproducibility).

Project Structure

RadarTrackingSim/
โ”œโ”€โ”€ CMakeLists.txt              # CMake build configuration
โ”œโ”€โ”€ include/                    # Public headers (class interfaces)
โ”‚   โ”œโ”€โ”€ Vector2D.h
โ”‚   โ”œโ”€โ”€ Target.h
โ”‚   โ”œโ”€โ”€ Radar.h
โ”‚   โ”œโ”€โ”€ KalmanFilter.h
โ”‚   โ””โ”€โ”€ Simulation.h
โ”œโ”€โ”€ src/                        # Implementation files
โ”‚   โ”œโ”€โ”€ Target.cpp
โ”‚   โ”œโ”€โ”€ Radar.cpp
โ”‚   โ”œโ”€โ”€ KalmanFilter.cpp
โ”‚   โ”œโ”€โ”€ Simulation.cpp
โ”‚   โ””โ”€โ”€ main.cpp
โ”œโ”€โ”€ scripts/
โ”‚   โ”œโ”€โ”€ plot_results.py               # Generates the trajectory & error charts (interactive + saved)
โ”‚   โ”œโ”€โ”€ make_architecture_diagram.py  # Regenerates assets/architecture.png
โ”‚   โ””โ”€โ”€ make_radar_banner.py          # Regenerates the radar-green banner image
โ”œโ”€โ”€ data/                        # CSV output from the simulation (generated)
โ”œโ”€โ”€ assets/                      # Charts/images used in this README (generated)
โ”œโ”€โ”€ README.md                    # This file (English)
โ””โ”€โ”€ README_TR.md                 # Turkish version

Building the Project

Requirements: a C++17-capable compiler (GCC โ‰ฅ 9, Clang โ‰ฅ 10, MSVC โ‰ฅ 2019) and CMake โ‰ฅ 3.15.

git clone <this-repo-url>
cd RadarTrackingSim
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make
cd ..

This produces an executable at build/radar_tracking_sim. The cd .. at the end matters โ€” the next step assumes you're back in the project root.

Running the Simulation

From the project root (not from inside build/):

./build/radar_tracking_sim

This runs the full simulation (target motion โ†’ radar noise โ†’ Kalman filtering) and writes the results to data/simulation_output.csv, relative to wherever you ran the command from โ€” which is why running it from the project root matters:

time, true_x, true_y, meas_x, meas_y, est_x, est_y

Visualizing the Results

The plotting script requires Python 3 with matplotlib and numpy:

pip install matplotlib numpy

Then, from the project root:

python3 scripts/plot_results.py

This is the correct, working command. By default it:

  • reads data/simulation_output.csv (the file produced in the previous step),
  • (re)writes assets/tracking_result.png and assets/error_over_time.png,
  • and opens an interactive Matplotlib window (plt.show()) if your machine has a display/GUI available, so you can pan, zoom, and inspect the trajectory live โ€” not just overwrite the saved images silently.

Useful variations:

# Headless machine / SSH session / CI โ€” skip the interactive window, just save the PNGs
python3 scripts/plot_results.py --no-show

# Point at a different CSV location or output folder
python3 scripts/plot_results.py --csv build/data/simulation_output.csv --outdir assets

Note

If you run the simulation from inside build/ instead of the project root (e.g. cd build && ./radar_tracking_sim), the CSV ends up at build/data/simulation_output.csv. In that case, run the plotting script with --csv build/data/simulation_output.csv as shown above.

Configuration

All simulation parameters live in Simulation::Config (see main.cpp):

Parameter Description Default
dt Time step per simulation iteration (seconds) 0.5
numSteps Total number of simulation steps 200
initialPosition Target's starting position (m) (0, 0)
initialVelocity Target's starting velocity (m/s) (40, 15)
targetTurnRateRadPerSec Turn rate applied to the target's velocity vector (rad/s) 0.02
radarNoiseStdDev Standard deviation of the radar's Gaussian measurement noise (m) 25.0
kalmanProcessNoiseStd Assumed process noise standard deviation for the filter 1.0
radarSeed Random seed for reproducible noise generation 42

Feel free to tune these to see how the Kalman Filter behaves with noisier sensors, sharper turns, or different sampling rates.

Roadmap (Future Versions)

This is explicitly a V1. Natural next steps for future iterations include:

  • ๐ŸŽฏ Multi-target tracking with data association (e.g. Nearest Neighbor, JPDA).
  • ๐Ÿ“ก Range/azimuth (polar) radar measurements instead of direct Cartesian noise, with an Extended Kalman Filter (EKF) or Unscented Kalman Filter (UKF).
  • ๐ŸŒ€ Maneuvering-target models (e.g. Interacting Multiple Model / IMM filters).
  • ๐Ÿ–ฅ๏ธ Real-time visualization instead of post-run CSV plotting.
  • โœ… Unit tests (GoogleTest) for each class.

License

This project is provided as an educational reference implementation. Feel free to use, modify, and extend it for learning or prototyping purposes.

About

๐Ÿ›ฐ๏ธ๐ŸŸข A 2D synthetic radar target tracking simulation and trajectory estimation system powered by Kalman Filtering in C++.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages