GNU Radio 3.7.3 C++ API
Exploring GNU Radio

In this page, we will go over two examples that are shipped with GNU Radio. We start off with a very simple dial tone generating example that is done in Python. The second example uses both GNU Radio Companion (GRC) and Python for different stages of the example.

In either case, we will be actually working with Python code and the modules as they exist in Python. However, in the following discussion, we will refer to each block using the full C++ namespace so that we can easily link to the block's documentation inside the manual.

The example files discussed in this page are installed with the documentation and are located in $prefix/share/doc/gnuradio-$version/.

Dial Tone Example

This example is found in the dial_tone.py file and constructs a very simple GNU Radio application that combines two sine waves to create a dial tone. It calls a function to construct the flowgraph which handles generating the signal sources.

The build_graph function sets up the sampling rate, which we will use to set the rate of the audio sink as well as the amplitude, which we use to scale the signal to control the volume of the output. We then create a top_block. The top_block is the object that holds the flowgraph, the basic data structure of a GNU Radio application. We will use the top_block to connect together and hold the signal processing blocks, which we build next.

This example uses three signal processing blocks. The first two are gr::analog::sig_source_f blocks, which generate sine waves at frequencies 350 and 440 Hz. We next create the connection to the speaker system using gr::audio::sink, which takes in the sample rate it will use to produce the output signal. The audio sink block can also take in a second parameter to set the output device name, which we use if there is a resource conflict or if using a sampling rate that the hardware won't naturally support. Common device names are "pulse" if using PulseAudio or "plughw:0,0", which is an ALSA device that can handle resampling.

We next take the three blocks we've built and connect together the flowgraph. The flowgraph connects sources to sinks through other signal processing blocks. Here, we are directly connecting two sources to a single sink. The next example uses more complex flowgraphs to farther explore these concepts. The two lines containing the "tb.connect" statements are where the connections are made. The flowgraph will look like:

sig_source_f (freq = 350) -->
                              audio.sink
sig_source_f (freq = 440) -->

We're inputting two signals into a single block, which with the audio sink allows us to output in stereo. The two signals combine to form the dual frequencies of a standard dial tone.

In the connection of the signal source to the audio sink, notice how we specify the sink as a Python tuple, (dst, X). Technically, we specify all connections as ((source block, port out), (sink block, port in)) because each block that outputs samples can have multiple output ports just as a block that receives samples can have multiple input ports. However, in the case of a gr::analog::sig_source_f, it only produces samples on a single output and so the output port of 0 is implied. Otherwise, we could write this as "tb.connect((src0, 0), (dst,0))" for complete representation of the connection.

When we are done connecting the blocks, we have a flowgraph in the object "tb". While it's connected, the sources are not generating any samples. We have to start the flowgraph running. In the main section, we return the top_block object and then call the "start" function on it. This is a non-blocking call that launches the flowgraph's main thread, which initiates the sources to start sending samples through the flowgraph. We then block until the user presses "Enter" at which point we call the flowgraph's "stop" function to shut it down.

FM Demodulator

This example can be done completely in GRC or both GRC and Python. We will generate an FM signal using GRC first and then using either a GRC program or an example in Python to demodulate and play it back.

Modulator

We first launch GRC using the terminal command "gnuradio-companion". This starts the graphical interface to create our flowgraphs. We won't explore the GRC interface here; just use it to generate a data file. With GRC launched, open the file "fm_tx.grc". Exploring this flowgraph, it generates the dial tone frequencies, adds them together, resamples the signal so we can use integer upsampling in the wideband FM transmitter block (WBFM Transmit) and output the data. While this is happening, we're also outputting the original signal to the audio system as well as viewing it in time and frequency at different stages.

The intent of this example is to generate a frequency-modulated dial tone signal and save itto a file. While saving it to a file, we only want to generate a signal large enough to make use of but it doesn't have to be too large. So we put a gr::blocks::head block that limits the number of samples into the file sink. Once this block has seen N number of samples, it will stop the flowgraph. Meanwhile, we use a gr::blocks::skiphead block to ignore the first M samples, which helps us avoid the transients and group delay of the filters in the system.

We run this either using the menu "Build->Execute" or using the gears button on the toolbar. It will run for a short amount of time and stop once the head has seen the items set in the "nitems" parameter. The result is a file "dummy.dat" that contains the complex FM samples.

Demodulator

The demodulator part is shown in both a GRC graph and as a Python script. Both the GRC graph, "fm_rx.grc", and the Python script, "fm_demod.py", do the same thing and basically reverse the stages of the modulator. It uses a gr::blocks::file_source to read the "dummy.dat" file we created previously. This is sent to the FM demodulator, which is simply implemented here using the gr::analog::quadrature_demod_cf. This demodulates the signal and converts the complex FM signal to a float signal.

We then resample it from the input signal at 200 ksps to the audio rate of 44.1 ksps. Because this resampling cannot be done using an integer decimation rate, we use an arbitrary resampler, the gr::filter::pfb_arb_resampler_fff block, that allows us to resample at any rate as well as filter the signal to the audio rate we want. The output of this block is filtered to a 15 kHz bandwidth at a sample rate of 44.1 ksps, which is ready for the gr::audio::sink block.

Both the GRC and Python files can be explored farther to better understand the operations of the blocks.