Mercurial > hg > aimc
comparison trunk/matlab/bmm/carfac/Carfac.py @ 531:acd08b2ff774
(none)
author | alan.strelzoff |
---|---|
date | Sun, 11 Mar 2012 00:49:12 +0000 |
parents | c3c85000f804 |
children | 9b478420cbe2 |
comparison
equal
deleted
inserted
replaced
530:fb60ea429bb8 | 531:acd08b2ff774 |
---|---|
1 # Carfac.py - Cochlear filter model based on Dick Lyons work. This material taken from his Hearing book (to be published) | 1 # Carfac.py - Cochlear filter model based on Dick Lyons work. This material taken from his Hearing book (to be published) |
2 # Author: Al Strelzoff | 2 # Author: Al Strelzoff: strelz@mit.edu |
3 | 3 |
4 from numpy import cos, sin, tan, sinh, arctan, pi, e, real,imag,arccos,arcsin,arctan2,log10,log | 4 # The point of this file is to extract some of the formulas from the book and practice with them so as to better understand the filters. |
5 | 5 # The file has been written and tested for python 2.7 |
6 from pylab import figure, clf, plot,loglog, xlabel, ylabel, xlim, ylim, title, grid, axes, axis, show | 6 |
7 from numpy import cos, sin, pi, e, real,imag,arctan2 | |
8 | |
9 | |
10 from pylab import figure, plot,loglog, title, axis, show | |
7 | 11 |
8 fs = 22050.0 # sampling rate | 12 fs = 22050.0 # sampling rate |
9 Nyq = fs/2.0 # nyquist frequency | |
10 | 13 |
11 | 14 |
12 # given a frequency f, return the ERB | 15 # given a frequency f, return the ERB |
13 def ERB_Hz(f): | 16 def ERB_Hz(f): |
14 # Ref: Glasberg and Moore: Hearing Research, 47 (1990), 103-138 | 17 # Ref: Glasberg and Moore: Hearing Research, 47 (1990), 103-138 |
41 # before we make the filters, let's plot the position of the frequencies and the values of ERB at each. | 44 # before we make the filters, let's plot the position of the frequencies and the values of ERB at each. |
42 | 45 |
43 fscale = [] | 46 fscale = [] |
44 erbs = [] | 47 erbs = [] |
45 | 48 |
46 figure(0) | 49 figure(1) |
47 for i in range(n_ch): | 50 for i in range(n_ch): |
48 | 51 |
49 f = pole_freqs[i] # the frequencies from the list | 52 f = pole_freqs[i] # the frequencies from the list |
50 ERB = ERB_Hz(f) # the ERB value at each frequency | 53 ERB = ERB_Hz(f) # the ERB value at each frequency |
51 fscale.append(f) | 54 fscale.append(f) |
66 | 69 |
67 | 70 |
68 | 71 |
69 # This filter class includes some methods useful only in design. They will not be used in run time implementation. | 72 # This filter class includes some methods useful only in design. They will not be used in run time implementation. |
70 # From figure 14.3 in Dick Lyon's book. | 73 # From figure 14.3 in Dick Lyon's book. |
74 # When translating to C++, this class will become a struct, and all the methods will be moved outside. | |
71 | 75 |
72 | 76 |
73 #########################################################The Carfac filter class################################################################################# | 77 #########################################################The Carfac filter class################################################################################# |
74 | 78 |
75 # fixed parameters | 79 # fixed parameters |
82 def __init__(self,f): | 86 def __init__(self,f): |
83 | 87 |
84 self.frequency = f | 88 self.frequency = f |
85 | 89 |
86 theta = 2.0 * pi * f/fs | 90 theta = 2.0 * pi * f/fs |
87 | |
88 r = 1.0 - sin(theta) * min_zeta | 91 r = 1.0 - sin(theta) * min_zeta |
89 | |
90 | |
91 a = r * cos(theta) | 92 a = r * cos(theta) |
92 c = r * sin(theta) | 93 c = r * sin(theta) |
93 | 94 h = sin(theta) |
95 g = (1.0 - 2.0 * a + r ** 2)/(1.0 - 2.0 * a + h * c + r ** 2) | |
94 | 96 |
95 h = c | 97 |
96 | 98 |
97 g = 1.0/(1.0 + h * r * sin(theta) / (1.0 - 2.0 * r * cos(theta) + r ** 2)) | 99 self.gh = g*h # no need to repeat in real time |
98 | 100 |
99 # make all parameters properties of the class | 101 # make all parameters properties of the class |
100 self.a = a | 102 self.a = a |
101 self.c = c | 103 self.c = c |
102 self.r = r | 104 self.r = r |
116 | 118 |
117 | 119 |
118 # the total frequency magnitude of this filter including all the filters in front of this one | 120 # the total frequency magnitude of this filter including all the filters in front of this one |
119 self.HT = [] # this list will be filled by multiplying all the H's ahead of it together with its own (H) | 121 self.HT = [] # this list will be filled by multiplying all the H's ahead of it together with its own (H) |
120 | 122 |
121 | 123 |
122 | |
123 | |
124 | |
125 | 124 |
126 # execute one clock tick. Take in one input and output one result. Execution semantics taken from fig. 14.3 | 125 # execute one clock tick. Take in one input and output one result. Execution semantics taken from fig. 14.3 |
127 # This execution model is not tested in this file. Here for reference. See the file Exec.py for testing this execution model. This is the main run time method. | 126 # This execution model is not tested in this file. Here for reference. See the file Exec.py for testing this execution model. This is the main run time method. |
128 def input(self,X): | 127 def input(self,X): |
129 | 128 |
130 # recover the class definitions of these variables. These statements below take up zero time at execution since they are just compiler declarations. | 129 # recover the class definitions of these variables. These statements below take up zero time at execution since they are just compiler declarations. |
131 | 130 # computation below is organized as some loads, followed by 3 2x2 multiply accumulates |
131 # Note: this function is not exercised in this file and is here only for reference | |
132 | 132 |
133 a = self.a | 133 a = self.a |
134 c = self.c | 134 c = self.c |
135 h = self.h | |
136 g = self.g | 135 g = self.g |
136 gh = self.gh | |
137 z1 = self.z1 # z1 is the lower storage in fig. 14.3 | 137 z1 = self.z1 # z1 is the lower storage in fig. 14.3 |
138 z2 = self.z2 | 138 z2 = self.z2 |
139 | 139 |
140 # calculate what the next value of z1 will be, but don't overwrite current value yet. | 140 # calculate what the next value of z1 will be, but don't overwrite current value yet. |
141 next_z1 = (a * z1) - (c * z2) # Note: view this as next_z1 = a*z1 + (-c*z2) so that it is a 2 element multiply accumulate | 141 next_z1 = (a * z1) + (c * z2) # Note: it is a 2 element multiply accumulate. compute first so as not to have to do twice. |
142 # the output Y | 142 # the output Y |
143 Y = g * (X + h * next_z1) # Note: reorganize this as Y = g*X + (g*h) * next_z1 g*h is a precomputed constant so then the form is a 2 element multiply accumulate. | 143 Y = g * X + gh * next_z1 # Note: organized as a 2 element multiply accumulate. |
144 | 144 |
145 #stores | 145 #stores |
146 z2 = (a * z2) + (c * z1) #Note: this is a 2 element multiply accumulate | 146 self.z2 = X + (a * z2) - (c * z1) #Note: this is a 2 element multiply accumulate |
147 z1 = next_z1 | 147 self.z1 = next_z1 |
148 | 148 |
149 return Y # The output | 149 return Y # The output |
150 | 150 |
151 # complex frequency response of this filter at frequency w. That is, what it contributes to the cascade | 151 # complex frequency response of this filter at frequency w. That is, what it contributes to the cascade |
152 # this method is used for test only. It finds the frequency magnitude. Not included in run time filter class. | 152 # this method is used for test only. It finds the frequency magnitude. Not included in run time filter class. |
156 c = self.c | 156 c = self.c |
157 g = self.g | 157 g = self.g |
158 h = self.h | 158 h = self.h |
159 r = self.r | 159 r = self.r |
160 z = e ** (complex(0,w)) # w is in radians so this is z = exp(jw) | 160 z = e ** (complex(0,w)) # w is in radians so this is z = exp(jw) |
161 return g * (1.0 + (h*c*z)/(z**2 - 2.0*a*z + r**2 )) # from page ?? of Lyon's book. | 161 return g * (1.0 + (h*c*z)/(z**2 - 2.0*a*z + r**2 )) |
162 | 162 |
163 | |
164 # Note: to get the complex frequency response of this filter at frequency w, get Hw(w) and then compute arctan2(-imag(Hw(w))/-real(Hw(w)) + pi | |
165 | |
166 | |
167 | |
168 | 163 |
169 | 164 |
170 ######################################################End of Carfac filter class######################################################################## | 165 ######################################################End of Carfac filter class######################################################################## |
171 | 166 |
172 # instantiate the filters | 167 # instantiate the filters |
182 | 177 |
183 | 178 |
184 # sweep parameters | 179 # sweep parameters |
185 steps = 1000 | 180 steps = 1000 |
186 | 181 |
187 sum = [] # array to hold the magnitude sum | 182 figure(2) |
188 for i in range(steps): sum.append( 0.0 ) | 183 title('CarFac individual filter frequency response') |
189 | 184 # note: the scales are linear, not logrithmic as in the book |
190 figure(1) | 185 |
191 title('CarFac frequency response') | |
192 | 186 |
193 for i in range(n_ch): | 187 for i in range(n_ch): |
194 filter = Filters[i] | 188 filter = Filters[i] |
195 # plotting arrays | 189 # plotting arrays |
196 u = [] | 190 u = [] |
197 v = [] | 191 v = [] |
198 # calculate the frequency magnitude by stepping the frequency in radians | 192 # calculate the frequency magnitude by stepping the frequency in radians |
199 for j in range(steps): | 193 for j in range(steps): |
200 | 194 |
201 w = pi * float(j)/steps | 195 w = pi * float(j)/steps |
202 u.append(w) | 196 u.append(w) |
203 mag = filter.Hw(w) # freq mag at freq w | 197 mag = filter.Hw(w) # freq mag at freq w |
204 filter.H.append(mag) # save for later use | 198 filter.H.append(mag) # save for later use |
205 filter.HT.append(mag) # will be total response of cascade to this point after we do the multiplication in a step below | 199 filter.HT.append(mag) # will be total response of cascade to this point after we do the multiplication in a step below |
206 v.append(real(mag)) # y plotting axis | 200 v.append(abs(mag)) # y plotting axis |
207 sum[j]+= mag | |
208 | 201 |
209 | 202 |
210 plot(u,v) | 203 plot(u,v) |
211 | 204 |
212 | |
213 | |
214 figure(2) | |
215 title('Summed frequency magnitudes') | |
216 for i in range(steps): sum[i] = abs(sum[i])/n_ch | |
217 plot(u,sum) | |
218 | 205 |
219 # calculate the phase response of the same group of filters | 206 # calculate the phase response of the same group of filters |
220 figure(3) | 207 figure(3) |
221 title('Filter Phase') | 208 title('Carfac individual filter Phase lag') |
222 | 209 |
223 | 210 |
224 for i in range(n_ch): | 211 for i in range(n_ch): |
225 filter = Filters[i] | 212 filter = Filters[i] |
226 | 213 |
227 u = [] | 214 u = [] |
228 v = [] | 215 v = [] |
229 for j in range(steps): | 216 for j in range(steps): |
230 x = float(j)/Nyq | 217 x = pi * float(j)/steps |
231 | 218 |
232 u.append(x) | 219 u.append(x) |
233 | 220 |
234 mag = filter.H[j] | 221 mag = filter.H[j] |
235 phase = arctan2(-imag(mag),-real(mag)) + pi # this formula used to avoid wrap around | 222 phase = arctan2(-imag(mag),-real(mag)) - pi # this formula used to avoid wrap around |
236 | 223 |
237 v.append(phase) # y plotting axis | 224 v.append(phase) # y plotting axis |
238 | 225 |
239 plot(u,v) | 226 plot(u,v) |
240 | 227 axis([0.0,pi,-3.0,0.05]) |
241 | 228 |
242 | 229 |
243 # calulate and plot cascaded frequency response and summed magnitude | 230 # calulate and plot cascaded frequency response |
244 sum = [] # array to hold the magnitude sum | |
245 for i in range(steps): sum.append( 0.0 ) | |
246 | |
247 | 231 |
248 figure(4) | 232 figure(4) |
249 title('CarFac Cascaded frequency response') | 233 title('CarFac cascaded filter frequency response') |
250 | 234 |
251 | 235 |
252 for i in range(n_ch-1): | 236 for i in range(n_ch-1): |
253 | 237 |
254 filter = Filters[i] | 238 filter = Filters[i] |
256 | 240 |
257 | 241 |
258 u = [] | 242 u = [] |
259 v = [] | 243 v = [] |
260 for j in range(steps): | 244 for j in range(steps): |
261 u.append(float(j)/Nyq) | 245 w = pi * float(j)/steps |
246 u.append(w) | |
262 mag = filter.HT[j] * next.HT[j] | 247 mag = filter.HT[j] * next.HT[j] |
263 filter.HT[j] = mag | 248 next.HT[j] = mag |
264 v.append(real(mag)) | 249 v.append(abs(mag)) |
265 sum[j]+= mag | |
266 | 250 |
267 | 251 |
268 plot(u,v) | 252 plot(u,v) |
269 | 253 |
270 | 254 |
271 | 255 |
256 # calculate and plot the phase responses of the cascaded filters | |
257 | |
272 figure(5) | 258 figure(5) |
273 title('Summed cascaded frequency magnitudes') | 259 title('Carfac cascaded filter Phase lag') |
274 for i in range(steps): sum[i] = abs(sum[i])/n_ch | 260 |
275 plot(u,sum) | 261 |
276 | 262 for i in range(n_ch): |
277 # calculate and plot the phase responses of the cascaded filters | 263 |
278 | |
279 figure(6) | |
280 title('Filter cascaded Phase') | |
281 | |
282 | |
283 for i in range(n_ch): | |
284 filter = Filters[i] | 264 filter = Filters[i] |
285 | 265 |
286 | 266 |
287 u = [] | 267 u = [] |
288 v = [] | 268 v = [] # store list of phases |
269 w = [] # second copy of phases needed for phase unwrapping | |
289 for j in range(steps): | 270 for j in range(steps): |
290 x = float(j)/Nyq | 271 x = pi * float(j)/steps |
291 | 272 |
292 u.append(x) | 273 u.append(x) |
293 mag = filter.HT[j] | 274 mag = filter.HT[j] |
294 phase = arctan2(-imag(mag),-real(mag)) + pi | 275 a = imag(mag) |
295 | 276 b = real(mag) |
296 v.append(phase) # y plotting axis | 277 phase = arctan2(a,b) |
297 | 278 |
298 | 279 v.append(phase) |
299 | 280 w.append(phase) |
300 | 281 |
301 plot(u,v) | 282 # unwrap the phase |
302 | 283 |
284 | |
285 for i in range(1,len(v)): | |
286 diff = v[i]-v[i-1] | |
287 if diff > pi: | |
288 for j in range(i,len(w)): | |
289 w[j] -= 2.0 * pi | |
290 elif diff < -pi: | |
291 for j in range(i,len(w)): | |
292 w[j] += 2.0 * pi | |
293 | |
294 else: continue | |
295 | |
296 | |
297 plot(u,w) | |
298 axis([0.0,pi,-25.0,0.05]) | |
303 show() | 299 show() |
304 | 300 |