Finite Impulse Response Filter
Finite Impulse Response Filter
Introduction
Finite Impulse Response Filter Basics
Chapter 3 of the course text deals with FIR digital filters. In ECE 2610 considerable time was
spent with this class of filter. Recall that the difference equation for filtering input x n with filter
coefficient set b n n = 0 N , is
N
yn = h k x n – k . (1)
k=0
The number of filter coefficients (taps) is N + 1 (later denoted M_FIR) and the filter order is N .
The coefficients are typically obtained using filter design functions in scipy.signal, e.g. the cus-
tom module of function in fir_design_helper.py, also utilized in the Jupyter notebook FIR Fil-
ter Design and C Headers.ipynb or MATLAB’s filter design function, fdatool().
Notice that the calculation behind the FIR filter can be viewed as a sum-of-products or as a dot
product between arrays/vectors containing the filter coefficients and the present and N past sam-
ples of the input. For the Nth filter the computational burden is N + 1 multiplications and N
additions.
The filter impulse response is obtained by setting x n = n as assuming zero initial con-
ditions (the filter state array x n x n – 1 x n – N contains zeros)
N
hn = h k n – k (2)
k=0
The filter frequency response is obtained by Fourier transforming (DTFT) the impulse response
N
– jk
h k e
j
He = (3)
k=0
From the system function it is clear why the filter order is N. The highest negative power of z is N.
Introduction 1
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Once a set of filter coefficients is available an FIR filter can make use of them. In Python/
MATLAB code this is easy since we have the lfilter()/filter() function available. In Python
suppose x is an ndarray (1D array) input signal values that we want to filter and vector h contains
the FIR coefficients. We can obtain the filtered output array y via
>> y = lfilter(h,1,x);
In this lab we move beyond the use of Python (lfilter(b,a,x))/MATLAB (filter(b,a,x)) for fil-
tering signals, and consider the real-time implementation of a sample-by-sample filter algorithm
in C/C++. The Reay text [1], Chapter 3, is devoted FIR filters and implementation in C. Under the
src folder of the ZIP package for Lab 4 you find the code module FIR_filters.c/FIR_filters.h
for implementing both floating-point and fixed-point FIR filters. Thirdly, FIR filters are also avail-
able in the ARM CMSIS-DSP library (http://www.keil.com/pack/doc/CMSIS/DSP/html/
index.html). Recall CMSIS is the ARM Cortex-M Software Interface Standard, freely available
for use with the Cortex-M family of microcontrollers. In this lab you will get a chance to check
out the last two approaches, plus write simple filtering code right inside the ISR routine.
where M_FIR is a constant corresponding to the tap count, as declared via a #define in a header file
Introduction 2
ECE 4680 DSP Laboratory 4: FIR Digital Filters
where the coefficients are listed. You will see later how this header file is obtained using a Python
function that transfers digital filter coefficients from a Jupyter notebook to a .h file.
Brute Force Filtering for a Few Taps
Implementing, say a four tap moving average filter, can be done in a less formal way. Below x
and y are float32_t values inside the FM4 ISR with x_old and state defined globally.
float32_t x_old[4] = {0, 0, 0, 0};
float32_t state[4] = {0, 0, 0, 0};
...
// Brute force 4-tap solution
x_old[0] = x;
y = 0.25f*x_old[0] + 0.25f*x_old[1] + 0.25f*x_old[2] + 0.25f*x_old[3];
x_old[3] = x_old[2];
x_old[2] = x_old[1];
x_old[1] = x_old[0];
...
Introduction 3
ECE 4680 DSP Laboratory 4: FIR Digital Filters
the filter states and h_FIR is the address to a float32_t array holding 101 filter coefficients.
The filter state array should be declared as a global. Often h_FIR will be filled using a header
file, e.g.,
#include "remez_8_14_bpf_f32.h" // a 101 tap FIR
is a 101 tap FIR bandpass filter with passband from 8 to 14 kHz generated in a Jupyter note-
book.
4. With the structure initialized, we can now filter signal samples in the ISR using
FIR_filt_float32(&FIR1,&x,&y,1);
where x is the input sample and y is the output sample. Notice again passing by address in
the event a frame of data is being filtered. The argument 1 is the frame length, which for
sample-by-sample processing is just one. By sample-by-sample I mean that each time the
ISR runs a new sample has arrived at the ADC and a new filtered sample must returned to
the DAC.
The code behind FIR_filt_float32(), inside FIR_filters.c, is:
//Process each sample of the frame with this loop
for (iframe = 0; iframe < Nframe; iframe++)
{
// Clear the accumulator/output before filtering
accum = 0;
// Place new input sample as first element in the filter state array
FIR->state[0] = x_in[iframe];
//Direct form filter each sample using a sum of products
for (iFIR = 0; iFIR < FIR->M_taps; iFIR++)
{
accum += FIR->state[iFIR]*FIR->b_coeff[iFIR];
}
x_out[iframe] = accum;
// Shift filter states to right or use circular buffer
for (iFIR = FIR->M_taps-1; iFIR > 0; iFIR--)
{
FIR->state[iFIR] = FIR->state[iFIR-1];
}
}
}
All working variables are float32_t. The outer for loop processes each sample within the frame.
The first of the inner for loops is in fact the sum-of-products represented by (1). The array FIR-
>state[] holds x n – k for k = 0 N (here M_taps is equivalent to N + 1 in (1)). The sec-
ond of the inner for loops updates the filter history by discarding the oldest input, x n – N , and
sliding all the remaining samples to the left one position. The most recent input, x n , ends up in
FIR->state[1] to make room for the new input being placed into FIR->state[0] on the next call
of the ISR. A more efficient means of keep the state array updated is using circular buffer. More
on that later.
A complete FIR filter example, fm4_FIR_intr_GUI.c, with the GUI configured can be found in
the src folder of the Lab4 Keil project. This project is configured to load a 101 tap bandpass filter.
Introduction 4
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Figure 1: ARM® CMSIS the big picture showing where CMSIS-DSP resides.
efficient C data structure-based FIR filter algorithms are available in the library: http://
www.keil.com/pack/doc/CMSIS/DSP/html/index.html. The DSP library is divided into 10 major
Introduction 5
ECE 4680 DSP Laboratory 4: FIR Digital Filters
groups of algorithms. Other parts of CMSIS are at work in the FM4, for example CMSIS-DAP
defines the Debug Access Port interface.
The documentation for the Filter Functions group com be expanded by clicking on Reference
disclosure triangle in the left navigation pane of the CMSIS-DSP Web Site as shown in Figure 3.
A good introduction to the inner workings of CMSIS-DSP can be found in Yiu [2]. Within the fil-
tering subheading you find FIR filters, and finally float32_t implementations that run on the M4
with the floating-point hardware present. The functions arm_fir_init_f32() and arm_fit_f32()
Functions of
interest here
Introduction 6
ECE 4680 DSP Laboratory 4: FIR Digital Filters
4. With the structure initialized, we can now filter signal samples in the ISR using
arm_fir_f32(&FIR1, &x, &y, 1);
where as before x is the input sample and y is the output sample. The argument 1 is the
frame length, which for sample-by-sample processing is just one.
A complete FIR filter example, fm4_FIR_intr_GUI.c, with the GUI configured can be found in the
src folder of the Lab4 Keil project. The ARM code is commented out next to the corresponding
FIR_filters.c module code. To use the ARM code simply comment out the FIR_filters.c state-
ments and uncomment the ARM code. You will be doing this in Problem 3
Introduction 7
ECE 4680 DSP Laboratory 4: FIR Digital Filters
H G%
– H G%
3DVVEDQG
/RZSDVV
*DLQG%
6WRSEDQG
–As
)UHT+]
fp fs fs e
H G%
– H G%
3DVVEDQG
*DLQG%
+LJKSDVV
6WRSEDQG
–As
)UHT+]
fs fp fs e
H G%
– H G%
3DVVEDQG
%DQGSDVV
*DLQG%
6WRSEDQG 6WRSEDQG
–As
)UHT+]
f s f p f p f s fs e
H G%
– H G%
3DVVEDQG 3DVVEDQG
*DLQG%
%DQGVWRS
Introduction 8
ECE 4680 DSP Laboratory 4: FIR Digital Filters
There are 10 filter design functions and one plotting function available in
fir_design_helper.py. Four functions for designing Kaiser window based FIR filters and four
functions for designing equiripple based FIR filters. Of the eight just described, they all take in
amplitude response requirements and return a coefficients array. Two filter functions are simply
wrappers around the scipy.signal function signal.firwin() for designing filters of a specific
order with one (lowpass) or two (bandpass) critical frequencies are given. The wrapper functions
fix the window type to the firwin default of hann (hanning). The plotting function provides an
easy means to compare the resulting frequency response of one or more designs on a single plot.
Display modes allow gain in dB, phase in radians, group delay in samples, and group delay in sec-
onds for a given sampling rate. This function, freq_resp_list(), works for both FIR and IIR
designs. Table 1 provides the interface details to the eight design functions where d_stop and
Kasier Window
Lowpass h_FIR = firwin_kaiser_lpf(f_pass, f_stop, d_stop, fs = 1.0, N_bump=0)
Equiripple Approximation
Lowpass h_FIR = fir_remez_lpf(f_pass, f_stop, d_pass, d_stop, fs = 1.0,
N_bump=5)
The optional N_bump argument allows the filter order to be bumped up or down by an integer value in order
to fine tune the design. Making changes to the stopband gain main also be helpful in fine tuning. Note also
that the Kaiser bandstop filter order is constrained to be even (an odd number of taps).
d_pass are positive dB values and the critical frequencies have the same unit as the sampling fre-
quency f_s. These functions do not create perfect results so some tuning of of the design parame-
ters may be needed, in addition to bumping the filter order up or down via N_bump.
Introduction 9
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Figure 5: Lowpass
design example;
Kaiser vs optimal
equal ripple.
Introduction 10
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Bandpass Design
Figure 6: Bandpass
design example; Kai-
ser vs optimal equal
ripple.
Introduction 11
ECE 4680 DSP Laboratory 4: FIR Digital Filters
#include <stdint.h>
#ifndef M_FIR
#define M_FIR 101
#endif
/************************************************************************/
/* FIR Filter Coefficients */
float32_t h_FIR[M_FIR] = {-0.001475936747, 0.000735580994, 0.004771062558,
0.001254178712,-0.006176846780,-0.001755945520,
0.003667323660, 0.001589634576, 0.000242520766,
0.002386316353,-0.002699251419,-0.006927087152,
0.002072374590, 0.006247819434,-0.000017122009,
0.000544273776, 0.001224920394,-0.008238424843,
-0.005846603175, 0.009688130613, 0.007237935594,
-0.003554185785, 0.000423864572,-0.002894644665,
-0.013460012489, 0.002388684318, 0.019352295029,
0.002144732872,-0.009232278407, 0.000146728997,
-0.010111394762,-0.013491956909, 0.020872121644,
0.025104278030,-0.013643042233,-0.015018451283,
-0.000068299117,-0.019644863999, 0.000002861510,
0.052822261169, 0.015289946639,-0.049012297911,
-0.016642744836,-0.000164469072,-0.032121234463,
0.059953731027, 0.133383985599,-0.078819553619,
-0.239811117665, 0.036017541207, 0.285529343096,
0.036017541207,-0.239811117665,-0.078819553619,
0.133383985599, 0.059953731027,-0.032121234463,
-0.000164469072,-0.016642744836,-0.049012297911,
0.015289946639, 0.052822261169, 0.000002861510,
-0.019644863999,-0.000068299117,-0.015018451283,
-0.013643042233, 0.025104278030, 0.020872121644,
-0.013491956909,-0.010111394762, 0.000146728997,
-0.009232278407, 0.002144732872, 0.019352295029,
Introduction 12
ECE 4680 DSP Laboratory 4: FIR Digital Filters
0.002388684318,-0.013460012489,-0.002894644665,
0.000423864572,-0.003554185785, 0.007237935594,
0.009688130613,-0.005846603175,-0.008238424843,
0.001224920394, 0.000544273776,-0.000017122009,
0.006247819434, 0.002072374590,-0.006927087152,
-0.002699251419, 0.002386316353, 0.000242520766,
0.001589634576, 0.003667323660,-0.001755945520,
-0.006176846780, 0.001254178712, 0.004771062558,
0.000735580994,-0.001475936747};
/************************************************************************/
Expectations
When completed, submit a lab report which documents code you have written and a summary of
your results. Screen shots from the scope and any other instruments and software tools should be
included as well. I expect lab demos of certain experiments to confirm that you are obtaining the
expected results and knowledge of the tools and instruments.
Problems
Measuring Filter Frequency Response Using the Network Analyzer
1. The Comm/DSP lab has test equipment that be used to measure the frequency response of
an analog filter. In particular, we can use this equipment to characterize the end-to-end
response of a digital filter that sits inside of an A/D- H z -D/A processor, such as the FM4
Pioneer Kit. The instructor will demonstrate how to properly use the Agilent 4395A vector/
spectrum analyzer for taking frequency response measurements.
Turning to the vector network analyzer consider the block diagram of Figure 2. You use the
vector network analyzer to measure the frequency response magnitude in dB as the ratio of
the analog output over the analog input (say using analyzer ports B/R). The phase difference
formed as the output phase minus the input phase, the phase response, can also be measured
by the instrument, although that is not of interest presently. The frequency range you sweep
over should be consistent with the sampling frequency. If you are sampling at 48 ksps what
should the maximum frequency of interest be?
Expectations 13
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Agilent 4395A
USB Host Line Mic HDP/
In In Line
Out
Line
3.3V 0 1
RF Out R .. A .. B
GND
P10/A3 PF7/D2
P1C/D1
FM4
Active Probe/
Active Probe/
P1B/D0
Adapter
Adapter
Reset
41802A
User JTAG & ARM
ULINK conn
Test input signal is a Adapter
swept sinusoid
USB Debug/Pwr
USB Device & serial port
Ethernet
Problems 14
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Figure 8: MA
4-tap theory vs
measured com-
parison.
c) Repeat part (b) except now set the coefficients to [0.25, -0.25, 0.25, -0.25]. Again use the
analyzer to find the frequency response. Theoretically there is a connection be the part
n jn
(b) and part (c) coefficients, namely the use of – 1 = e . Explain the connection
between the two frequency responses using the DTFT theorem corresponding to multi-
jn
plication by e .
2. Now its time to design and implement your own FIR filter using the filter design tools of
fir_design_helpe.py. Example highlighted here are
The assignment here is complete a design using a sampling rate of 48 kHz having an
Problems 15
ECE 4680 DSP Laboratory 4: FIR Digital Filters
equiripple FIR lowpass lowpass response with 1dB cutoff frequency at 5 kHz, a passband
ripple of 1dB, and stopband attenuation of 60 dB starting at 6.5 kHz. See Figure 10 for a
graphical depiction of these amplitude response requirements.
0
-1
dB
j2 f f s
fs 2
He
-60
f (Hz)
0 5k 6.5k 24k
Figure 9: Equiripple lowpass filter amplitude response design requirements.
When the times comes to get your filter running you just need to move your h-file into the
project and then include it in the main module, e.g.,
#include "remez_8_14_bpf_f32.h" // a 101 tap FIR
as in the bandpass example, and re-build the project. Make special note of the fact that the
algorithm in the ISR only passes the left channel codec signal through your FIR filter
design. The right channel goes straight through from input to output. If you should sweep
this channel by accident it will result in a lowpass response, but the cutoff frequency is fixed
at f s 2 Hz (in this case 24 kHz).
As an example, results of the optimal FIR bandpass filter of Figure 6 is captured using the
Analog Discovery and compared with theory in the Jupyter notebook in the following:
• Note a small gain adjustment of 0.5 dB is applied to correct for gain differences in the signal
chain through the FM4.
Problems 16
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Furthermore this example of a 101-tap FIR, makes it clear that a lot of real-time resources
are consumed as evidenced from the logic analyzer measurement below:
Figure 11: Logical analyzer showing filter loading of the ISR time interval.
a) Using the network analyzer obtain the analog frequency response of your filter design
and compare it with your theoretical expectations from the design functions in
fir_design_helper.py. Check the filter gain at the passband and stopband critical fre-
quencies to see how well they match the theoretical design expectations. By expectations
I mean the original amplitude response requirements.
b) Measure the time spent in the ISR when running the FIR filter of part (a) when using the
normal -O3 optimization. Recall your experiences with the digital GPIO pin in Lab 3.
How much total time is spent in the ISR, T alg + T overhead , when sampling at 48 kHz?
c) Repeat part (b) replacing the use of FIR_filt_float32(&FIR1,&x,&y,1) with the CMSIS-
DSP function arm_fir_f32(&FIR1, &x, &y, 1), and the corresponding creation and ini-
tialization code. Note the speed improvement offered by CMSIS-DSP.
d) What is the maximum sampling rate you can operate your filter at and still meet real-
time operation? Find T overhead by bypassing the filter and letting y = x when using the
CMSIS-DSP functions.
Problems 17
ECE 4680 DSP Laboratory 4: FIR Digital Filters
e) Estimate the maximum number of FIR coefficients the present algorithm can support
with f s = 48 kHz and still meet real-time. Show your work. You can assume that T alg
grows linearly with the number of coefficients, M_FIR. Again assume you are using
CMSIS-DSP.
Apply psd()
Run white to create |H(f)|dB
Line
noise code Input frequency
as filter Out response
input estimate.
f
FM4 Import
PC wave file
Capture 30 seconds
Sound into
using >= 24.4 kHz
Card Jupyter
sampling rate.
notebook
Figure 12: Waveform capture using the PC sound card and Goldwave.
same FIR filter as used in Problem 2. The software capture tool that is useful here is the
shareware program GoldWave1 (goldwave.zip on Web site). A 30 second capture at
44.1 kHz seems to work well. Since the sampling rate is only 32 ksps.
To get this setup you first need to add a function to your code so that you can digitally gen-
erate a noise source as the input to your filtering algorithm. Add the following uniform ran-
dom number generator function to the ISR code module:
// Uniformly distributed noise generator
int32_t rand_int32(void)
{
static int32_t a_start = 100001;
Problems 18
ECE 4680 DSP Laboratory 4: FIR Digital Filters
Note the code is already in place in the project you extract from the Lab 4 zip file. Now you
will drive your filter algorithm with white noise generated via the function rand_int32(). In
your filter code you will replace the read from the audio code with something like to follow-
ing:
# Replace ADC with internal noise scaled
//x = (float32_t) sample.uint16bit[LEFT];
x = (float32_t) (rand_int32()>>4);
Once a record is captured in GoldWave it can be saved as a .wav file. The .wav file can
then be loaded into a Jupyter notebook using ssd.from_wav('filename.wav'). Note, Gold-
Wave can directly display waveforms and their corresponding spectra, but higher quality
spectral analysis can be performed using the numpy function psd(). You need a version that
allows rescaling of the spectrum estimate. For this purpose use the wrapper function
Px_wav, f_wav = ssd.my_psd(x, NFFT, fs)
The spectral analysis function implements Welch’s method of averaged periodograms. Sup-
pose that the .wav file is saved as FIR_4tap_MA.wav, then a plot of the frequency response
can be created as follows:
fs,x_wav = ssd.from_wav('FIR_4tap_MA.wav')
# Choose channel 0 or 1 as appropriate
Px_wav, f_wav = ssd.my_psd(x_wav[:,0],2**10,fs/1e3)
# Normalize using a reasobable value close to f = 0, but not zero
plot(f_wav,10*log10(Px_wav/Px_wav[10]))
One condition to watch out for is overloading of the PC sound card line input. Goldwave has
level indicators to help with this however. Use the sound card line input found on the back of
the PC Workstation. The software mixer application has a separate set of mixer gain settings
just for recording. You will need to adjust the Line In volume (similar to Figure 11) and
watch the actual input levels on Goldwave.
Double-click
Problems 19
ECE 4680 DSP Laboratory 4: FIR Digital Filters
In summary, using the procedure described above, obtain a Python plot of the frequency
response magnitude in dB versus frequency of the FM4 DAC output channel. Normalize the
filter gain so that it is unity at its peak frequency response magnitude. Overlay the theoreti-
cal frequency response estimate using the original Python generated filter coefficients.
in response to the present input x and M FIR – 1 past inputs using the linear array state k ,
0 k M FIR – 1 . This array is updated by shifting all array entries to the right and placing
the new present input on the left end at index zero. The circular buffer avoids this reshuffling
by keeping a pointer to the oldest value [4]. The newest value is written over the oldest value
as each new input, x, arrives to be filtered. All values remain static in the array as the pointer
does all of the work. A graphical depiction of the linear array and the circular buffer
approach is shown Figure 13. To access past values of the input modulo index arithmetic is
Shift right
as each new x n xn – 1 x n – M FIR – 1 Linear
sample arrives Buffer
0 1 M FIR – 1
Increment the
pointer modulo Circ.
x n – 2 xn – 1 x n x n – M FIR – 1 x n – M FIR – 2
the buffer length Buffer
as each new
sample arrives Increment by one modulo
M FIR – 1 to write new input
Step backwards to pointer
values
access older values; from (ptr)
0 jump up to index MFIR-1
Figure 13: Linear array hold dynamic values versus the circular buffer holding
static values.
needed to step backwards through the array, modulo the array length. The C language has
the operator % for modulo math, but it does not work properly when a negative index occurs.
The function
// A mod function that takes negative inputs
int16_t pmod(int16_t a, int16_t b)
{
int16_t ret = a % b;
if(ret < 0)
ret += b;
return ret;
}
Problems 20
ECE 4680 DSP Laboratory 4: FIR Digital Filters
solves this problem by returning nonnegative indices. A downside of using the circular buf-
fer is that that both % and pmod are not single cycle operations. Reshuffling linear takes mul-
tiple clock cycles as well. Which requires fewer total clock cycles depends on the
architecture factors. In dedicated DSP microprocessors hardware for circular buffer pointer
control is built-in. On the Cortex-M family this is not the case [2].
Variable Delay Implementation: When implementing a pure delay filter modulo address-
ing inefficiency is not a major concern, as a pure delay filter of n d samples has all zero taps
except for a single unity tap, e.g.,
y n = x n – nd (6)
where 0 n d N FIR – 1 . Ignoring global variable initialization, the variable delay filter
takes the form
// Begin buffer processing
// Write new input over oldest buffer value
circbuf[ptr] = x;
// Calculate delay index working backwards
delay = (int16_t) FM4_GUI.P_vals[2];
y = circbuf[pmod(ptr - delay,N_buff)];
// Update ptr to write over the oldest value next time
ptr = (ptr + 1) % N_buff;
a) Fill in the rest of details in the above code snippets to implement a variable delay that is
adjustable from 0 to 10 ms when f s = 48 kHz. The GUI slider control should take inte-
ger steps. Notice that since the buffer also holds the present sample value, the length of
the buffer has to be sample longer than you might think to get the desired time delay.
b) Verify that the delay is adjustable over the expected 10 ms range using the oscilloscope.
Show your results to the lab instructor. To make the testing clear input a 50 Hz square
wave turned pulse train by setting the duty cycle to about 5%. A sample display from the
Analog Discovery is shown in Figure 14.
Input Output
Volts
Delay
Case A
Input Output
Delay
Volts
Case B
Figure 14: AD output from the fully implemented 0–10ms variable delay.
Problems 21
ECE 4680 DSP Laboratory 4: FIR Digital Filters
c) Record the ISR timing to see how efficient the time delay is, in spite of how long the cir-
cular buffer is. Nice?
d) In a later lab (likely Lab 6) you will use this variable delay along with a low frequency
sinusoidal signal generator to implement an audio special effect known as flanging1 [4].
To get a test of this under manual control (slider control), input a 1 kHz sinusoid from a
bench function generator. Using speakers of earphones listen to the time delayed output
moving the time delay slider control up and down. By changing the time in real time you
compressing and then expanding the time axis, which should make the tone you hear
waver in frequency. Demonstrate this to your lab instructor.
e) What else? Not complete at this time is an experiment with a simple two element micro-
phone array combined with the adjustable time delay to provide bean steering .
References
[1] Donald Reay, Digital Signal Processing Using the ARM Cortex-M4, Wiley, 2016
[2] Joseph Yiu, The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors, third edi-
tion, Newnes, 2014.
[3] Alan V. Oppenheim and Ronald W. Schafer, Discrete-Time Signal Processing, third edition,
Prentice Hall, New Jersey, 2010.
[4] Thad B. Welch, Cameron H.G. Wright, and Michael Morrow, Real-Time Digital Signal Pro-
cessing from MATLAB to C with the TMS320C6x DSPs, second edition, CRC Press, 2012.
Development continues!
"""
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
1. https://en.wikipedia.org/wiki/Flanging
References 22
ECE 4680 DSP Laboratory 4: FIR Digital Filters
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import numpy as np
import scipy.signal as signal
import optfir
import matplotlib.pyplot as plt
from matplotlib import pylab
w_k = signal.kaiser(N_taps,beta)
n = np.arange(N_taps)
b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k
b_k /= np.sum(b_k)
print('Kaiser Win filter taps = %d.' % N_taps)
return b_k
# frequencies:
f_pass = (f_pass2 - f_pass1)/2
f_stop = (f_stop2 - f_stop1)/2
# Continue to design equivalent LPF
wc = 2*np.pi*(f_pass + f_stop)/2/fs
delta_w = 2*np.pi*(f_stop - f_pass)/fs
# Find the filter order
M = np.ceil((d_stop - 8)/(2.285*delta_w))
# Adjust filter order up or down as needed
M += N_bump
N_taps = M + 1
# Obtain the Kaiser window
beta = signal.kaiser_beta(d_stop)
w_k = signal.kaiser(N_taps,beta)
n = np.arange(N_taps)
b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k
b_k /= np.sum(b_k)
# Transform LPF to BPF
f0 = (f_pass2 + f_pass1)/2
w0 = 2*np.pi*f0/fs
n = np.arange(len(b_k))
b_k_bp = 2*b_k*np.cos(w0*(n-M/2))
print('Kaiser Win filter taps = %d.' % N_taps)
return b_k_bp
beta = signal.kaiser_beta(d_stop)
w_k = signal.kaiser(N_taps,beta)
n = np.arange(N_taps)
b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k
b_k /= np.sum(b_k)
# Transform LPF to BPF
f0 = (f_pass2 + f_pass1)/2
w0 = 2*np.pi*f0/fs
n = np.arange(len(b_k))
b_k_bs = 2*b_k*np.cos(w0*(n-M/2))
# Transform BPF to BSF via 1 - BPF for odd N_taps
b_k_bs = -b_k_bs
b_k_bs[int(M/2)] += 1
print('Kaiser Win filter taps = %d.' % N_taps)
return b_k_bs
Development continues!
"""
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
from matplotlib import pylab
def FIR_header(fname_out,h):
"""
Write FIR Filter Header Files
def FIR_fix_header(fname_out,h):
"""
Write FIR Fixed-Point Filter Header Files
#k_mod = k % M
if (kk < N-1) and (k < M-1):
f.write('%5d,' % hq[k])
kk += 1
elif (kk == N-1) & (k < M-1):
f.write('%5d,\n' % hq[k])
if k < M:
f.write(' ')
kk = 0
else:
f.write('%5d' % hq[k])
f.write('};\n')
f.write('/
************************************************************************/\n')
f.close()
def IIR_sos_header(fname_out,b,a):
"""
Write IIR SOS Header Files
File format is compatible with CMSIS-DSP IIR
Directform II Filter Functions
def tf2sos(b,a):
"""
Cascade of second-order sections (SOS) conversion.
Convert IIR transfer function coefficients, (b,a), to a
matrix of second-order section coefficients, sos_mat. The
gain coefficients per section are also available.
SOS_mat,G_array = tf2sos(b,a)
where K is ceil(max(M,N)/2).
def shuffle_real_roots(z):
"""
Move real roots to the end of a root array so
complex conjugate root pairs can form proper
biquad sections.
"""
A method for displaying digital filter frequency response magnitude,
phase, and group delay. A plot is produced using matplotlib
theta_dif = np.diff(theta2)
f_diff = np.diff(f)
Tg = -np.diff(theta2)/np.diff(w)
# For gain almost zero set groupdelay = 0
idx = pylab.find(20*np.log10(H[:-1]) < -400)
Tg[idx] = np.zeros(len(idx))
max_Tg = np.max(Tg)
#print(max_Tg)
if mode.lower() == 'groupdelay_t':
max_Tg /= fs
plt.plot(f[:-1]*fs,Tg/fs)
plt.ylim([0,1.2*max_Tg])
else:
plt.plot(f[:-1]*fs,Tg)
plt.ylim([0,1.2*max_Tg])
if n == N_filt-1:
plt.xlabel('Frequency (Hz)')
if mode.lower() == 'groupdelay_t':
plt.ylabel('Group Delay (s)')
else:
plt.ylabel('Group Delay (samples)')
plt.title('Frequency Response - Group Delay')
else:
s1 = 'Error, mode must be "dB", "phase, '
s2 = '"groupdelay_s", or "groupdelay_t"'
print(s1 + s2)