In theory, you shouldn’t need any help to develop a software-defined radio (SDR) application. But in real life you really don’t want to roll your own code every time to read the IQ samples, perform various transformations on them, and then drive audio output. At worst, you’ll use some libraries (perhaps GNU Radio) but usually, you’ll use some higher-level construct such as GNU Radio Companion (GRC). GRC is a bit heavyweight, though, so if you’ve found it daunting before, you might check out some of the material on the LuaRadio website.

We’ve looked at LuaRadio several years ago, but it has undergone a lot of changes since then and has some excellent documentation. Like Lua itself, LuaRadio emphasizes fast scripting. It supports quite a few pieces of common hardware and nearly anything that feeds data through a soundcard.

Why not use GNU Radio? LuaRadio has an official answer. However, LuaRadio doesn’t have a GUI — at least, not yet. Maybe a Hackaday reader will fix that. It also isn’t as mature as GNU Radio, but it does have a lot of positive features such as a small footprint, easy embedding, and a simple way to add additional features.

If you have an RTL-SDR, there are a number of examples:

WBFM Broadcast Mono and Stereo Receivers

NBFM Receiver

AX.25 Packet Radio Receiver

POCSAG Receiver

RDS Receiver

AM Receiver (envelope and synchronous)

SSB Receiver

The project GitHub page shows recent updates to version 0.6.0. Just as an example, the flowgraph at the top of this post looks like this in Lua code:

local radio = require('radio') radio.CompositeBlock():connect( radio.RtlSdrSource(88.5e6 - 250e3, 1102500), -- RTL-SDR source, offset-tuned to 88.5MHz-250kHz radio.TunerBlock(-250e3, 200e3, 5), -- Translate -250 kHz, filter 200 kHz, decimate by 5 radio.FrequencyDiscriminatorBlock(1.25), -- Frequency demodulate with 1.25 modulation index radio.LowpassFilterBlock(128, 15e3), -- Low-pass filter 15 kHz for L+R audio radio.FMDeemphasisFilterBlock(75e-6), -- FM de-emphasis filter with 75 uS time constant radio.DownsamplerBlock(5), -- Downsample by 5 radio.PulseAudioSink(1) -- Play to system audio with PulseAudio ):run()

Not too hard, even without too much documentation. If you’d rather tackle GRC, we have a tutorial for that.