Implementation Details¶
This project is built as a small, inspectable radar simulation pipeline rather than a black-box simulator. Each module owns one stage of the pipeline, and the output of one stage becomes the input of the next stage.
Overall Design¶
The main data path is:
mesh file
-> TriangleMesh
-> per-chirp transformed triangles
-> visible triangles
-> ScatterSet
-> raw radar data cube
-> FFT outputs
-> plots
The important design choice is that the simulator does not jump directly from a mesh to a heatmap. It keeps intermediate concepts explicit:
- mesh loading
- geometric visibility
- scattering approximation
- channel-level signal synthesis
- range/Doppler/angle FFT
That makes the project easier to debug and easier to teach.
1. Mesh Loading¶
mesh_loader.py reads OBJ, STL, and GLB files and converts them into TriangleMesh.
TriangleMesh only stores:
vertices: point coordinatesfaces: triangle vertex indices
Rendering information such as textures, materials, and animation is ignored. The radar simulator only needs geometry.
2. Per-Chirp Target Transformation¶
For each chirp, the target is transformed as a rigid body.
The target position is:
position(t) = initial_position + velocity * slow_time
Then a fixed Euler rotation is applied. This creates a simple moving target model that is enough for early range and Doppler experiments.
3. Visibility Filtering¶
visibility.py removes triangles that should not contribute to the radar echo.
It uses two checks:
- Front-facing check: keep triangles whose normals point toward the radar.
- Occlusion check: cast a ray from the radar phase center to the triangle center and discard the triangle if another face blocks the ray.
This is intentionally direct and readable. It is not yet accelerated by BVH or spatial indexing.
4. Scatter Model¶
scatter_model.py converts each visible triangle into one scattering point.
The scattering point is placed at the triangle center. Its strength is computed from:
- triangle area
- incidence angle
- global target reflectivity
This approximation is not a full electromagnetic model. It is a teaching-oriented model that makes the relationship between geometry and radar signal visible.
5. Signal Synthesis¶
signal_synth.py generates the raw radar data cube.
For each chirp, each virtual channel, and each scatterer, it computes:
- TX-to-scatterer distance
- scatterer-to-RX distance
- round-trip delay
- distance attenuation
- beat frequency
- complex phase over fast time
All scatterer returns are summed into one complex signal per channel.
The output shape is:
num_adc_samples x num_chirps x (num_tx * num_rx)
6. FFT Pipeline¶
fft_pipeline.py performs three FFT stages:
- Range FFT over ADC samples.
- Doppler FFT over chirps.
- Angle FFT over virtual MIMO channels.
The outputs include both full cubes and projected maps for visualization.
Why This Structure Works¶
The implementation is deliberately modular:
- geometry code does not know radar parameters
- radar configuration does not synthesize signals
- visibility does not compute FFT
- multiprocessing only splits work; it does not change the physical model
This separation makes the simulator easier to extend. For example, a future version can replace the visibility stage with BVH acceleration or replace the scatter model with a more detailed material model without rewriting the whole project.
Beginner Reading Path¶
If you are new to the project, read it from the outside in:
- Start with
main.py. It shows the full command-line flow: parse arguments, create configuration objects, load the mesh, run simulation, run FFT, and save output. - Move to
radar_model.py. It explains what the radar needs to know: carrier frequency, bandwidth, chirp duration, ADC samples, chirp count, and antenna count. - Read
mesh_loader.pyandgeometry.py. These files explain how a 3D model becomes triangles and how those triangles are measured. - Read
visibility.py. This is where the simulator decides which surfaces the radar can actually see. - Read
scatter_model.py. This turns visible surfaces into point-like radar scatterers. - Read
signal_synth.py. This is the core file where distances become delays, delays become beat frequencies, and scatterers become complex radar samples. - Read
fft_pipeline.py. This is where the raw cube becomes range, velocity, and angle maps.
This order is easier than reading alphabetically because it follows the actual execution path.
Stage-by-Stage Inputs and Outputs¶
The project is easier to understand if every stage is viewed as a transformation:
| Stage | Input | Output |
|---|---|---|
| Mesh loading | OBJ / STL / GLB file |
TriangleMesh |
| Geometry transform | mesh + target motion | per-chirp triangle positions |
| Visibility | transformed triangles + radar origin | visible triangles |
| Scatter model | visible triangles | scatterer centers and strengths |
| Signal synthesis | scatterers + radar config | raw complex RDC |
| FFT pipeline | raw complex RDC | range/Doppler/angle outputs |
| Plotting | FFT maps | PNG heatmaps |
This table is also a debugging guide. If a result looks wrong, find the earliest stage where the intermediate output becomes unreasonable.
Why Keep the Model Simple¶
The simulator intentionally omits many advanced radar effects. That is not a bug; it is a design choice. The first goal is to make the main signal path visible.
For example, a production radar system may include antenna radiation patterns, receiver noise, calibration errors, leakage, multipath, clutter suppression, CFAR detection, and tracking. Adding all of those at once would make the code harder to learn from.
This project starts with a smaller model:
surface geometry -> simple scattering -> complex samples -> FFT maps
Once this path is understood, advanced effects can be added one at a time.
How Code Maps to Radar Concepts¶
The code is intentionally named after radar concepts:
RadarConfigis the radar hardware and waveform description.TargetMotionis the moving object description.TriangleMeshis the target geometry.VisibilityResultis the set of surfaces that can reflect directly to the radar.ScatterSetis the simplified scattering model.rdcis the raw radar data cube before FFT interpretation.
The most important variable is rdc. It is the bridge between simulation and radar signal processing. Everything before rdc creates the signal. Everything after rdc interprets the signal.
What to Change First When Extending¶
Different research directions map to different modules:
| Goal | First module to modify |
|---|---|
| Better mesh loading | mesh_loader.py |
| Faster visibility | visibility.py |
| More realistic scattering | scatter_model.py |
| Noise or hardware effects | signal_synth.py |
| Different radar axes | fft_pipeline.py |
| More CLI options | main.py |
This is why the project is split into small files. The boundaries are meant to make future experiments local rather than global rewrites.