Recently i published the first of a series of posts on radio listening, and while this is not technically part 2 yet, i figured something out that is quite important to my workflow of recording and then processing radio input.

i own a RTL SDR Blog V4 dongle, which is based on the RTL2832U chip. The drivers you install come with a set of binaries, including rtl_sdr, which lets you record a band of the spectrum into a raw data file. Later on, because i use SDR++, i would ideally want to open those files and process them with the UI in that program. SDR++ (or sdrpp) is also capable of recording raw bands of the spectrum into what it calls baseband files, but it cannot immediately open raw files recorded from rtl_sdr. The reason for that is that rtl_sdr outputs RAW "IQ" information, whereas sdrpp reads "IQ" information in a WAV file.

My understanding of the technical aspects of IQ data, by me, an idiot
For reasons that are too complex (lol) to get into and that are also somewhat starting to fade from my memory, an alternating electrical signal can be expressed as a complex number: it has a magnitude, a period as a function of time, and an initial shift. Complex numbers, represented in their more "vector" or "algebraic" form are essentially two numbers in a trench coat: one is real (let's call it Q), and one is "imaginary" (let's call it I). When reading from the RTL2832U chip, you get two samples, 8 bit each, for I then Q. What `rtl_sdr` does, roughly, after tuning, is reading a given number of those samples and writing them in a file, which is then *RAW IQ* (as in, just wrote the I and Q parts one after the other in a big sequence, no headers, no nothing).

What SDR++ and other tools will record and read, however, is WAV IQ, which is to say, IQ data that has been de-interleaved, processed into the appropriate number size for the program (SDR++ lets you choose, and GnuRadio uses 32-bit floating point numbers). How exactly the signal is created remains somewhat of a mystery to me at this point. My best guess is that the conversion process involves taking in the decoded complex number from IQ data and generating the corresponding input signal, and then mushing them all together. Exactly how that works? When i figure it out, i will update this part.

There is exactly one workflow where i would, ideally, not want to have to be on the UI and click a button to record on SDR++ at a precise time and again to stop it: satellite listening. Whether it be for catching SSTV from the ISS, LRPT from the Russian Weather Satellites, i do not want to get up at 7AM to do it. Or, rather, it is highly inconvenient that it's always the ideal time. i also recently discovered that, at least for SSTV from the ISS, a straight dipole is often fine.

So how about slapping a bunch of sleep commands, a bit of CLI nonsense, and get this recorded and opened in SDR++ later so i can actually record the track i want? Well, reviewing the command i use for rtl_sdr:

rtl_sdr -f 145.8e6 -s 60K -g 20 iq-145800000Hz.raw

Summing up what is going on:

  • -f 145.8e6: tune to 145.8MHz
  • -s 60K: record a bandwidth of 60K. rtl_sdr uses the term "sample rate" which is also used by SDR++; what it actually means is how many samples are taken around the tuning frequency, or how big the band you're seeing "at once" is
  • -g 20: set the gain to 20 on the dongle
  • <file name>: pretty explicit; this one includes the frequency, for a reason i will explain later

Now, i use sox to process the raw data into a WAV container:

sox -t raw -r 200k -b 8 -e unsigned-integer iq-145800000Hz.raw \
    -t wav -r 200k -b 16 iq_145800000Hz.wav

There is probably an equivalent for FFMPEG, but i haven't tested that yet.

What it does is, roughly:

  • There is an input from file iq-145800000Hz.raw:
    • The bit per sample (-b) is 8
    • There are 200k samples per slice of input
    • The type is raw data
    • The integer type is unsigned (here for 8 bits: 0-255)
  • The file created as an output, iq-145800000Hz.wav is:
    • Of type wav,
    • Has a sample rate of 200k
    • An integer type of 16 bits (you can change this part depending on what you use in SDR++)

Now, opening the resulting file iq_145800000Hz.wav with SDR++ should show you exactly the recording you plan to use.

And why the frequency in the file name? Well, see, SDR++ needs to know a center frequency to show you on the tuner, and while it does not actually matter when reading a file (the waterfall will just display the entire band and let you zoom in on it and use other tuners like radio, NOAA, METEOR, etc. on parts of it), it is good to now where you are tuned in if you have for example bookmarks and such.

So how does SDR++ determine the center frequency from the WAV file? Easy, the fucking file name.

i kid you not; i spent a solid 20 minutes digging in the code only to figure out that getFrequency searches the filename with a regex to figure out the first occurrence of [0-9]+Hz, and returns 0Hz otherwise. That is actually a smart choice considering the limitations of WAV files (i.e. you cannot use custom labels for metadata and they are generally annoying to use in general).