Bringing Ofdm Test
Bringing OFDM to Hardware: Building and Debugging a GNU Radio USRP Test
Introduction
As part of my work on the Hardware-in-the-Loop (HIL) CI framework for GNU Radio using CortexLab, one of the important steps was to move an OFDM transmission and reception flowgraph from a software-only setup to real SDR hardware.
The initial OFDM example was designed around GNU Radio’s virtual source and sink blocks. While this is useful for validating the signal-processing chain, it does not test whether the complete flowgraph works correctly with actual hardware.
The goal was therefore to build an OFDM TX/RX experiment that could run on CortexLab nodes equipped with USRP devices and could eventually be executed automatically as part of the HIL testing framework.
From a Software Flowgraph to Real Hardware
The original OFDM example used GNU Radio’s virtual connections for transmitting and receiving samples.
For the HIL experiment, I replaced this architecture with:
TX Flowgraph
Message
↓
OFDM Modulation
↓
USRP Sink
↓
RF
↓
USRP Source
↓
OFDM Demodulation
↓
File Sink
↓
Received Payload
This introduced several additional parameters that are not relevant in a purely software-based simulation.
For example:
- Sample rate
- Center frequency
- TX gain
- RX gain
- TX amplitude
- Hardware synchronization
- USRP source/sink configuration
These parameters had to be carefully coordinated between the transmitter and receiver.
Parameterizing the Experiment
Instead of hard-coding experiment parameters inside the Python flowgraphs, I introduced a parameters.json file.
A simplified configuration looks like:
{
"message": "Hello CortexLab",
"tx_gain": 10,
"tx_amplitude": 0.05,
"sample_rate": 195312,
"rx_gain": 20,
"center_frequency": 915000000,
"rx_output_file": "rx_payload.bin"
}
The TX and RX scripts read the configuration from this file and use the values to configure their respective GNU Radio blocks.
This provides an important advantage for HIL testing: the experiment configuration can be changed without modifying the flowgraph itself.
For example, the same OFDM experiment can be executed with different:
- Messages
- Frequencies
- Gains
- Sample rates
- Output files
This also makes the experiment easier to integrate with an automated CI system.
Making TX and RX Parameters Consistent
One of the most important debugging lessons from this experiment was that OFDM parameters must match between the transmitter and receiver.
Parameters such as:
- FFT length
- Cyclic prefix length
- Occupied carriers
- Pilot carriers
- Pilot symbols
- Header configuration
- Sync words
- Constellation/modulation parameters
are not independent on the two sides.
If the transmitter generates an OFDM frame using one configuration while the receiver expects another, the receiver may still execute successfully but fail to recognize or decode the transmitted packet.
This initially caused problems during the hardware test.
After comparing the TX and RX configurations, I found that some of the header-related parameters were not exactly matching. I updated the RX configuration so that it used the same OFDM parameters as the transmitter.
Debugging the OFDM Header
After correcting the basic configuration, I started debugging the complete receive chain.
The RX flowgraph contains several stages responsible for detecting and decoding an OFDM packet.
Conceptually:
USRP Source
↓
OFDM Synchronization
↓
Header Parser
↓
Header/Payload Demultiplexer
↓
Payload Decoder
↓
File Sink
One of the errors observed during debugging was:
packet_headerparser_b :info:
Detected an invalid packet at item 0
followed by:
header_payload_demux :
Parser returned #f
This was particularly interesting because the hardware flowgraph itself was running without a fatal execution error.
The problem was therefore not simply that the RX flowgraph failed to start. Instead, the receiver was receiving samples but was unable to interpret the OFDM frame correctly.
Debugging Step by Step
Rather than treating the entire RX chain as a single black box, I decided to debug it incrementally.
The first step was to verify that the USRP receiver was actually producing samples.
I inserted a file sink directly after the USRP source:
USRP Source
↓
File Sink
This allowed me to determine whether raw IQ samples were being captured successfully.
If the file contained data, it confirmed that:
- The USRP was connected.
- The UHD configuration was valid.
- The RX flowgraph was receiving samples.
- The problem was likely somewhere further downstream in the OFDM processing chain.
This approach made the debugging process much more systematic.
Handling the Payload
Another part of the experiment was verifying that the transmitted message actually reached the receiver.
The transmitter converts the message into a payload representation before passing it into the OFDM transmission chain.
For example:
Hello CortexLab
is represented as:
48656c6c6f20436f727465784c6162
during payload processing.
The receiver eventually writes the decoded payload into:
rx_payload.bin
The analysis stage can then inspect this file and determine whether the received payload matches the transmitted data.
This creates a simple end-to-end validation:
TX Message
↓
OFDM Encoder
↓
USRP
↓
RF Channel
↓
USRP
↓
OFDM Decoder
↓
rx_payload.bin
↓
Analysis
↓
PASS / FAIL
Separating Execution From Analysis
Another improvement was separating the actual experiment from result validation.
The RX flowgraph is responsible for receiving and storing the payload.
The analysis script is responsible for determining whether the experiment succeeded.
This separation is useful for HIL CI because the controller does not need to understand the internal details of the OFDM flowgraph.
Instead, the experiment can produce a simple result such as:
{
"status": "passed"
}
or:
{
"status": "failed"
}
The CI system can then use this result to decide whether the hardware test passed.
What I Learned From the Debugging
The OFDM experiment taught me that getting a GNU Radio flowgraph to execute is only the first step.
There are several layers that need to be verified:
1. Hardware layer
Is the USRP correctly detected and configured?
2. Sample layer
Is the receiver actually obtaining IQ samples?
3. Synchronization layer
Can the receiver identify the OFDM frame?
4. Header layer
Can the receiver correctly decode the packet header?
5. Payload layer
Can the receiver recover the transmitted payload?
6. Analysis layer
Can the experiment automatically determine whether the expected data was received?
This layered approach is especially important for HIL testing because a test should distinguish between a hardware/configuration problem and an actual GNU Radio processing problem.
Why This Matters for HIL CI
The final goal is not simply to make one OFDM experiment work manually.
The experiment needs to become part of an automated hardware-testing framework.
The intended workflow is:
GitHub Pull Request
↓
Identify GNU Radio revision
↓
Build / select matching GNU Radio environment
↓
Create HIL experiment
↓
Reserve CortexLab nodes
↓
Run TX/RX OFDM experiment
↓
Collect rx_payload.bin
↓
Run analysis.py
↓
Generate result.json
↓
Return PASS / FAIL
↓
GitHub Actions
This allows a GNU Radio change to be tested against real SDR hardware instead of relying only on software-based unit tests.
Current Status
The OFDM flowgraph has now been adapted for hardware-based execution.
The main changes include:
- Replacing virtual source/sink components with USRP hardware.
- Parameterizing TX and RX configurations.
- Introducing
parameters.json. - Matching the OFDM configuration between TX and RX.
- Debugging header synchronization and packet parsing.
- Capturing the received payload into
rx_payload.bin. - Separating experiment execution from result analysis.
- Preparing the experiment for integration with the CortexLab HIL CI framework.
The remaining work is to make the complete test robust enough for automated execution and ensure that the analysis stage can reliably distinguish successful and unsuccessful hardware transmissions.
Conclusion
Moving the OFDM example from a software-only environment to real USRP hardware exposed several issues that would not necessarily appear during simulation.
The most important lesson was that hardware testing requires validating the complete signal path, not just whether the GNU Radio flowgraph starts successfully.
By parameterizing the experiment, synchronizing TX/RX configurations, debugging the receive chain stage by stage, and separating execution from analysis, the OFDM experiment is becoming a reusable building block for the GNU Radio HIL CI framework.
Ultimately, this work will allow GNU Radio changes to be tested automatically on real SDR hardware through CortexLab, bringing hardware validation closer to the normal software CI workflow.