Last time I looked at how GNU Radio allows a Linux system to deal with DSP hardware that can work with radio frequency (RF) and audio frequency (AF) signals. In particular, I'd been spurred by the availability of a $20 USB radio that works well as a software defined radio (SDR) over a wide range of frequencies.
Before getting the radio in the mix, though, I want to explore a little bit more of the GNU Radio software. If you missed last time, GNU Radio is a set of Python libraries aimed at digital signal processing applications. The GNU Radio Companion (GRC) is a graphical environment for building GNU Radio flowgraphs.
The last flowgraph was simple: An audio source (the sound card) sent samples to an oscilloscope display and a two-second delay. The output of the delay went to an FFT display and an audio sink so that what comes in the soundcard gets echoed back two seconds later.
Although the graphical flow masks it, the flowgraph is really generating Python code and, therefore, you can use Python expressions in the block setups. For example, the program multiplies the
samp_rate variable times two to get the right parameter for the delay block.
One thing the previous flowgraph did not do, however, is take input from the user (unless you count the built-in controls for the scope and FFT displays). Most practical radios are going to need inputs ranging from a frequency control to a volume control and maybe even more.
Look at the flowgraph below:
This is almost the same as the previous one, but I've added a band pass filter. This filter cuts off frequencies below some threshold and also cuts off frequencies above another threshold. The block has several visible parameters:
- Decimation — The filter can change the sample rate. With a 1 here, it doesn't change the sample rate at all. If this parameter were a 2, for example, the output sample rate would be 11.025kHz. You can also select interpolating filters that can step up the apparent sample rate.
- Gain — The filter can amplify the signal as it goes through. Here, I just put a 2 in to double the incoming signal. This would be a good place to add a volume control.
- Sample Rate — This shows 22.05k but really it is set to
samp_rate(the variable) in the block configuration. The display shows the computed result, not the actual setting.
- Low Cutoff Freq and High Cutoff Freq — These are the frequencies the filter cuts off. Again, although the block shows numbers, the actual setting is a variable, as you'll see shortly.
- Transition Width — The width of the filter "skirt." That is, how many Hertz does it take for the filter's response to go from full on to full off (or vice versa).
- Window Type — Real signal processing is a continuous affair. When you deal with signals as a mathematical quantity, the value changes continuously as does the output. Because all DSP relies on samples taken at some rate, there is an inherit error that occurs when you go from the time domain to the frequency domain (and back). To minimize this error, there are certain window functions used to preprocess inputs. Hamming is common and works well here. If you want to know more about window functions click here.
- Beta — Not used by this type of window (only applies to Kaiser windows).
This particular filter block is handy to use because it conceals a lot of the complexity involved with using GNU Radio's primitive filters. However, many of the filter blocks do require an array of "taps" to configure the filter. In general, you will make a Python call to set the taps. For example:
gr.firdes.low_pass creates a set of taps for a low-pass filter with parameters you specify.
That particular call does a normal finite impulse response filter (that's a DSP term) using time convolution. However, you can also make different calls to get taps for different kinds of filters (e.g., an FFT filter does a frequency domain conversion and does the convolution in the frequency domain). If you have the DSP background to care about things like that, you might look here and here for more details (or, if you are more comfortable with Python, try this link). Incidentally, click here if you want a good practical introduction to DSP that doesn't bog down on math. You can download the book or buy a hardcopy, which is well worth it.
That takes care of the filter, but what about the user interface? To the lower left of the flowgraph, you can see a notebook block and three sliders. You don't have to include a notebook, so ignore that for a moment.
The sliders are like variables but with a visual sliding component that allows you to adjust them at runtime. They appear just like the scope and FFT blocks appear. You can control their relative positions (including the scope and FFT blocks) at runtime using the Grid Position parameter. This lets you specify a row, column, row span, and column span. If you don't set this, the elements appear in some order determined by the software.
To use the slider's value, you simply set a parameter to the slider's ID or use an expression involving the ID. For example, the delay slider ties into the Delay block with the expression
samp_rate*delay. Just remember that only parameters that appear underlined can change at runtime.
If you have a complex graphical design, the screen can get crowded fast. That's the purpose of the Notebook block. It provides a series of tabs (in this case, Tuning and Monitoring). Then visual blocks like the sliders, the scope, or the FFT can use the Notebook parameter to place themselves on a particular page of a notebook (for example, the scope is on the main notebook, page 1).
There are many other user interface components. You can select check boxes, text, and a variety of displays. There's a set of WX widgets and another set for QT. The main block lets you pick if you want to use wxWidgets or Qt. In addition, you can elect to have no user interface, or create a block that you can use in other flowgraphs using the same option in the
When you run this flowgraph, you’ll see the following display:
Headphones are helpful to avoid a feedback loop.
As an exercise, how would you add a volume control to the flowgraph? Clearly a slider would work, and I mentioned earlier that the filter block has a
gain parameter that is currently set to 2. Try it!
You can download the complete flowgraph (without the volume control) here. Next time, I'll leave the audio domain behind and finally get to play with the USB radio that got this whole thing started.