Let’s continue our analysis of the feedforward filter that we were discussing a couple of
videos back. We had subjected the filter to a few different test signals, signals of particular
frequencies like 0Hz, the Nyquist, ½ Nyquist and ¼ Nyquist frequencies. The last test
signal left for us is the impulse signal. We learned from the last video that the impulse
signal as a very unique property - that it contains sinusoids of all possible frequencies,
from 0Hz all the way up to the Nyquist frequency. Now that we have a better understanding of
what an impulse signal is, let’s pass it through the filter, and get an impulse response.
Here, we have our first order feedforward filter, with the coefficients of a0 and a1
as 0.5. The first sample that enters is 1, which is
the impulse itself. So, using the difference equation, the output signal is just the direct
sample, whose value is 1, multiplied by the coefficient a0 which is 0.5 added to the delayed
sample that was previously in the register. Now, since this is the very first pass through
the filter, there was nothing that was previously in the register. In this case, a default state
of zero is passed. This value is multiplied by the coefficient a1, and hence the resulting
output sample value is 0.5. So, for the first input sample of 1, the output sample is 0.5.
Now we need to update the state of the delay register with the value that was passed. So
we set the state of the register to 1. Next, in the input series, we have 0. So calculating
the difference equation, the direct path is 0 times 0.5 and in the delayed path, the previous
state was 1, so the delayed path results in 0.5. The output is 0.5. Let’s update the
state of the register again, and this time it’s 0. Next pass, and all passes after,
we have 0. So the direct path remains the same which is 0, and in the delayed path,
the previous state was 0, and so the result is also zero. The output of the difference
equation is 0, and we update the register value to 0. After this sample, every other
sample would yield the same result of output equal to 0, since the input signal doesn’t
alter. So, for an input sequence of the impulse,
we get an impulse response which looks like this.
Since there are a finite number of non-zero values that we get in the impulse response,
in this case it’s only 2, this is regarded as a Finite Impulse response, or FIR. In general,
all filters which are purely feedforward their topology have a finite impulse response and
they are said to be stable.
We can see that the impulse is flattened and smeared out. It also looks like 2 points on
a sinc-like function. Another interesting and bizarre observation that you might make
is that two non-zero values are identical to our pair of filter coefficients a0 and
a1. This is not a coincidence. For a feedforward type filter, the non-zero values of the impulse
response are identical to the filter coefficients. The more you think about it, the more it makes
sense. The impulse input is always a single sample of 1. And this sample is solely influenced
by the coefficients a0 and a1. So, they would directly have an effect on the output samples
produced. Here’s what an impulse response would look like for coefficients 0.75 and
-0.25. The non-zero sample values of the finite impulse response would take after the values
of the coefficients.
Let’s look at some programmatic examples of this. I’ll run Python code on Jupyter
notebooks. You can get the code online in the description below.
I've got a feedforward filter function defined here and this function accepts three arguments.
x which is the input signal and a0 and a1 which are filter coefficients. The function
basically loops through the entire range of the input and calculates the output by using
this difference equation and then it returns output. All we are doing here is creating
an impulse signal, feeding that impulse signal through the feedforward filter function and
getting the impulse response out, and then plotting both the impulse and the impulse
response on two separate graphs. When a0 and a1 are 0.5 each, we see a familiar
response in the impulse signal. If you change a0 to be 0.75 and a1 to be -0.25, then we
can see that the non-zero values of the impulse response are identical to the coefficients
that we chose.
So, the impulse response is the time domain response of the filter. There isn’t much
we can infer from this graph, other than the fact that the signal has been slightly stretched
out and smeared. The real interesting part is how the filter behaves with certain frequencies.
And for this, we need a frequency domain representation of this impulse response. Fortunately, that’s
quite easy to do. Once we have a time domain response, we can convert that into a frequency
domain response by using the FFT or Fast Fourier Transforms algorithm.
So, I’m going to calculate the FFT spectrum of the impulse response. The result from the
fft operation is a bunch of complex numbers. The absolute value of the complex numbers
gives us the magnitude of the frequencies, or the amplitude of the frequency, and the
angle value gives us the phase of the different frequencies. So I can plot both the frequency
response and the phase response.
If we filter the impulse signal through the 1st order feedforward filter with the coefficients
a0 and a1 as 0.5 each, we get the following graphs.
On the left, is the frequency response graph, and this is more like it. This gives us a
lot of valuable information. But first, the magnitudes of the frequencies are plotted
on the y axis and these are in dBFS. And the normalized frequencies are plotted on the
x-axis, where 1 is the sampling frequency. We only plot till 0.5 because that’s the
Nyquist frequency, the highest representable frequency for a given sample rate. And the
reason I’m plotting the normalized frequencies here and not some specific range of frequencies
like 0- 24kHz, is the frequency response of this filter is relative to the sample rate.
Looking at the plot, clearly, what we’ve built here is a low pass filter, with a cutoff
frequency of -3db at 0.25, which is half the Nyquist frequency. On the right, is a phase
response graph. The phase shifts of each of the frequencies are represented on this graph,
where the y axis represents the actual phase shift in degrees, and the x axis is normalized
frequency as before. What we see is a straight line going from 0 degrees at 0Hz to -90deg
at the Nyquist, and this is said to be a linear phase response of the filter. As mentioned
briefly in the previous videos, the linear phase response is a unique characteristic
property of feedforward filters alone; this can’t be emulated in feedback filters or
analog filters for that matter. Phase response plots are generally hard to infer from, but
we can see a general trend here. When you phase shift the 2 signals and add them together,
you run the risk of cancelling them out. At 0Hz, there’s 0 phase shift, there doesn’t
seem to be any attenuation, and as the phase shift increases, we can see that adding the
2 paths from the filter, causes attenuation, till it finally cancels out the signal towards
the end.
We also learnt that the phase is linear only when both the coefficients are symmetric.
So, let’s try putting in different values for the coefficients a0 and a1 and see what
happens. I’ll go with 0.75 and 0.25. Well, we get a general low pass filter type, but
the attenuation is not much here, it’s only about -6dB. More importantly, the phase response
has completely changed, and this is no longer a linear phase filter, since the coefficients
are no longer symmetric about 0. I’m not even going to try and explain the shape of
the phase response curve here, since I have no intuitive understanding of it either.
Let’s try one more set of coefficients. 0.5 and -0.5. This is quite interesting. With
this set of coefficients, the filter has transformed itself into a high pass filter for a change.
Lower frequencies are attenuated, and higher frequencies are passed through. The phase
response, as expected, is linear because the coefficients are symmetric. But it goes from
a 90 deg phase shift at 0Hz, to a 0 deg phase shift at the Nyquist. You can kind of figure
out what’s happening here. With a negative sign introduced within one of the filter coefficients,
the signals from the 2 paths are being subtracted, rather than being added. Now, if 2 signals
are identical and are subtracted, they cancel each other out. Whereas, if you introduce
a phase shift in one of the signals, they don’t fully cancel each other out.
Let’s take a look at an audio plugin that I made with the feedforward filter design
that we’ve been talking about. There are only 2 controls for this plugin, you can change
the coefficients of a0 and a1 with these sliders. And I’ve also got the frequency and phase
response plots here. The way I’ve implemented these responses are pretty much the same as
how we’ve been generating them in python, with an impulse response and its FFT. So whenever
the coefficients change, I run an impulse signal through this filter, and then perform
the FFT on the output of the filter which is basically the impulse response. You can
play around with this plugin yourself, you just need to get the code from github and
build it locally. The link to the repo is in the description.
As you play around with the plugin, you can see a familiar response of a low pass filter,
when both the coefficients are either positive or both are negative. The phase response is
only going to be linear if the 2 coefficients are symmetric. When one of the coefficients
is negative, and the other positive, we get a high pass filter instead.
We can add white noise through this track, and hear the filter in action.
That’s great, we’ve basically looked at a first order FIR filter in detail. FIR filters
are generally easy to understand. But filters with only 2 taps, like we’ve seen, are not
very useful, and to get a more customized frequency response from our filter, we’ll
need several taps, sometimes hundreds. But the idea is incredibly simple. The coefficients
of each of the taps represent the impulse response of the filter. So a non-mathematical
approach of designing an FIR filter would be to first design a frequency response that
you are looking for. Then performing an inverse FFT on it. This will basically convert the
signal from the frequency domain to the time domain. The result would be an impulse response
whose sample values can be mapped as coefficients of the filter. We can go over a couple of
concrete and mathematical methods of efficiently designing FIR filters later on. But before
that, let’s take a look at the feedback topology and discover how fundamentally different
they are from the feedforward filters that we’ve been talking about.