This project implements a real-time passive radar system using the RTL-SDR platform and Python. The radar passively receives signals (e.g., from FM broadcast stations) and computes target motion using range-Doppler analysis. The application is visualized through a PyQt5 GUI and uses multithreading, real-world units, multi-antenna support, target tracking, clustering, and real-time database logging.
- Why: Prevents GUI freezing while SDR samples are processed.
- How:
- Each active surveillance antenna is assigned a
RadarWorkerthread. - These threads run signal processing routines (correlation, FFT, range-Doppler mapping) asynchronously.
- Results are emitted via PyQt signals and handled in the main thread for GUI-safe updates.
- Each active surveillance antenna is assigned a
- Why: Allows comparison between receivers, directional tracking, or spatial diversity.
- How:
- Up to 4 antennas are supported.
- Each has a checkbox in the GUI to toggle it on/off.
- Each active antenna creates its own
RtlSdrobject and thread.
- Why: Organizes visualization per antenna for clarity and scalability.
- How:
- A
QTabWidgetholds tabs labeled "Antenna 1" through "Antenna 4". - Each tab contains a Matplotlib canvas showing a range-Doppler map.
- A
- Why: Enables detection of objects based on delay (range) and Doppler shift (velocity).
- How:
- Cross-correlation is used to find range.
- Doppler FFT is applied across a sliding window of correlated samples.
- Units:
- Range axis in meters
- Velocity axis in meters per second (m/s)
- Why: Groups peaks in the range-Doppler map into targets, reducing noise and improving tracking.
- How:
- Peaks are identified where power is within 10 dB of max.
DBSCANis applied to spatially cluster these into grouped detections.- Centroids of these clusters are passed to the tracker.
- Why: Maintains continuity of moving objects and assigns persistent identifiers.
- How:
SimpleTrackermaintains a list oftrackswith positions, history, and a unique ID.- Tracks are updated frame-by-frame based on proximity to current detections.
- Tracks that disappear for a defined number of cycles (
max_lost) are pruned.
- Why: Translates sample data into real-world interpretable values.
- How:
- Range in meters using:
range_bin * c / (2 * sample_rate) - Velocity in m/s using:
doppler_freq * λ / 2(λ = wavelength)
- Range in meters using:
- Why: Enables persistent identification across updates and sessions.
- How:
- Each new target is assigned an
idwhen initialized. - The ID is displayed next to the target in the plot and stored in the database.
- Each new target is assigned an
- Why: Keeps a persistent history of target activity for analysis or export.
- How:
- A SQLite database is initialized (
radar_tracks.db) with atrackstable. - Each tracked object (range, velocity, time, antenna, ID) is logged in real time using
INSERT INTO.
- A SQLite database is initialized (
passive_radar_gui.py: Main GUI + processing logic
- Python 3.8+
- RTL-SDR compatible hardware
- Dependencies:
PyQt5,numpy,scipy,matplotlib,scikit-learn,pyrtlsdr
pip install PyQt5 numpy scipy matplotlib scikit-learn pyrtlsdrpython passive_radar_gui.py- Add heading estimation or AoA (angle of arrival)
- Network streaming of data
- Advanced tracking (Kalman filter, JPDA, etc.)
- Web interface for remote viewing