Core concepts of GNU Radio¶
- Core concepts of GNU Radio
Flow graphs -- and what they're made of¶
Before we're going anywhere, first we need to understand the most basic concepts about GNU Radio: flow graphs and blocks.
Flow graphs are graphs (as in graph theory) through which data flows. Many GNU Radio applications contain nothing other than a flow graph. The nodes of such a graph are called blocks, and the data flows along the edges.
Any actual signal processing is done in the blocks. Ideally, every block does exactly one job - this way GNU Radio stays modular and flexible. Blocks are usually written in C++ (might also be Python); writing new blocks is not very difficult.
In order to illuminate this diffuse topic a little, let's start with an example (all these examples were created with the GNU Radio companion (GRC), a graphical user interface to GNU Radio).
Here, we have three blocks (the rectangles). Data flows from left to right in this example, meaning that it originates in the audio source, passes through the low pass filter and ends in a file that gets written to hard disk.
The blocks are connected at ports. The first block has no input port, it produces samples. Such a block, with only output ports, is called a source. In an analog fashion, the final block, with no outputs, is called a sink.
Sometimes, this is confusing: from the user's perspective, the audio block (which takes samples from the sound card) is just a part of the processing. When we're talking about sinks and sources, we always mean from the flow graph's perspective.
So what's happening here. The audio source block is connected to the sound card driver and outputs audio samples. These samples are connected to the low pass filter, which processes them further. Finally, the samples are passed to a block which writes them to a WAV file.
In general, we call whatever a block outputs an item. In the previous example, one item was a float value representing one sample produced by the audio driver. However, an item can be anything that can be represented digitally. The most common types of samples are real samples (as before), complex samples (the most common type in software defined radio), integer types, and vectors of these scalar types.
To understand this latter concept, consider an FFT analysis. Say we want to perform an FFT to a signal before we save it a file. Of course, we need a certain number of samples at a time to calculate an FFT; unlike the filters, it does not work sample-wise.
Here's how it works:
There's a new block in here called 'Stream to vector'. What's special about this is that its input type is different to its output type. This block takes 512 samples (i.e. 512 items) and outputs them as one vector of 512 samples (which is one item). The complex FFT outputs are then converted to their magnitude squared; which is a real data type (note how we use different colors at the ports to indicate different data types).
So remember: an item can be anything, a sample, a bunch of bits, a set of filter coefficients or whatever.
Here's what you should know by now:
- All signal processing in GNU Radio is done through flow graphs.
- A flow graph consists of blocks. A block does one signal processing operation, such as filtering, adding signals, transforming, decoding, hardware access or many others.
- Data passes between blocks in various formats, complex or real integers, floats or basically any kind of data type you can define.
- Every flow graph needs at least one sink and source.
So what does GNU Radio do?¶
First, this is what you do: you design the flow graph, choose the blocks, define the connections and tell GNU Radio about all of this. GNU Radio comes in twice, here: first, it supplies you with a multitude of blocks. Once the flow graph is defined, it executes the flow graph by calling the blocks one after another and makes sure the items are passed from one block to another.
Of course, if you're reading this, you know what sampling rates are (if you don't, go figure that out). Let's see how these relate to flow graphs. In the first example, the audio source has a fixed sampling rate of 32ksps. Because the filter doesn't change the sampling rate, the same sampling rate is used through the entire flow graph.
In the second example, the second block (stream to vector) produces one item for every 512 input items. So, the rate at which it produces items is 512 times smaller then the rate at which it consumes items (the fact that it actually produces bytes at the same rate it consumes them is irrelevant here). Such a block is called a decimator, well, because it decimates the item rate. A block which outputs more items than it receives is called an interpolator. If it produces and consumes at the same rate, it's a sync block.
Now, let's return to the second example. As mentioned, it has different sampling rates throughout the flow graph. But what's the base sampling rate?
OK, get ready: there's no such thing. As long as there is no hardware clock present which fixes the rate, sampling rate is meaningless--only relative rates (i.e. input to output rates are important. Your computer may handle the samples as fast as it wants (note that this can cause your computer to lock up by allocating 100% of CPU cycles to your signal processing).
Here's another example:
First of all, what's new here is that the sink has two inputs. Each port goes to one channel (left, right) of the sound card, which runs at a fixed sampling rate.
More on blocks (and atomicity)¶
Let's go back to the blocks. The biggest part of GNU Radio is the large number of blocks that GNU Radio provides. When you start using GNU Radio, you'll be connecting block after block. Sooner or later, you'll need a block that's not available in GNU Radio, which you can write yourself. It's not hard.
The question is, how much do you put into one block? Ideally, blocks are as atomic as possible; every block does exactly one job - this way GNU Radio stays modular and flexible.