Introductory Tour of the GNU Radio Project

gnuradio12.png

Before you read too far, I have produced a coding guide: Blocks Coding Guide. Don't overlook it.


Introduction

I am writing this guide because GNU Radio is a great tool that can easily be overlooked. The documentation is poor and just getting started is not obvious. There is a tight niche between GNU Radio developers and programmers/users. I hope to explain GNU Radio, what it is, why its useful, and how to use it.

GNU Radio is a set of signal processing tools for the computer. It encompass hundreds of signal processing blocks and utility applications. GNU Radio can tie in with hardware such as the USRP and various ADC/DAC pci cards. Signal processing blocks are written in C++, while creating flow graphs and connecting signal blocks is done is an interpreted language called Python.

GNU Radio is...

  • An API for creating signal blocks (C++/Python)
  • A runtime environment for signal processing
  • A library of signal processing blocks
  • User scripts and applications
  • Hardware drivers (USRP/USRP2/VRT)
  • An application for creating flow graphs (GRC)

USRP

The USRP is big ADC/DAC with a USB plug, with a decent price (under $1k). This hardware device is probably GNU Radio's best friend.


Installing GNU Radio

Installing GNU Radio is probably the biggest leap for a beginner. GNU Radio can run on any platform, however, some installations are easier than others. GNU Radio must be compiled from source and all of the dependencies have to be taken care of. If your heart is set on Windows, I recommend using MSVC. If you can spare an extra PC, I recommend installing Ubuntu Linux.

Windows

GNU Radio definitely works in Windows. Build with MSVC and CMake:

Linux

Ubuntu Linux is very nice for GNU Radio because all the dependencies can be easily met. You simply have to select the correct check boxes and click install. Follow the Ubuntu Install Guide. Fedora Core also makes for a pretty easy installation, but with a little more effort. Follow the Fedora Core Install Guide. Then follow the build guide.


Using GNU Radio

Introdution

In this section, I will explain how to use the GNU Radio API in the Python programming language. If you are interested in a graphical interface like Simulink, check out GNU Radio Companion.

Python

A signal processing flow graph is implemented in Python. Python is an object oriented language, much like C++ and Java. Python code is very neat and organized and you will never have to compile it. There are no semicolons, or curly braces in Python. Rather, the code relies heavily on indentation levels and newlines. If you are familiar with programming, understanding the basics of Python should be trivial.

Helpful Python References


Learning By Example

The quickest way to understand how to use GNU Radio is to start with some basic examples. My examples are written in Python. You can copy them into a text file and run them with the Python interpreter.

A Simple Flow Graph

#bring in blocks from the main gnu radio package
from gnuradio import gr

#create the top block
tb = gr.top_block()

#create a signal source
src = gr.null_source(1) #1 indicates the data stream size

#create a signal sink
sink = gr.null_sink(1)

#connect the source to the sink
tb.connect(src, sink)

#run the flow graph
tb.run()

  • As you may have guessed, this flow graph does nothing. The null source spits out zeros, and the null sink takes a data stream and does nothing with it. Also, there is nothing in the flow graph to control the data rate, the CPU usage should climb to 100%.

The Phone-Tones Example

#bring in blocks from the main gnu radio package
from gnuradio import gr
#bring in the audio source/sink
from gnuradio import audio

#create the flow graph
tb = gr.top_block()

#create the signal sources
#parameters: samp_rate, type, output freq, amplitude, offset
src1 = gr.sig_source_f(32000, gr.GR_SIN_WAVE, 350, .5, 0)
src2 = gr.sig_source_f(32000, gr.GR_SIN_WAVE, 440, .5, 0)

#an adder to combine the sources
#the _ff indicates float input and float output
adder = gr.add_ff()

#create a signal sink
sink = audio.sink(32000)

#connect the adder
#the adder has multiple inputs...
#we must use this syntax to choose which input to use
tb.connect(src1, (adder, 0))
tb.connect(src2, (adder, 1))

#connect the adder to the sink
tb.connect(adder, sink)

#run the flow graph
tb.run()

  • Sampling Rates: The same sample rate, 32000, is used in the creation of signal sources and the audio sink. Certain blocks must agree on the rate at which they are sending or receiving data. However, the adder is not dependent on sampling rate, it simply adds whatever it receives.
  • Data Types: I will describe the data types in another section. In the meantime, take notice of the _ff in gr.add_ff and the _f in gr.sig_source_f. Most blocks indicate their input/output data types in their name. In this case, f is for float. The signal sources output a stream of floats, and the adder takes and outputs floats as well. Obviously, the audio sink must take a stream of floats. However, this is not indicated by the name.
  • Mutiple Inputs/Outputs: Certain blocks have more than one input or output. Some have two, some have infinite. The adder has one output and an infinte number of inputs. In the above example, we use only two inputs of the adder. Inputs and outputs have indexes starting at 0 and counting up. "tb.connect(src2, (adder, 1))" means that we want to connect the output of src2 to the second input of the adder. By not specifying an index, index 0 is implied. Therefore, "tb.connect((src2, 0), (adder, 1))" would have an identical effect.

It would be wise to check out the GNU Radio class list to see what kind of signal blocks are offered. The class listing only contains the blocks in the main GNU Radio package (gr). Other blocks are not documented there. Unofficial GNU Radio User Manual


Data Types

Signal blocks communicate with each other via data streams. A stream is made up of individual elements, where all elements have a particular data type. GNU Radio has very strict data type checking, meaning: Input and output data types must match exactally or an error will be thrown at runtime.

Data types can be bytes, shorts, ints, floats, and complex. In addition, a data type could be a vector of type byte, short, int, float, or complex. In many ways, a regular data stream is just a stream of length-1 vectors.

  • Byte - 1 byte of data (8 bits per element)
  • Short - 2 byte integer
  • Int - 4 byte integer
  • Float - 4 byte floating point
  • Complex - 8 bytes (actually a pair of floats)

Interleaved Shorts

Some blocks with a _s suffix say that they take interleaved shorts rather than shorts. Interleaved shorts are I&Q pairs of short intergers. There is no difference between interleaved shorts and shorts. This is up to the interpretation of the block.

Bytes and Characters

Some blocks will output character streams or unsigned character streams. There is no difference between bytes and characters. Once again, this is up to the interpretation of the block.

Signal Block Naming Conventions

Usually, the name of the signal block indicates the data type. A signal block ending in _f indicates that the block will input or output a float (depending on its function). A signal block ending in _fc, indicates that the block will input a float and output a complex. Sometimes, a block may end in a _vff, indicating that the input and output are a vector of floats. You can assume: _b for byte, _s for short, _i for int... and so on.

Keep in mind, not all signal block names follow this suit. Some blocks input or output a particular data type, but do not specify this in the name. Ex: audio.sink always takes a stream of floats but does not end in _f.

Other blocks do not expect a specific input or output type. In these cases, you must specify the size of the data type (in bytes) as one of the signal block's parameters. Ex: gr.null_sink can take a stream of any data type, but the first parameter must be the size of the data type in bytes.


Moving On...

I have only described the very basic framework of GNU Radio. There is so much more. Get a firm grasp on python, try the examples that come with GNU Radio, and experiment with other signal blocks. You can do anything...

Last edited: Tue, Jul 18 2023 - 10:32AM