Transmitting stereo FM with GNU Radio Companion and the HackRF

Transmitting FM radio with the HackRF

About

For testing and fixing some radio equipment recently I needed a trusted source of stereo FM audio for the radio to pick up on. While there are plenty of FM stations available there's nothing more trustworthy than a sample audio file from audacity that beeps in the left then right channels independently with a small delay between each tone.

GNU Radio Companion is a useful graphical tool for building flows for radio processing however the included WBFM Transmit block only does mono - even if you pipe in your own stereo signal.

With some searching I wasn't able to find a single guide for transmitting in stereo FM so I'm here making my own footnote for the Internet.

How FM does stereo

Stereo FM involves multiplexing the signal to carry both the left and right audio channels together. This way, stereo radios can enjoy stereo and mono radios can still enjoy the left channel. This is achieved by:

Combining the left and right channels together as a sum [L+R],

Subtracting the left channel from the right channel [L-R] and multiplying it by a 38Khz sine as a subcarrier.

Then combining the above two plus a 19khz sine wave pilot signal to hint to a stereo radio that it's a stereo transmission.


The resulting combined signal consists of a 19khz sine wave, the combined L+R channels in the human-audible range for a mono experience for non-stereo radios to use and finally the L-R signal modulated onto 38Khz for stereo radios to demodulate back to L-R by combining the L+R, L-R differences to get the original two channels we want to hear. (This really isn't the best explanation...)

Getting there

Transmitting FM radio digitally takes some extra steps. For one, we need a 192Khz audio source. So my left/right channel beep test wav file being only 44.1Khz needs to be upsampled to 192Khz. A Rational Resampler block set to 640 interpolation by 147 decimation is enough to upsample the 44.1Khz to 192Khz (44100*640/147=192000).

The 38khz subcarrier sine we multiply L-R against and the 19Khz pilot sine also need to be generated at 192Khz as we flow through the steps.

We have to operate in 192khz for the minimum required accuracy to digitally broadcast our signal. To transmit such high frequencies we need a sampling frequency of at least double that. (Nyquist Sampling Theorem states that to perfectly capture and reconstruct an analog signal the sample rate needs to be double the source to avoid distortion)

We then need to modulate the the resulting sum of these three ourselves with a Frequency Mod block. The Documentation tab for this block states we take 2*pi*75000/192000 (Our sample rate) for a result of 2.454369 in my case. So I've plugged that value in then piped it into another Rational Resampler with a Interpolation of 10 and Decimation of 1 and finally into an Osmocom Sink with "hackrf=0" as the device argument and some radio frequency such as 100e6 targeting 100 MHz for our FM signal.

Overall

I'm hoping or rather at this point, expecting, that putting this info out there will be absorbed into the world's knowledge base one way or another. The resulting signal worked great in my testing but the signal strength wasn't great over a metre distance so I upped the RF Gain to 20dB from 10Db and it just barely made it clear.

I actually started testing this with a radio that ended up being mono, making this very difficult to test on! I ended up plugging in my RTL-SDRv3 to listen to my own signal on the headphones with GQRX. Tx'ing and Rx'ing to the same machine.

The flow .jpg

Here's a screenshot of the full flow for easy copying. Note that I multiply the combined streams by 0.5 to avoid clipping:

The screenshot should be here

Unique hits for this page: 4