February 06 2025
RF Capture #1
Stage 2 Area 3
We’re given an RF capture and the hint:
"You'll need to reverse this RF capture. The freq. is 315MHz and sample rate 1MHz. Use GNURADIO."
I'd never used GNU Radio before, and was reluctant to learn it before exploring my typical workflow. So I did what I always do first and opened it in Inspectrum.
RF captures typically contain complex IQ samples. This assumption led me to open the file as
cf32instead off32, convincing me it was FSK until I corrected the format.
Identifying and demodulating the signal in Inspectrum
Once the file was loaded as real float (-f f32), the modulation became obvious as ASK/OOK. Using Inspectrum's amplitude plot (envelope), demodulation became straightforward - filter the signal, add a threshold plot, measure the timing with the cursors, and export the resulting bits.
Summary from Inspectrum:
- Signal offset: 250 KHz
- Modulation: ASK / OOK
- Symbol rate: 5 kBd (200 µs)
- Preamble:
01010101 01010101(0x55 0x55, "UU") - Packet length: 144 bits (18 bytes)
010101010101010101010111011001010110110001101100001000000110010001101111011011100110010100101110001000000101010001101000011001010111001101100101
# UUWell done. These
010101010101010100100000011100110110101101101001011011000110110001110011001000000111011101101001011011000110110000100000011000110110111101101101
# UU skills will com
010101010101010101100101001000000110100101101110001000000110100001100001011011100110010001111001001000000110110001100001011101000110010101110010
# UUe in handy later
010101010101010100100000011011110110111000101110001000000101010001101000011001010010000001100011011011110110010001100101001000000111100101101111
# UU on. The code yo
010101010101010101110101001000000111011101100001011011100111010000100000011010010111001100100000010001110100011001010011010001100101001101000110
# UUu want is GFSFSF
010101010101010100110101001101000011010100110011001101010000101000001010000010100000101000001010000000000000000000000000000000000000000000000000
# UU54535Each packet starts with a fixed preamble (0x55 0x55), so removing the first 16 bits leaves the actual payload text. After repeating this process for each of the 6 packets, the message and code are readable - challenge solved!
Recreating the demodulation in GNU Radio
After reaching the next RF challenge (stage 3 area 1), Inspectrum struggled to demodulate the signals. It was clear that GNU Radio (as the hint had suggested) would be needed to properly clean and process the capture. To start learning the new software, I came back and rebuilt this demodulation using GNU Radio.
Translating Inspectrum into a signal-processing pipeline
Before building anything in GNU Radio, I needed to translate what I was doing in Inspectrum into actual DSP steps:
- The selection band effectively mixes the signal down to baseband (0 Hz)
- The sidebands behave like a low-pass filter / bandwidth selection
- The amplitude plot is the magnitude of the complex samples in the time domain (ASK envelope)
- The threshold plot is a slicer that turns amplitude into 0/1
- The cursors are manual symbol timing / sampling (measuring the symbol period and where to sample)
Once I had that mental model, recreating the same thing in GNU Radio was just a matter of choosing the equivalent blocks.
Flowgraph
- File Source - load the RF capture (
f32) - Xlating FIR Filter - mix to baseband (0 Hz) + low-pass + decimate
- Complex to Mag - convert IQ to amplitude (ASK/OOK envelope)
- Keep 1 in N - sample once per symbol (
N = int(samp_rate / baud_rate)) - Threshold - output 0/1
- Delay (optional) - bit/byte alignment tweak for ASCII
- Pack K Bits (8) - pack bits into bytes
- File Sink - write the demodulated bytes
Keep 1 in Nis used as a basic symbol sampler that assumes perfect timing. For more complex captures, use the adaptiveSymbol Sync.
Result
The GNU Radio output perfectly matches the earlier Inspectrum demodulation. Since there's no explicit preamble synchronisation, byte alignment can vary, but the packets are still easy to recover by trying the 8 possible bit offsets, or scanning the bitstream for the preamble.
bitstring = "".join(f"{b:08b}" for b in packet_bytes)With the packets extracted, they decode to the same message and code as before - but this time via GNU Radio - giving me a solid foundation for the next RF challenge.