Have you ever wanted to build your own radio receiver? Looking for a challenging but fun software project? Coding SDR meets both objectives. It is a project within reach of radio hobbyists with a bit of skill in writing software. Here are some ideas.
Even with integrated circuits to reduce parts count, and lots of cookbooks on the subject, it’s a hard job to build a physical receiver that performs well. It gets even harder when you try to work with hundreds tiny parts. But these days, you can build a radio receiver in software – coding SDR, or Software Defined Radio. And, based on my experience, coding SDR on a do-it-yourself basis will probably get you better results than trying to build an old fashioned analog radio.
In a previous article, I described the basic components of SDR: signal capture, signal processing and human interface. In this article, the focus is on signal processing, assuming that you already have a signal capture device. Perhaps you have a good quality SDR already, like a Perseus. Or, maybe you have a lower-end signal capture device, such as the RTL-SDR. This are devices that you can use as the only hardware needed for your DIY software radio, aside from the antenna, of course.
Coding SDR can be done in many different programming languages and development environments. These include Visual Studio with C++ and C# or RAD Studio with Delphi. The main requirement is the ability to interface with DLL’s and, preferably, to be able to link either dynamically or statically with digital signal processing libraries. More on this later.
Coding SDR – Interfacing with Signal Capture
Most signal capture devices use a USB connection to your computer. Usually, the USB connection is controlled by a Windows Dynamic Link Library. Each DLL exposes functions that you can call from your software program. These functions typically include:
- Hardware control, such as activation, frequency tuning, filter switching, amplification, attenuation and firmware modification. Most important are the functions for telling the “black box” how you want it to sample the radio spectrum.
- Data provision. Once you activate the hardware, it will provide you a constant stream of samples. These are a digital representation of the signals the hardware is receiving and sampling. Data is presented as frames, that is a certain number of samples. Each time the hardware converts say 20 milliseconds of radio signals into data, and fills its buffer, it sends the data to your software. This is usually done by something known as a callback. When you connect with your hardware, you provide it with an address in memory where it can call you back whenever it has a buffer of data for you to process.
So, when coding SDR, you just need to know the commands to configure the hardware, and tell the hardware how you want to receive the data. Then you effectively say “go”. You will receive hundreds of thousands, or millions of samples per second. Your job in coding SDR is to process this data arriving from the hardware. At the end of this process, you will have audio signals coming out of your speaker.
Typically, you can find the documentation for your hardware control DLL on the vendor’s web site, from open source software that knows how to control your hardware, or from other hobbyists who have figured it out and posted the information online. For Perseus, the manufacturer provides a development kit with documentation and sample code. More generally, coding SDR has become much easier thanks to what is called the ExtIO_<name>.DLL. Nearly all of the SDR signal capture devices have an ExtIO_<name> interface library. There are a number of these for the RTL-SDR. You can read about this standard approach here. ExtIO libraries may be written by the manufacturer or by others. They contain common functions for hardware control and data provision. Once you have experience coding SDR for one receiver, it is straightforward to modify it for many other receivers using ExtIO.
When coding SDR, you need to configure your software uniquely for each signal capture device. All the rest is reuseable and does not have to be re-written for different devices.
Coding SDR – Digital Signal Processing
If you have gotten this far in coding SDR, you now face the arrival of buffers of sample data that you need to process and turn into audio. As an example, you might be facing the arrival of 40,000 samples every 20 milliseconds, or fifty buffers per second. Don’t worry, most general purpose computers can handle this easily. But there are a few tricks to make coding SDR easier.
For starters, you can throw most of this data away. This is a process called down-sampling or decimation. Properly implemented with low-pass filtering, down-sampling substantially reduces the amount of work your computer has to do. Fewer samples means less calculations. Remember, at your output you might only need a sample rate of 10,000 samples per second to produce great quality audio. This means you can down-sample by a factor of 4, and this effectively means throwing 75% of your samples away.
Most DSP operations work best (most efficiently) if done in the frequency domain. You can achieve this by doing a Fourier Transform on the buffer of data. This is called the FFT. In the frequency domain, you can perform operations on an entire buffer of samples at one time. This is quite different to the time domain, where you must perform operations over-and-over on each sample as they flow through the system. You can look up formulas for calculating the number of operations (additions, multiplications) that must be performed by your computer for equivalent frequency versus time domain processing. In the meantime, trust me on this.
You can also improve performance by using parallel processing and multiple CPU threads, and sometimes using integer math, when coding SDR.
So, why all this concentration on efficiency? Basically, it’s because there is fresh data arriving every 20 milliseconds or so. This means that you have a very short time to do all the DSP magic and output audio, before the next buffer of samples arrives to demand your attention. In general, when coding SDR, I try to make sure that my processing gets done in only 50% of the time available. This provides a margin of safety. When coding SDR, you can place timers in your software so that you know exactly how long things are taking.
There are a number of DSP code libraries that you should consider using, for at least three reasons. First, all of the heavy lifting has been done by someone else, probably better than you could do yourself. Second, coding SDR does not mean that you need to know exactly how an FFT or FIR Filter works. You just need to know how and when to use one. And you do this by calling a high level function rather than writing low level code. And third, good DSP libraries have already been optimized to take advance of various CPU features, parallel processing and multiple threads.
The two DSP libraries I would urge you to explore when coding SDR are Intel Performance Primitives and FFTW. Both are available as static and dynamic libraries. With static libraries, you can compile the code into your program directly. With dynamic libraries, the DSP routines have been pre-compiled into a group of DLL. You can call hundreds of DSP functions directly in your program. Or, you can write object wrappers for the routines. You can also compile a custom library that contains only the routines that you need for your program.
So, there is a quick summary of the basic things you need to know when you start a journey of coding SDR. If you understand intermediate math and radio theory, coding SDR is within your reach. And, as with building any radio, hearing that audio come out of your speaker for the first time is quite a thrill!