Frequently Asked Question

This replaces the old FAQ. Please add questions if appropriate, but make sure you've read the guidelines at the end of this page.

Getting Started

What is GNU Radio?

Check out our page What is GNU Radio? for an introduction to what GNU Radio is and why you would want to use it.

Which operating systems are supported? Does GNU Radio run on Windows or Mac OS X?

GNU Radio works on several popular operating systems including Windows, Mac OS X, and most Linux variants. See the installation guide for OS-specific instructions.

What are the system requirements? Will GNU Radio run on my embedded device?

GNU Radio in its core is C++ with lots of user functionality relying on Python. So basically, as long as there is a feasible compiler for your platform, it can work.

Hardware requirements basically depend on what you want to do. A modern PC/laptop computer is usually up to most tasks such as receiving broadcast signals, doing audio frequency processing, and many narrowband digital signals.

When dealing with telecommunication signals, however, sample rates of over 5Msamples/s are not uncommon. The average embedded ARM platform is generally not up to that task. Even rather modern hardware often meets its limits when it comes to doing things in realtime; it all depends on your processing requirements, GNU Radio is only the platform to perform these computationally intensive tasks.

How do I install GNU Radio?

See the installation guide. Unless you have good reasons, make sure you are installing a recent version.

Where do I get help?

The main ports of call for help are the mailing list and our IRC channel #gnuradio on Freenode. Other social medias, such as Google Plus, LinkedIn or Reddit are checked less regularly, and the core devs do not read these sites for support.

When posting to the mailing list, make sure that you've read our guide on reporting errors and asking questions. This is very important, and will help you get a good answer faster.

Who runs GNU Radio?

Read our organization page.

Using GNU Radio

How do I start? What's the first thing to do after installation?

Start with our Simulation tutorial to learn your way around the GNU Radio Companion (GRC).

GRC is a graphical system that outputs a Python program. Python and GRC are the preferred methods of building GNU Radio applications. If you are unfamiliar with Python, there are many on-line resources to get you started. See the Python section on our SuggestedReading page. A good step-by-step tutorial is Dive into Python.

The Simulations tutorial will walk you through the concepts of using GRC and interacting with GNU Radio applications. From there, go on to the tutorial on Writing Python Application. This will teach you how flowgraphs are actually structured in code. It also contains a lot of information about the entire GNU Radio system that you'll be interacting with.

We are actively working on a set of tutorials to improve upon these two that will get you more familiar with the system and code.

Where can I find a list of GNU Radio blocks?

All GNU Radio blocks are listed in the GNU Radio manual under the "Modules" section. They are sorted by category. A "multiplier" block, for example, would be listed under the category "Math Operators".

In GNU Radio Companion, blocks are also listed at the side in the Block Tree. You can use the search feature of GNU Radio companion to find blocks by name by using Ctrl+f to open the search box.

What does sample rate mean in GNU Radio?

Digital signals are only meaningful in relation to the sampling rate. When we sample signals, we do so at a particular speed with, generally, uniform timing between samples. For our purposes here, we will assume uniform sampling in time to prevent any confusion.

When a real signal is sampled, we take a 'snapshot' of the signal at a particular time. We then convert the amplitude of that snapshot into a digital value, represented by some number of bits. Going the other way, we convert the digital representation at a point in a vector to an analog value at an equivalent point in time. These processes are known as analog to digital and digital to analog conversion, respectively.

GNU Radio works on digital samples of signals. We pull samples in from a hardware source like a radio receiver or an audio microphone. Likewise, GNU Radio can send signals out to hardware sinks like a radio transmitter or an audio system. These hardware devices operate on a specific sample rate.

GNU Radio, however, generally works inside a general purpose processor (GPP) on a standard OS like Linux. Neither the OS nor the GPP has any really accurate concept of time, and so sampling rate as a measure of samples/second is rather meaningless. In fact, GNU Radio doesn't really understand sampling rates at all. It simply processes samples as fast as it can. So does sampling rate matter? Yes, but we have to be careful about how we understand how things are happening. Inside of GNU Radio blocks, most algorithms work off normalized sampling rates. They only understand that they have a set of samples that need to be processed. For something like a sine wave generated from a gr::analog::sig_source_X block, the sine wave is specified at a certain frequency and a given sample rate. The actual frequency of the sine generator only knows that it has to produce a full rotation around the unit circle at "frequency/sample rate". We normalize the frequency by the sample rate.

We can always think of GNU Radio running off a normalized sampling rate of 1.0 and everything must be set in relation to that value. We offer the concept of the sample rate in many blocks like the signal sources or the filter design functions so that we can more easily specify values of frequency and bandwidth in more natural terms like samples/second and Hertz.

But don't be confused: we need to match the sampling rates at the hardware ends. Think of it as an impedance matching problem. Take for example the following flowgraph:

Rx ( fs_0) --> block0 (D_0) --> block1 (D_1) --> block2 (I_0) --> Tx ( fs_1)

We receive a signal at a real sampling rate of fs_1. We have three blocks that do three stages of sample rate changes. We down sample in block0 by D_0; down sample again in block1 by D_1; and then up sampling in block2 by I_0. The signal is then passed to the transmitter, which operates at a rate of fs_1. What we have to make sure is that at each stage the rates are properly matched so that by the time we send the signal out of block2 the sampling rate of the signal is fs_1. That is:

fs_1 = I_0 * fs_0/D_0/D_1

If we're given fs_0 and fs_1, we have to make sure our rate-changing stages in the flowgraph match the above equation properly.

My flowgraph is too slow. What can I do to make it faster? My hardware signals underflows, overflows or dropped samples.

The most common answer to that question is: It's as fast as it can run. If your signal processing application really needs that much computing, you need more computational power.

There are, however, some cases where your problems can be helped:
  1. If your signal processing relies on a bandwidth that is substantially smaller than your nyquist bandwidth (in case of complex sampling: sampling rate, in case of real sampling: 0.5 * sampling rate) use a lower sampling rate as early as possible. Often, you could also tell your hardware to produce a lower sample rate.
  2. If your signal processing could as well be done offline (instead of in realtime), write your signal to file (using file_sink) and load it from there in another flowgraph (using file_source)

When do I use a throttle block?

Ask yourself these questions:

  • Does my flowgraph have a radio device connected (UHD, RTLSDR, ...)?
  • Does my flowgraph have an audio device connected?
  • Is there a 'head' block in my flow graph?

If you've answered any of these questions with 'yes', you must not use a throttle block. Its only purpose is to slow down your flow graph, so that running it does not occupy your entire CPU (it does this by throttling the avarage number of items going through this block per second). If you have a hardware device attached, this will slow down the flow graph itself because it is running at a fixed sampling rate.

What is the file format of a gr_file_sink? How can I read files produced by a file sink?

The file sink writes the samples to a file in binary format (little-endian). The data format will only depend on the data type used in the file sink block. The following explains the data types and gives the Python Scipy command to read data from the file.

  • gr.sizeof_char: 1 byte per sample, f = scipy.fromfile(open("filename"), dtype=scipy.uint8)
  • gr.sizeof_short: 2 bytes per sample, f = scipy.fromfile(open("filename"), dtype=scipy.int16)
  • gr.sizeof_int: 4 bytes per sample, f = scipy.fromfile(open("filename"), dtype=scipy.int32)
  • gr.sizeof_float: 4 bytes per sample (IEEE 754 single-precision floats), f = scipy.fromfile(open("filename"), dtype=scipy.float32)
  • gr.sizeof_gr_complex: 4 bytes per sample as floating point real and imaginary, f = scipy.fromfile(open("filename"), dtype=scipy.complex64)

Note that the metadata file sink also stores tags, and is thus slightly different.

Signal Processing Related Questions

Which concepts do I need to know to start using GNU Radio?

Here's some concepts you will have to understand to fully unlock all the capabilities of GNU Radio:

  • Sampling rates / sampling theorem
  • (Equivalent) complex baseband
  • Digital signal processing (e.g. FIR filters)

The SuggestedReading page has many good pointers to guide you into the basics.

I'm trying to perform an FFT followed by an IFFT, why doesn't my output match my input?

There are often two issues here. One is windowing and the other is scaling. The basic flowgraph is:

source --> stream_to_vector --> forward FFT --> reverse FFT --> vector_to_stream --> sink

The windowing problem is related to the fact that we use a default window in the FFT. If you're just doing the transform to be followed by an inverse transform, you don't want to window the signal because you're changing the results of the FFT. Make sure to remove the window. You can pass an empty Python list as [] to the window parameter in the FFT options, or you can use a fft.window.rectangular(fftlen), which is just a vector of 1's. Now we're just doing the pure Fourier transform.

The scaling issue is related to how the FFT algorithm computes the results. There is an internal scaling effect of fftlen (the length of your FFT). So the output of your forward FFT is fftlen times the input. We can scale this down here if we wanted to:

... forward FFT --> multiply_const_cc(fftlen*[1.0/fftlen,]) --> reverse FFT ...

Or you can wait until you're done with the IFFT to rescale:

... forward FFT --> reverse FFT --> vector_to_stream --> multiply_const_cc(1.0/fftlen) ...

Note that in the first case, we have to pass a vector of fftlen constants with the scaling value (1.0/fftlen) because we're working with vectors at this point. Waiting until after the vector_to_stream block, we only need the single scalar that is multiplied against every value. It's still the same number of multiplies in the end.

We can solve both problems at once, by setting a rectangular window that includes the scaling to [1.0/fftlen,] * fftlen.

How do I know the exact voltage/power of my received input signal?

This is extremely difficult. Remember that the USRP (or whatever device you're using) has several analog stages (AGC, amplifiers etc.) which all affect the power before it is passed to the A/D converter. Once you're in the digital domain, all you have is numbers.

The only way to get the exact received power is by calibrating your signal manually.

Developing with GNU Radio

How can I add my own functionality to GNU Radio?

This depends. In most cases, you want to write your own module (an "out of tree" module, because it won't live inside the GNU Radio source code); have a look at the tutorial on how to do this. If you think your block is an important DSP component or something else that should be part of the GNU Radio core, have a look at the contributor guide.

How does the history work?

The history is the number of items a block needs to calculate 1 output item. For a filter, this is equal to the number of taps.
For a differential (y(n) = x(n) - x(n-1)), the history equals 2. Obviously, the smallest value for the history is 1.

When you are in the work function, the number of items in your input buffer equals the number of input items plus the history minus one.
Here is an example for an accumulator that outputs the sum of the last N items:

for (int i = 0; i < noutput_items; i++) {
    out[i] = 0;
    for (int k = 0; k < history(); k++) {
        out[i] += in[i+k];
    }
}

As you can see, noutput_items items of out[] are written, whereas noutput_items + history() - 1 items of in[] are read from.

If the history has the value N, the first N-1 items are "old" items, i.e. they were available in the previous call to work() (when work() is called the first time, they are set to zero).

How can I reconfigure a flow graph? How do I use lock(), unlock()?

A running flow graph is static, and can't be changed. There are two ways to implement reconfigurability:

  • Use lock() / unlock()
  • Create blocks that react dynamically

Using lock() and unlock(), you will actually stop the flow graph, and can then disconnect and re-connect blocks. In the following example, the flow graph will run for a second, the stop the execution (lock), disconnect the source, connect a different one, and resume. The resulting file will first have data from the vector source, then lots of zeros.

#!/usr/bin/env python
import time
from gnuradio import gr
from gnuradio import blocks

def main():
    tb = gr.top_block()
    src1 = blocks.vector_source_f(range(16), repeat=True)
    throttle = blocks.throttle(gr.sizeof_float, 1e6)
    sink = blocks.file_sink(gr.sizeof_float, 'out.dat')
    tb.connect(src1, throttle, sink)
    tb.start()
    time.sleep(1)
    print "Locking flowgraph..." 
    tb.lock()
    tb.disconnect(src1)
    src2 = blocks.null_source(gr.sizeof_float)
    tb.connect(src2, throttle)
    print "Unlocking flowgraph..." 
    tb.unlock()
    time.sleep(2)
    tb.stop()
    tb.wait()

if __name__ == "__main__":
    main()

Note that this is not meant for sample-precision timing, but rather for situations where time does not really matter.

If sample-timing is an issue, use general blocks to react to certain events. In the following example, we assume that you have written a general block which stops reading from the first sink at a given time, and then seamlessly switches over to the second input:

#!/usr/bin/env python
import time
from gnuradio import gr
from gnuradio import blocks
import my_awesome_oot_module as myoot # This is your custom module

def main():
    tb = gr.top_block()
    src1 = blocks.vector_source_f(range(16), repeat=True)
    src2 = blocks.null_source(gr.sizeof_float)
    switch = myoot.switch() # This is your custom block
    throttle = blocks.throttle(gr.sizeof_float, 1e6)
    sink = blocks.file_sink(gr.sizeof_float, 'out.dat')
    tb.connect(src1, switch, throttle, sink)
    tb.connect(src2, (switch, 1))
    tb.start()
    time.sleep(2)
    tb.stop()
    tb.wait()

if __name__ == "__main__":
    main()

There are many blocks that react to input data, or incoming tags.

Applications



Notes on adding answers to this FAQ:

  • Please stick to simple English and a neutral tone.
  • The order of sections should be in order 'advancedness', so the more beginner you are, the more likely your questions are at the front.
  • Obviously, we'd like to avoid duplication. If there's a page explaining the answer, please link to that.
  • Questions should be posed very explicitly, so people can search for a keyword or two and still find the correct question.
  • Most readers will be beginners, so try to not confuse them. Don't make unstated assumptions. Link to other resources if you think something needs to be explained.
  • There can be a section for advanced stuff, as long as the items are really relevant for some users. I'd rather have an advanced section here than another page with 'Tips and Tricks'.