Software-defined radio on GNU/Linux

For a long time, people have been using DVB tuners to watch TV on their computers. However, many of these DVB tuners are actually capable of doing much more than just TV. If you're lucky, and you have a decent tuner, you can turn your little dongle into a full software-defined radio receiver.

By far the best suitable chipset on the market is the Realtek RTL2832 with the R820T2 tuner. It works with a fully free (GPLv2) kernel module and it does not require any firmware to operate. There are quite a lot of dongles around with this chipset and this tuner, but such technical details are hardly ever advertised. Finding the “right” one will take some effort.

If you're lucky enough to have an RTL2832, you'll be able to use the RTL-SDR suite (GPLv2) and a bunch of other FOSS tools to do all kinds of useful things.

First off, you'll have to unload the DVB kernel module, because it interferes with SDR capabilities:

sudo rmmod dvb_usb_rtl28xxu

If you're running a recent kernel, you may also have to load the new SDR module:

sudo modprobe rtl2832_sdr

So far, I haven't yet found a way to easily re-enable DVB capabilities without manual intervention. Reloading the module right away will make it work again, but as soon as you've used SDR functionality, the chip wants to be power-cycled before it starts decoding DVB streams again (even a computer reboot won't help, as USB remains powered then).

So until someone finds a better way, unplug and re-plug the dongle if you want to watch TV again. And of course, udev will then also reload the dvb_usb_rtl28xxu module for you.

On some distributions, you may have to set up udev rules as well. In that case, you'll receive warnings when you start using SDR functions, such as:

Using device #0 Generic RTL2832U OEM
usb_open error -3
Please fix the device permissions, e.g. by installing the udev rules file rtl-sdr.rules

In order to fix it, create the file in question and add this line to it:

SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", GROUP="adm", MODE="0666", SYMLINK+="rtl_sdr"

Then restart udev:

sudo systemctl restart udev

For DVB reception, you probably already had a bunch of DVB tools installed. If not:

sudo apt install dvb-apps vlc vlc-plugin-zvbi w-scan

Please note that DVB-T (television reception) is outside the scope of this post.

For SDR, you're going to need some other tools:

sudo apt install rtl-sdr sox

This will install the basics for your RTL-SDR device, but it's really just a collection of backend, command-line tools. In order to really get going, you're going to need some front-end software as well.

Gqrx SDR (GPLv3+) is a relatively easy front-end for the extremely powerful but also horribly complicated GNU Radio (GPLv3+). It's available in most distributions' repositories:

sudo apt install gqrx-sdr libqt4-svg

A very helpful beginner's guide for Gqrx can be found on its website.

To get started: you can change the frequency by scrolling on the digits in the top-left part of the screen. Then you set the filter to Normal and the mode to Wide FM (stereo). Once you've done that, you click the Start / Stop button and hopefully you'll be able to make out a radio broadcast.

After reading the guide, you'll probably understand most functionality and you should be able to tune in to a local FM station after disabling Hardware AGC and adjusting the antenna gain under Input controls. For me, 30dB was about right, but it will depend on many conditions. Just tune in to a known working frequency and adjust the gain until you receive a decent signal.

Whereas Gqrx can be used to receive FM radio, it cannot decode digital radio, such as DAB(+). There's a lot of fluff about DAB+ and countries shutting down FM broadcasts in the (near) future, so DAB+ reception would be useful as well.

For that, you can use the SDR-J DAB Receiver (GPLv2+). Although it's GPL licensed and written in C++, using Qt as its toolkit, the author only supplies binaries for proprietary operating systems. For GNU/Linux, it's up to us to compile the source.

Information on the build system can be found here.

You'll have to manually install some dependencies:

sudo apt install libqwt-qt5-6 librtlsdr0 librtlsdr-dev

Now just click the binary and run it. Depending on your country, you'll have to find out which multiplex contains the most interesting channels (for the Netherlands, that would be 11C and 12C) and click the START button to scan for channels.

If all goes well, you'll start seeing DAB+ channels and you can tune in by clicking on them once.

Once more, you may have to manually play with the antenna gain to get a working signal. SDR-J's gain control appears to be opposite to Gqrx's: a lower number means a stronger signal and vice versa. However, do not overmodulate the signal. Even though you may get a higher SNR by increasing your gain, it will most likely result in choppy audio and an excess of scanning. For us, gain levels between 10 and 12 work best, but YMMV. Also, disable AGC.

If DAB+ reception is poor, FM is likely the best way to use RTL-SDR for music playback. Of course, you can use Gqrx to listen to FM radio, but as you might have noticed, its sound quality isn't all that great. After all, it wasn't built with music playback in mind.

On GitHub, Joris van Rantwijk claims to have built a superior FM demodulator called SoftFM (GPLv2+).

Once you've got it, cd to its directory and run ./softfm -f 103.8M, where 103.8M is just an example, of course.

By default, SoftFM uses automatic LNA gain levels from the tuner, which doesn't always work well. Especially weak channels are often noisy that way, but this can be avoided by forcing a higher gain level than the tuner thinks it should use.

So for your convenience, we made a simple bash script that asks you for the channel you want to listen to and which LNA gain level you want to use. In case you enter an unsupported value, a list of supported values will be echoed. In case you haven't got a clue, you can also use auto.

echo "Which channel (in MHz) do you want to listen to?"
read freq
echo "Which LNA gain level (in dB) do you want to use?"
read gain
./softfm -g `echo $gain` -f `echo $freq`M

RDS has been around for a long time. It's primarily used for radio station and traffic information in FM reception. It would be nice if we could display this information on a terminal. For that, we can use redsea (ISC License) by Oona Räisänen.

Once you've got it, cd to its directory and run ./ 103.2M, where 103.2M is just an example, of course.

We did have to make one modification to the Perl script though. The default one didn't work. It would just create a file called fm which only kept on growing, while nothing would be displayed in the terminal. Our initial thoughts were that the output pipe was wrong, but it seems that rtl_fm doesn't like the -F and -M operators, and it also doesn't seem to need them for normal operation either.

In order to fix the script, change one block of code (lines 220-223) from

  = open $bitpipe, '-|', sprintf($rtl_fm_exe.' -f %.1f -M fm -l 0 '.
                   '-A std '.$ppm.' -F 9 -s %.1f | '.$rtl_redsea_exe,
                   $freq, FS) or die($!);


  = open $bitpipe, '-|', sprintf($rtl_fm_exe.' -f %.1f -l 0 '.
                   '-A std '.$ppm.' -s %.1f | '.$rtl_redsea_exe,
                   $freq, FS) or die($!);

You can also use RTL-SDR to scan for airplanes with ADS-B using Dump1090 (2-clause BSD License).

Once you've got it, cd to its directory and run ./dump1090 –interactive. You'll start seeing some raw data.

This, of course, is really only interesting for people who know a lot about air traffic. Luckily, Dump1090 is also able to project this data on a map. You can do that by running ./dump1090 –interactive –net. Then you fire up a browser and go to http://localhost:8080.

Other than tracking planes with Dump1090, you can also read messages transmitted between airplanes and ground stations over the Aircraft Communications Addressing and Reporting System (ACARS).

In Europe, ACARS messages are sent on the 131.725MHz frequency, using amplitude modulation. If you fire up Gqrx and tune to that frequency, you'll notice random beeps. In order to find out what they mean, you'll have to get your hands on a decoder. For that, you can use rtl_acars_ng (GPLv2+).

Once you have it, cd to its directory and run ./rtl_acars_ng -f 131.725M.

A lot of your neighbours probably have those quirky little weather stations with wireless outdoor sensors. This data is usually broadcast at 433MHz, useable by anyone who is able to listen in to that frequency.

You'd tune in to 433MHz with Gqrx, set the mode to AM and the filter to Narrow, and you'd be able to hear some weird beeps every time the transmitter pings its data.

Of course, those beeps are rather useless unless they're decoded into useable data. For that, you can use rtl_433 (GPLv2).

In the Netherlands, we use P2000 pagers for alarm messages used by fire fighters, ambulance personnel and policemen. Those messages are sent using Motorola's FLEX protocol. For a long time, this protocol couldn't be decoded on GNU/Linux, but recently support has been added to multimon-ng (GPLv2+). It hasn't been upstreamed yet, so in order to decode P2000, you'll have to use Craig Shelley's fork (GPLv2+).

Once you have it, open a terminal in that directory, and run the following command: rtl_fm -f 169.65M -s 22050 -l 250 | ./multimon-ng -a FLEX -a SCOPE -t raw /dev/stdin.