Collecting mmWave beam-sweep data is the easy part of propagation research. The hard part is what comes next: turning a dense CSV of 3,969 signal-to-noise ratio measurements into something you can actually interpret — a spatial picture of which beam directions work, where specular reflections appear, and how the room geometry shapes the link. I built the Ray Tracing Micro Tool to solve exactly that problem, and this post explains the design decisions behind it.
The Problem: From Raw Data to Spatial Insight
Our phased-array mmWave radios support 63 discrete beam directions each, spanning –45° to +45° in approximately 1.5° steps. An exhaustive beam sweep records the received SNR for every one of the 63 × 63 = 3,969 TX/RX beam pair combinations. The result is a compact CSV file — four columns, no header, 3,969 rows — but there is nothing obvious to look at in raw form.
The standard approach in our lab was to load the data into a MATLAB script and manually tweak plot settings each time. Recreating figures for a new experiment meant adjusting hardcoded paths and column mappings. It worked, but it didn't scale. Every new dataset produced a new version of the same script. I wanted a single command that would ingest any experiment folder and produce both publication-quality static heatmaps and a fully interactive report.
Architecture: A Lightweight CLI with Two Modes
The tool is structured as a single entry-point script (raytrace.py) that delegates to two independent modules:
- generate_report.py — builds a self-contained HTML report with an interactive floor-plan overlay, live beam selection, and specular ray-tracing visualization. The entire output is a single
.htmlfile; no web server needed, no external dependencies to install in the browser. - plot_heatmap.py — generates four publication-quality 500 dpi PNG and SVG figures: raw Rx power, SNR heatmap (TX angle × RX angle), incident-angle power, and incident-angle SNR. It also exposes a
LiveHeatmapPlotterclass for real-time sweep monitoring as measurements come in.
Keeping the two modes as separate modules meant each could be tested and evolved independently. The CLI layer in raytrace.py does late imports — it only imports numpy, pandas, matplotlib, and seaborn once a valid subcommand is selected. This means validation errors (missing directory, missing snr_data.csv) surface immediately, even if the Python environment is incomplete.
The Interactive HTML Report
The most useful output for understanding a measurement campaign is the interactive report. The report embeds all data — the SNR matrix, the floor plan, the antenna positions, the wall segments — directly in the HTML as JavaScript variables. This makes it fully self-contained: email it, archive it, or open it three years later and it works identically.
The core visualization has three linked panels:
- SNR heatmap — a 63 × 63 grid where each cell is colored by the measured SNR. Clicking a cell selects that TX/RX beam pair.
- Floor plan overlay — shows the room geometry with the TX and RX antennas drawn to scale. When a beam pair is selected, the tool draws the TX beam cone, the RX beam cone, and the specular reflection path (computed in real time using the law of reflection against each wall segment).
- Beam info panel — displays the exact TX angle, RX angle, and SNR for the selected pair, plus which wall produced the strongest specular contribution.
The "best beam" — the pair with the highest measured SNR — is highlighted automatically on load, so the most important result is immediately visible without any interaction.
The Floor Plan Editor
To overlay beam paths on the actual room, the tool needs to know where the walls are. I built floorplan.html, a standalone browser-based editor that lets you draw a room to scale by clicking to place wall endpoints. You can drop predefined shapes (squares, rectangles), drag endpoints to adjust, and undo the last action. When you're done, clicking Save JSON exports a floorplan.json file containing TX position, RX position, boresight angles, and all wall segments as pixel coordinates (2 px = 1 inch).
The included floorplan.json is pre-configured for the NH Building 2nd-floor lab at UNL — where our mmWave measurement platform lives — so anyone in our group can run the tool immediately without touching the floor plan configuration.
Specular Ray Tracing
The specular reflection visualization is the part I'm most pleased with. Given the TX position, boresight, and selected TX beam index, the tool computes the physical direction the TX beam points in 2D space. It then finds the image point of the TX through each wall using the standard mirror-reflection construction and checks whether the line from that image point to the RX position intersects the wall segment within its bounds. When it does, the reflection point and path are drawn on the floor plan, and the incident angle is computed and displayed.
This is purely 2D geometric optics — no full electromagnetic simulation — but it is fast enough to recompute on every beam selection in the browser, and it consistently matches the high-SNR ridge patterns visible in the heatmap for our lab environment.
What I Would Do Differently
The tool currently handles only single-bounce specular reflections. In cluttered indoor environments, second-bounce paths through two walls are common and can dominate the received power. Extending the ray tracer to handle two-bounce paths is the obvious next step.
I also kept the floor plan editor intentionally simple — click to place walls, no snapping to grid, pixel coordinates only. For more complex rooms or multi-floor environments, a proper parametric editor would be more robust. That said, for our lab's measurement campaigns the current editor has been sufficient.
Using the Tool
The full source is on GitHub. Getting started requires only four commands:
git clone https://github.com/apalapramanik/Ray-Tracing-Micro-Tool.git
cd Ray-Tracing-Micro-Tool
pip install -r requirements.txt
python raytrace.py report example_experiment/
The last command reads example_experiment/snr_data.csv, generates the report, and opens it in your browser. An example dataset from a real 63 × 63 sweep in our lab is included, so you can see the output immediately without collecting any measurements of your own.
If you use the tool in your own mmWave research, I'd be glad to hear about it — the contact page is always open.