Random Quote Board

Playing Back IQ Files with Gnu Radio

Gary Schafer, June 2022

There are a lot of different SDRs, just as there are a lot of different SDR programs that you can use to control said SDRs. One thing that makes SDRs so useful is their ability to record IQ samples. If you're new to SDRs and digital signal processing and are wondering, "What's an IQ sample and why is it so important?", know this: the IQ samples are what comes off of the SDR. They're nothing more than numbers. But you can use those numbers to show you pretty spectra, demodulate signals to hear music or look at cool images, or track airplanes. By recording IQ samples, you're literally recording the samples coming off of the SDR. If you play them back, there's no difference between the samples when they first came off the SDR and when they're coming off of the hard drive or other storage media later. No difference at all..

I'm going to go through those programs that I've used to record IQ, then go through how I was able to play back the IQ samples using Gnu Radio.

"rtl_sdr" from Command Line

There's a small program for the RTL-type SDRs called, appropriately enough, "rtl_sdr". You can use this program from the command line to record IQ samples while controlling the center frequency, RF gain, sample rate and a few, other features. Here's an example showing a recording of a portion of the FM broadcast band with a 2.4 MHz sample rate, and also telling the system to collect 12 million samples (5 seconds).

rtl_sdr -f 90.9e6 -g 16 -s 2.4e6 -n 12e6 FM-Broadcast-90M9CF-2M4FS-20220611-1255.rsiq

Where:

Once I ran the program, it collected an IQ sample file. Do you know what such a file contains? Numbers. It contains numbers, which is all samples are. They're numbers. Nothing more. Using Gnu Octave, I was able to read the first ten numbers:

122 143 115 133 130 135 119 133 124 138

These ten numbers correspond to the first 5 values of both the in-phase (I) and quadrature (Q) signals. They alternate, with values 122, 115, 130, 119 and 124 being the in-phase (real) values and 143, 133, 135, 133 and 138 being the quadrature (imaginary) values. When I import a couple thousand values then divide them up in the same way, I can create a plot showing the two signals.

Plot of in-phase (blue) and quadrature (red) samples from a short IQ file captured with the RTL-SDR and using the "rtl_sdr" command.

The RTL-SDR uses an 8-bit digitizer. Note that all of the numbers center around 128. The output from this program must be a straight, unsigned 8-bit number. This means that they have values between 0 - 255. To make these into standard Gnu Radio samples, we need to:

Gnu Radio only has one block that can be used to read unsigned 8-bit samples. This is the "UChar to Float" block. I then use an "Add" block to remove the value of 128 offset, followed by dividing by 128 so that all amplitudes fall between +/- 1. Then I split the samples to make them complex. Here's the flowgraph I used to read the samples directly.

Gnu Radio Companion (GRC) flowgraph showing how to read samples directly from a file captured using the "rtl_sdr" command. The "File Source" is set to "byte" for "Output Type". The "UChar to Float" block converts the values from 8-bit unsigned integer into 32-bit floating point values. The "Add Const" block takes out the 128 offset, then the "Multiply Const" block divdes by 128 (1/128 = 7.8125e-3) so that all amplitudes fall between +/- 1. The "Stream Demux" alternates the output samples between the "re" ("real" or in-phase) and "im" ("imaginary" or quadrature) streams. The last blocks convert the stream of floating point samples into complex samples.
Properties for the File Source for reading an IQ sample file captured using the "rtl_sdr" command.
Properties for the "Multiply Const" block.
This is the output time and frequency domain displays from the flowgraph above.

SDR++

This program is a newer version of SDR# that is advertised as "the bloat-free SDR receiver". It's very similar to SDR#, though it has a version that will run on Linux. (NOTE: I've only been able to get SDR# to run on Windows.)

The main screen for SDR++ running on Linux Mint.
Record window of SDR++. This program has two options for recording output. One is "Baseband", which means IQ samples (almost) direct from the SDR. I say "almost" because, regardless of the bit encoding coming from the SDR, SDR++ will convert it into 16-bit integers that are then stored as a .WAV file. The other option is "Audio", which means it will be recording the demodulated output based on the settings in the "Radio" section. The ellipsis ("...") is used to set the directory used to store the output files. The "Record" button is used to toggle recording on and off.

It has the ability to record IQ as well as demodulated audio. In both cases, it will create a .WAV file. Do you know what a .WAV file is? It's a file of samples (again, either IQ or audio) with a header in it. Specifically, a 44-byte header. I used Gnu Octave to read in an array of samples, all of them as 16-bit integers, then separated out the in-phase (real) and quadrature (imaginary) components.

This is a time-domain display created in Gnu Octave by reading in the samples as signed 16-bit integers. Note the high values at the beginning. This is the 44-bytes of header data after reading it in as 16-bit integers, when in fact the header is a combination of different bit encoding types (8-bit, 16-bit and 32-bit integers).
SDR++ file metadata. This shows the various parameters of the WAV file stored in the first 44-bytes. This shows the basic file information, such as the type ("2 channels" means complex, in this case), bit encoding ("16 bits") and sample rate ("1920 kHz", which is equal to 1.92 MHz).
Gnu Radio flowgraph that reads in .WAV files created by SDR++. Because the file parameters includes the bit encoding, this block knows how to read in the samples and convert them to floating point without any further parameters.
File Source properties. This shows the number of channels ("N Channels") as 2. Normally, for audio WAV files, this indicates stereo. In this context, it refers to complex (in-phase and quadrature).
Gnu Radio displays of time and frequency domain from SDR++ file reader.

SDR#

This is one of the more popular programs, though it only works on Windows (and perhaps Mac, though I've never worked with Macs, so I can't say.) SDR# has a lot of different plugins that extend its basic capabilities.

SDR# main screen. The record capability is shown in lower, lefthand side.
SDR# main screen showing the allowable recording file types on the left. These are 8-bit integer, 16-bit integer and 32-bit floating point.

SDR# also provides the capabilities to record both IQ ("Baseband") and audio (demodulated) output. It can also set the bit encoding ("Sample Format", which is 8-bit integer, 16-bit integer and 32-bit floating point). Also, just as with SDR++, the output will be a .WAV file. The playback is the same as with SDR++. It doesn't matter the bit encoding for the .WAV file. The WAV File Source block will perform the correct conversion.

Spike

Signal Hound is a relatively small company in Washington state. They manufacture a small line of SDRs and computer-controlled signal generators. I saved up my pennies several years ago and purchased the BB60C, which I consider to be a high-end SDR.

Signal Hound BB60C. The BB60C connects to a computer via USB3.
Main screen from Spike, Signal Hound's software used to drive their different RF front ends. Unlike all of the other software shown in this post, this program provides the ability to scan over the entire frequency range of the RF system to which it is connected. The BB60C goes from 9 kHz to 6 GHz, though this sweep covers from 11 - 6000 MHz.

The default for Spike is to act as a SDR controller to create a spectrum analyzer. It can also be run in "Zero Span" mode. This locks a spectrum analyzer to a single frequency. This is similar to all of the other SDRs and the software that controls them; the BB60C (or whatever SDR Spike is controlling) will be at a particular center frequency. The sample rate for the BB60C starts at 40 MHz and can be decimated by powers-of-2, up to a maximum decimation of 8192.

Spike in "Zero Span". This currently shows various NOAA National Weather Radio (NWR) transmissions. The top, left graph is the FM demodulated time-domain, the next one down is the AM demodulated time-domain and the bottom is the spectral trace. The figure on the right is the spectrogram created using overlapping FFTs.
This is the "Zero Span" with a lower sample rate. Note how the spectrogram, when rotated 90 degrees counter-clockwise, is similar to the FM demodulated time-domain view.

The "Zero Span" also provides the ability to both record and playback IQ files. Spike is different from the other programs in how it records IQ. Some programs ("rtl_sdr", GQRX, Gnu Radio "File Sink") record straight IQ samples with no metadata. Others (SDR#, SDR++) record with IQ samples together with metadata, called an "inline" recording. Spike records two, separate files. One is the IQ file; the other contains the metadata. This is called "detached" recording.

Spike provides for a lot of customization of IQ recording parameters. Aside from the reference level ("Ref Level", which also sets the input gain), it also allows you to set the sample rate, IF bandwidth, file record directory, file prefix, and the amount of time to be recorded. The IQ file will be a series of interleaved in-phase and quadrature 16-bit integers.

Gnu Radio flowgraph used to playback IQ files captured using Signal Hound's Spike software. The file source is set to an "Output Type" of "short" (16-bit integer). The "IShort to Complex" block automatically creates complex samples from the input stream coming from the file source block. Note the scale factor of 16384. This ensures that the output of the block will fall between +/- 1.
This is the playback of the Spike IQ file using the Fnu Radio flowgraph.

GQRX

GQRX is an open-source program based on Gnu Radio and QT. It was written by Alexandru Csete. Before I go into the details of IQ recording and playback, I will say this: GQRX is, without a doubt, the best demodulation of FM stations of ANY program I've ever listened to. Bar none. I've created frequency demodulators (as a matter of fact, I think I've made them all), and I cannot figure out how he does it. Since the program is based on Gnu Radio, I've attempted to replicate his flowgraph in Gnu Radio, and it still doesn't sound as nice. No idea what he did, exactly, but it's awesome!

Main screen of GQRX. The tabs on the right allow the user to control the RF front end (gain, center frequency), demodulation and display of the FFT.

As for the IQ recording and playback, I'm also going to give GQRX props for ease-of-use. By clicking on "Tools -> I/Q Recorder" (or pressing ctrl + I), GQRX pops up a window that can be used to set the recording directory where IQ files will be stored, start and stop recording by pressing the "Record" button, and playing back files by selecting an IQ recording file and pressing "Play".

Recording pop-up window for GQRX. From here, you can select the directory to which it will store IQ files, or playback IQ files recorded earlier. GQRX appends the extension ".raw" to its IQ files. The files are complex 32-bit

GQRX stores IQ samples as complex 32-bit floating point samples. Such samples can be read into Gnu Radio directly using a "File Source" with output type set to "complex".

Gnu Radio flowgraph used to playback IQ samples captured with GQRX. Since GQRX records with the same complex sample type as Gnu Radio, all that is required for playback is a "File Source" block set to "complex" for the "Output Type".
Time and frequency domain displays from Gnu Radio flowgraph replaying IQ samples from a GQRX IQ capture file.

Gnu Radio

Yes, Gnu Radio itself can store IQ samples. Frankly, it's something at which it excels. You can store IQ samples as signed or unsigned 8-bit integers, signed 16-bit integers, or 32-bit floating point. You can store them as raw IQ samples (no metadata) or with metadata inline (using the "Wav File Sink"). NOTE: Gnu Radio also has the "File Meta Sink" which can also be used to store metadata as either an inline or detached file. I've not yet figured out how to use that block properly.)

Here's a short flowgraph that takes the IQ samples directly from a SDR and stores them in a file. In this case, the samples are stored as 32-bit floating point complex samples. While that may sound really complicated, remember two things:

  1. The samples are nothing more than numbers. Each number represents the measured voltage at periodic points from the original, analog waveform.
  2. The "complex" part means that each sample is represented by two numbers. They're stored in the file in sequential order as real-imaginary-real-imaginary... until the very end of the file.
Gnu Radio flowgraph showing how to save IQ samples to a file. The blue connectors mean that the samples are being processed as complex 32-bit floating point numbers.

The issue with storing the samples as 32-bit samples is that the file size will be quite large. Even a relatively small sample rate, such as 250 kSam/s, would still be a relatively large file. That sample rate for 30 seconds collecting 32-bit complex samples (8 bytes / sample) would still be a 60 MB file.

We can reduce the amount of storage required by switching to "byte" storage (8-bit samples), which will reduce the amount of required storage by 3/4 of what floating point requires. Thus, our 60 MB file would become a 15 MB file.

Gnu Radio flowgraph showing how to record IQ samples in byte (8-bit) format. While this would reduce the amount of storage required, it would also reduce the available signal-to-noise ratio (SNR) due to the reduced number of bits per sample.

Conclusion

Gnu Radio can playback just about any IQ file recorded either in Gnu Radio itself, or in any other program. It's a matter of determining:

After that, its all up to you to figure out what you want to do with those samples.

Here's a Random Fact...