1 |
13 |
daniel.kho |
# Lowpass FIR filter design.
|
2 |
|
|
#
|
3 |
|
|
# Authors:
|
4 |
|
|
# Daniel C.K. Kho
|
5 |
|
|
# Tan Hooi Jing
|
6 |
|
|
#
|
7 |
|
|
# Copyright(c) 2012 Daniel C.K. Kho and Tan Hooi Jing. All rights reserved.
|
8 |
|
|
#
|
9 |
|
|
# This library is free software; you can redistribute it and/or
|
10 |
|
|
# modify it under the terms of the GNU Library General Public
|
11 |
|
|
# License as published by the Free Software Foundation; either
|
12 |
|
|
# version 2 of the License, or (at your option) any later version.
|
13 |
|
|
#
|
14 |
|
|
# This library is distributed in the hope that it will be useful,
|
15 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17 |
|
|
# Library General Public License for more details.
|
18 |
|
|
#
|
19 |
|
|
# You should have received a copy of the GNU Library General Public
|
20 |
|
|
# License along with this library; if not, write to the
|
21 |
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
22 |
|
|
# Boston, MA 02111-1307, USA.
|
23 |
|
|
#
|
24 |
|
|
# @dependencies:
|
25 |
|
|
# @revision history: See Mercurial log.
|
26 |
|
|
# @info:
|
27 |
|
|
#
|
28 |
|
|
# This notice and disclaimer must be retained as part of this text at all times.
|
29 |
|
|
#
|
30 |
|
|
# Note:
|
31 |
|
|
# For an equivalent Matlab model, contact Tan Hooi Jing (hooijingtan@gmail.com).
|
32 |
|
|
|
33 |
|
|
#reset();
|
34 |
|
|
from scipy import *;
|
35 |
|
|
from scipy.signal import freqz;
|
36 |
|
|
from scipy.fftpack import fftshift, fftfreq;
|
37 |
|
|
from scipy import signal;
|
38 |
|
|
|
39 |
|
|
|
40 |
|
|
# Filter specifications
|
41 |
|
|
# Here, we specify the ideal filter response
|
42 |
|
|
# Window method: Hamming
|
43 |
|
|
# N = filter order = number of unit delays
|
44 |
|
|
# M = filter length = number of taps = number of coefficients
|
45 |
|
|
# wp = passband frequency
|
46 |
|
|
# ws = sampling frequency
|
47 |
|
|
# wm = mainlobe width, transition edge
|
48 |
|
|
# wc = cutoff frequency
|
49 |
|
|
N=30; M=N+1;
|
50 |
|
|
ws=10;
|
51 |
|
|
wm=3.3/N; #ws-wp;
|
52 |
|
|
wp=0.5; #in kHz
|
53 |
|
|
wc=2*pi*(wp+wm/2)/ws; # (wp+ws)/2;
|
54 |
|
|
|
55 |
|
|
|
56 |
|
|
# Specify the ideal impulse response (filter coefficients) for cutoff frequency at w_c = 20kHz:
|
57 |
|
|
j=complex(0,1);
|
58 |
|
|
n01=r_[0:M-1:j*M];
|
59 |
|
|
|
60 |
|
|
print(n01);
|
61 |
|
|
|
62 |
|
|
# Infinite-duration impulse response. This impulse response will later be truncated using
|
63 |
|
|
# a discrete-time window function (here we use the Hamming window).
|
64 |
|
|
h_n=sin(n01*wc)/(n01*pi);
|
65 |
|
|
|
66 |
|
|
print(h_n);
|
67 |
|
|
|
68 |
|
|
# Hamming window
|
69 |
|
|
w_n=0.54-0.46*cos(2*pi*n01/N);
|
70 |
|
|
# Hann window
|
71 |
|
|
#w_n=0.5*(1+cos(2*pi*n/(M)));
|
72 |
|
|
|
73 |
|
|
print(w_n);
|
74 |
|
|
|
75 |
|
|
# Impulse response of ideal filter in time domain:
|
76 |
|
|
## FIR filter design using the window method.
|
77 |
|
|
# Usage:
|
78 |
|
|
# scipy.signal.firwin(numtaps,cutoff,width=None,window='hamming',pass_zero=True,scale=True,nyq=1.0)
|
79 |
|
|
b_n01=signal.firwin(M,wc,width=None,window='hamming',pass_zero=True,scale=True,nyq=10*wc);
|
80 |
|
|
|
81 |
|
|
# Impulse response data in time domain.
|
82 |
|
|
#
|
83 |
|
|
# Time-domain impulse response data, simulated with ModelSim and measured with Altera's on-chip
|
84 |
|
|
# SignalTap II embedded logic analyser.
|
85 |
|
|
# The DSP computations operate on up-scaled values, which is then down-scaled with the same scaling factor
|
86 |
|
|
# to produce the results below. This is for fixed-point conversion.
|
87 |
|
|
#
|
88 |
|
|
# Digital simulation and hardware measurements yield exactly the same results (in Volts):
|
89 |
|
|
b_n02=[-0.0017,
|
90 |
|
|
-0.0019,
|
91 |
|
|
-0.0024,
|
92 |
|
|
-0.0026,
|
93 |
|
|
-0.0021,
|
94 |
|
|
0,
|
95 |
|
|
0.0044,
|
96 |
|
|
0.0117,
|
97 |
|
|
0.022,
|
98 |
|
|
0.0351,
|
99 |
|
|
0.05,
|
100 |
|
|
0.0654,
|
101 |
|
|
0.0799,
|
102 |
|
|
0.0916,
|
103 |
|
|
0.0993,
|
104 |
|
|
0.102,
|
105 |
|
|
0.0993,
|
106 |
|
|
0.0916,
|
107 |
|
|
0.0799,
|
108 |
|
|
0.0654,
|
109 |
|
|
0.05,
|
110 |
|
|
0.0351,
|
111 |
|
|
0.022,
|
112 |
|
|
0.0117,
|
113 |
|
|
0.0044,
|
114 |
|
|
0,
|
115 |
|
|
-0.0021,
|
116 |
|
|
-0.0026,
|
117 |
|
|
-0.0024,
|
118 |
|
|
-0.0019,
|
119 |
|
|
-0.0017];
|
120 |
|
|
|
121 |
|
|
n=r_[0:len(b_n02)-1:j*len(b_n02)];
|
122 |
|
|
|
123 |
|
|
|
124 |
|
|
|
125 |
|
|
# Calculate the z-domain frequency responses:
|
126 |
|
|
w_n01,h_n01 = signal.freqz(b_n01,1);
|
127 |
|
|
w_n02,h_n02 = signal.freqz(b_n02,1);
|
128 |
|
|
|
129 |
|
|
|
130 |
|
|
|
131 |
|
|
print("Theoretical computation of the time-domain impulse response,\nb_n01: "); print(b_n01);
|
132 |
|
|
print("Digital simulation and hardware measurements of the time-domain impulse response,\nb_n02: "); print(b_n02);
|
133 |
|
|
|
134 |
|
|
|
135 |
|
|
## Graphing methods. ##
|
136 |
|
|
|
137 |
|
|
import pylab as plt0;
|
138 |
|
|
graph0=plt0.figure();
|
139 |
|
|
|
140 |
|
|
#html("Theoretical response curves to a unit impulse excitation:");
|
141 |
|
|
plt0.title("Theoretical response curves to a unit impulse excitation:");
|
142 |
|
|
#
|
143 |
|
|
# Filter response curves simulated from impulse response equation (Sage's firwin() method).
|
144 |
|
|
# The time-domain impulse response is used to specify the FIR filter coefficients.
|
145 |
|
|
#
|
146 |
|
|
graph0.add_subplot(2,1,1); # #rows, #columns, plot#
|
147 |
|
|
plt0.plot(n01,b_n01);
|
148 |
|
|
|
149 |
|
|
#
|
150 |
|
|
# Frequency response of the impulse excitation, or I'd just say,
|
151 |
|
|
# frequency-domain (z-domain) impulse response.
|
152 |
|
|
#
|
153 |
|
|
graph0.add_subplot(2,1,2);
|
154 |
|
|
plt0.plot(w_n01,20*log10(abs(h_n01)));
|
155 |
|
|
|
156 |
|
|
# TODO: Frequency response plot based on wc calculation:
|
157 |
|
|
|
158 |
|
|
plt0.show();
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
import pylab as plt1;
|
162 |
|
|
graph1=plt1.figure();
|
163 |
|
|
|
164 |
|
|
plt1.title("Measured vs. theoretical response curves");
|
165 |
|
|
#
|
166 |
|
|
# Filter response curves digitally simulated using ModelSim, and measured using Altera's
|
167 |
|
|
# SignalTap II embedded logic analyser. Digital simulation and hardware measurements yield
|
168 |
|
|
# exactly the same data, i.e. they have exactly the same curves, hence we only plot them once.
|
169 |
|
|
#
|
170 |
|
|
# Impulse response in time domain.
|
171 |
|
|
graph1.add_subplot(2,1,1);
|
172 |
|
|
simulated_t=plt1.plot(n01,b_n01,'r');
|
173 |
|
|
measured_t=plt1.plot(n,b_n02,'b');
|
174 |
|
|
|
175 |
|
|
# Impulse response in frequency domain (z domain).
|
176 |
|
|
graph1.add_subplot(2,1,2);
|
177 |
|
|
|
178 |
|
|
simulated_w=plt1.plot(w_n01,20*log10(abs(h_n01)),'r');
|
179 |
|
|
measured_w=plt1.plot(w_n02,20*log10(abs(h_n02)),'b');
|
180 |
|
|
|
181 |
|
|
plt1.savefig('plt1.png');
|
182 |
|
|
plt1.show();
|