Frequency Xlating FIR filter and channeling basics in GnuRadio

In this post I'm hoping to describe the filtering process as simply as possible. The reason for this is it took me quite a lot of reading to actually understand what is happening during the filtering, mostly because most of the articles I've read were either listing what needs to be done without actually explaining how it works, or listing detailed calculations, equations and hardware implementations without explaining it in plain words. Most of these articles have also assumed the reader is an expert in the topic, effectively excluding interested enthusiasts who are still beginning to grasp the basics of DSP. So this will hopefully be helpful for the mentioned folks to tie up loose ends. Here is the list of the things I will try to cover:

  • Why does the sampling matter in the filtering process

  • Why does the sampling frequency matter when defining the cutoff frequency

  • What is the connection between the sampling frequency and the cutoff frequency

  • What is the frequency translation and the center frequency

  • How FIR filters work

  • How calculating taps for low-pass filter works

I will also present an example in GnuRadio describing how to use Frequency Xlating FIR filter with the low-pass filter taps.

What is aliasing and why sampling matters

Interestingly enough, most of us have seen the effect of aliasing one time or the other. On some video recordings or old movies you can sometimes observe the car wheels going very slowly forwards or even backwards when you know the car is speeding forwards. You can observe the trains for which you can't be sure if they are moving forwards or backwards (example). You can also observe airplane propeller camera shots looking very strangely warped (example). All of this is the aliasing effect. It happens when there is not enough captured information to correctly recreate the original movement. The same happens with the frequencies. If you capture too few samples, they will produce aliasing errors when recreating the original analog signal.

You might be wondering now, how to know or calculate the correct sampling frequency? Here is where Nyquist theorem comes to play. According to Dataq Instruments' article, Nyquist theorem says two things about the minimum sampling rate needed to avoid aliasing:

  1. Nyquist sampling rate needs to be twice as the highest sampled frequency rate

  2. The signal being digitized must be bandwidth-limited at a value equal to half the Nyquist rate

For example, if you want to filter the signal with the bandwidth of 200kHz, you have to sample at least at 400kHz.

Finite Impulse Response Filters - the theory

I have already explained how the sampling affects the density and the amount of the collected samples in one of my previous articles. Now we will take a look what happens to these samples inside the filter. The incoming signals can be represented as a function (rearranged from this article):

On the first look this might look scary, but don't let yourself be intimidated. The stated formula calculates the convolution between the signal samples and the filter taps. $t_{i}$ represents i-th tap, $s_{i}$ represents i-th sample, $f(i)$ is filtered i-th sample, $h(i)$ is filter's response (we'll take a look into this one shortly) and $N$ is number of taps (or filter length). If you want to know the filter order, it is $N-1$.

The first sum describes one iteration for one resulting point. Each time you calculate this sum of multiplications, you get one resulting point. This means the calculation takes into account some of the samples from the past. If we have $N$ taps, one element of the sum is the sample from the current time and $N-1$ samples are from the past.

The second sum defines the convolution for theoretically calculating the filter to the infinity. With the correct values this would produce the ideal low-pass filter. It is obvious (or it will soon become) that this calculation going to infinity cannot be implemented on a today's computer. We will show later in practice why this is so.

Finite Impulse Response Filters - the practice

Figure 1: FIR filter implementation diagramThe figure 1 displays the implementation blocks of a FIR filter. The samples flow on the upper stream (denoted by the blue arrow) one by one. When one sequence is completed, the rightmost sample is dropped out and everything moves one sample to the right. The leftmost slot is then filled with the next newest sample. The number of used samples is determined by the filter length.

In one iteration, each sample in the pipeline is then multiplied with the corresponding tap weight. To get the current filtered sample result, we sum up all the multiplication results. In the next time hop, we move the samples in the pipeline to the right again and the same calculation is performed again for this next point in time.

The second part of Aaron Parsons' video excellently describes the convolution procedure between the two functions in practice.

Xlating FIR filter

GnuRadio has several different FIR filter types implemented as blocks. Each type has some additional functionality implemented besides the FIR filtering functionality. Xlating FIR filter has three steps that get executed consecutively.

  1. Frequency translation. User selects one desired frequency, which gets shifted down to near zero hertz. This can be used to shift lowest passband frequency to zero hertz.

  2. FIR filtering is applied. If the low-pass filter is used, all the frequencies above the upper passband frequency can be attenuated.

  3. The signal is decimated. According to this Mathworks article, the decimation happens last because the filtering is better done with full sample rate. This way there is less chance for noise and aliasing.

The GnuRadio's fir filters receive the list of real numbers as tap weights parameter. This list then is used in filtering and defines what kind of filter is used (low-pass, high-pass, band-pass...). The user can enter the hard-coded list directly, or some of the helper methods can be used to generate the list programmatically. We will explore the low-pass helper method in the following section.

In my experience with this block, it is not enough to center at the desired center frequency, because you will loose the lower part of the bandwidth. I had to subtract half the bandwidth from the center frequency to set the lowest frequency in the bandwidth to zero and only then do the full bandwidth low-pass filtering.

Low-pass filter

We already stated the taps are in GnuRadio's FIR filters entered as an array of numbers (weights). As some filters can be very lengthy, there are a couple of available tools to calculate filter taps easily. The particular one that we are going to examine is the firdes low-pass filter. GnuRadio accepts valid Python code for the blocks' parameters. This allows for building the utility methods which can ease the block's usage. Here is an example Python code.

Figure 2: The resulting graph of the low-pass filter


from gnuradio.filter import firdes
import matplotlib.pyplot as plt

taps = firdes.low_pass_2(
    1,     # Gain - usually 1
    1,     # Sampling frequency, 1 for normalized frequency
    0.2,   # Cut-off frequency, from zero excluded to half the sampling frequency
    0.01,  # Transition frequency
    60)    # Attenuation dB

print taps

plt.ylim(-0.2, 0.5)

The result of this python script is the tuple holding all the tap weights and a graph presenting those weights in the coordinate system. If you have searched the Web for the low pass filter taps, the graph presented on figure 2 will surely be familiar to you.

The filter gain is usually set to one, as per the block manual entry.

Figure 3: Low-pass filter cut-off behaviorThe sampling frequency is usually the one coming into the block from some source. I had some strange outputs on FFT sinks when the input sampling frequency and filter sampling frequency didn't match. My practice is to set the value of Xlating FIR Filter's sampling frequency equal to input sampling frequency and then use the normalized frequencies in the low-pass filter. This means this value will be 1 for the 100% of filter's sampling frequency.

Cut-off frequency determines after which part the filter will start cutting. If the Xlating FIR Filter sampling frequency is set to 1000kHz, the cut-off frequency of 0.2 will be from -200kHz to 200 kHz from the center of the signal (the real center, not the one after subtracting the half bandwidth).

The transition frequency, although at first not appearing important, defines the number of taps that will be used. The shorter the transition frequency, the more precision you need, the more taps you need. As we discussed earlier, the ideal low-pass filter looks like a quadratic function, which means it cuts immediately. But following this rule you would need an infinite amount of taps to produce such cut. This is also why it is worth to consider the requirement of shorter transition frequency against more required computational power and memory.

The attenuation defines how much the signal will be attenuated after the cut-off frequency. I keep this one at 60dB.

There are also the optional parameters for windowing. The windowing gives the more detailed control over the convolution, but is out of the scope of this document (read more here).

GnuRadio experiment findings

I have been playing with a simple GnuRadio application to learn about filtering, which I will present here. I have set up an Xlating FIR filter with the low-pass taps. The taps can be changed while the program is running. This allowed me to use the WX sliders to control the firdes values. This way you can observe the parameter changes live and learn what changing each one actually does to your filter. Also, I'd suggest changing the sampling frequency to see how the ratio is being changed on different sampling frequencies.

I haven't observed the expected visual output when changing the attenuation, I'll need to follow up on this one.

Project on GitHub: GnuRadioFiltering


I started this experiment being sure that filtering has to happen solely in the frequency domain and that I'll need to deal with the Fourier transformation sooner or later. As you probably know, in the frequency domain you can easily extract each separate frequency and easily cut it out, calculating the inverse Fourier transformation afterwards to get the filtered signal. During my research I found out that the actual FFT implementations exist alongside the FIR implementations. This kept me exploring in the wrong direction for quite some time. When I realized that the filtering is done using the convolution in the time domain, the pieces of the puzzle started fitting one another. 

GnuRadio, low-pass filter, filtering