Mercurial > hg > aimc
comparison trunk/matlab/bmm/carfac/Carfac.py @ 706:f8e90b5d85fd tip
Delete CARFAC code from this repository.
It has been moved to https://github.com/google/carfac
Please email me with your github username to get access.
I've also created a new mailing list to discuss CARFAC development:
https://groups.google.com/forum/#!forum/carfac-dev
author | ronw@google.com |
---|---|
date | Thu, 18 Jul 2013 20:56:51 +0000 |
parents | be2b68ced23d |
children |
comparison
equal
deleted
inserted
replaced
705:be2b68ced23d | 706:f8e90b5d85fd |
---|---|
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: strelz@mit.edu | |
3 | |
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 # The file has been written and tested for python 2.7 | |
6 | |
7 from numpy import cos, sin, pi, e, real,imag,arctan2,log10 | |
8 | |
9 | |
10 from pylab import figure, plot,loglog, title, axis, show | |
11 | |
12 fs = 22050.0 # sampling rate | |
13 | |
14 | |
15 # given a frequency f, return the ERB | |
16 def ERB_Hz(f): | |
17 # Ref: Glasberg and Moore: Hearing Research, 47 (1990), 103-138 | |
18 return 24.7 * (1.0 + 4.37 * f / 1000.0) | |
19 | |
20 | |
21 # ERB parameters | |
22 ERB_Q = 1000.0/(24.7*4.37) # 9.2645 | |
23 ERB_break_freq = 1000/4.37 # 228.833 | |
24 | |
25 ERB_per_step = 0.3333 | |
26 | |
27 # set up channels | |
28 | |
29 first_pole_theta = .78 * pi # We start at the top frequency. | |
30 pole_Hz = first_pole_theta * fs / (2.0*pi) # frequency of top pole | |
31 min_pole_Hz = 40.0 # bottom frequency | |
32 | |
33 # set up the pole frequencies according to the above parameters | |
34 pole_freqs = [] # empty list of pole frequencies to fill, zeroth will be the top | |
35 while pole_Hz > min_pole_Hz: | |
36 pole_Hz = pole_Hz - ERB_per_step * ERB_Hz(pole_Hz) | |
37 pole_freqs.append(pole_Hz) | |
38 | |
39 n_ch = len(pole_freqs) # n_ch is the number of channels or frequency steps | |
40 print('num channels',n_ch) | |
41 | |
42 # Now we have n_ch, the number of channels, so can make the array of filters by instantiating the filter class (see below) | |
43 | |
44 # before we make the filters, let's plot the position of the frequencies and the values of ERB at each. | |
45 | |
46 fscale = [] | |
47 erbs = [] | |
48 | |
49 figure(1) | |
50 for i in range(n_ch): | |
51 | |
52 f = pole_freqs[i] # the frequencies from the list | |
53 ERB = ERB_Hz(f) # the ERB value at each frequency | |
54 fscale.append(f) | |
55 erbs.append(ERB) | |
56 | |
57 # plot a verticle hash at each frequency: | |
58 u = [] | |
59 v = [] | |
60 for j in range(5): | |
61 u.append(f) | |
62 v.append(10.0 + float(j)) | |
63 | |
64 plot(u,v) | |
65 | |
66 loglog(fscale,erbs) | |
67 | |
68 title('ERB scale') | |
69 | |
70 | |
71 | |
72 # This filter class includes some methods useful only in design. They will not be used in run time implementation. | |
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. | |
75 | |
76 | |
77 #########################################################The Carfac filter class################################################################################# | |
78 | |
79 # fixed parameters | |
80 min_zeta = 0.12 | |
81 | |
82 class carfac(): | |
83 | |
84 | |
85 # instantiate the class (in C++, the constructor) | |
86 def __init__(self,f): | |
87 | |
88 self.frequency = f | |
89 | |
90 theta = 2.0 * pi * f/fs | |
91 r = 1.0 - sin(theta) * min_zeta | |
92 a = r * cos(theta) | |
93 c = r * sin(theta) | |
94 h = sin(theta) | |
95 g = (1.0 - 2.0 * a + r ** 2)/(1.0 - 2.0 * a + h * c + r ** 2) | |
96 | |
97 | |
98 | |
99 self.gh = g*h # no need to repeat in real time | |
100 | |
101 # make all parameters properties of the class | |
102 self.a = a | |
103 self.c = c | |
104 self.r = r | |
105 self.theta = theta | |
106 self.h = h | |
107 self.g = g | |
108 | |
109 | |
110 # the two storage elements. Referring to diagram 14.3 on p.263, z2 is the upper storage register, z1, the lower | |
111 self.z1 = 0.0 | |
112 self.z2 = 0.0 | |
113 | |
114 | |
115 # frequency response of this filter | |
116 self.H = [] | |
117 | |
118 | |
119 | |
120 # the total frequency magnitude of this filter including all the filters in front of this one | |
121 self.HT = [] # this list will be filled by multiplying all the H's ahead of it together with its own (H) | |
122 | |
123 | |
124 | |
125 # execute one clock tick. Take in one input and output one result. Execution semantics taken from fig. 14.3 | |
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. | |
127 def input(self,X): | |
128 | |
129 # recover the class definitions of these variables. These statements below take up zero time at execution since they are just compiler declarations. | |
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 | |
133 a = self.a | |
134 c = self.c | |
135 g = self.g | |
136 gh = self.gh | |
137 z1 = self.z1 # z1 is the lower storage in fig. 14.3 | |
138 z2 = self.z2 | |
139 | |
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: it is a 2 element multiply accumulate. compute first so as not to have to do twice. | |
142 # the output Y | |
143 Y = g * X + gh * next_z1 # Note: organized as a 2 element multiply accumulate. | |
144 | |
145 #stores | |
146 self.z2 = X + (a * z2) - (c * z1) #Note: this is a 2 element multiply accumulate | |
147 self.z1 = next_z1 | |
148 | |
149 return Y # The output | |
150 | |
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. | |
153 def Hw(self,w): | |
154 | |
155 a = self.a | |
156 c = self.c | |
157 g = self.g | |
158 h = self.h | |
159 r = self.r | |
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 )) | |
162 | |
163 | |
164 | |
165 ######################################################End of Carfac filter class######################################################################## | |
166 | |
167 | |
168 # instantiate the filters | |
169 | |
170 # n_ch is the number of filters as determined above | |
171 | |
172 Filters = [] # the list of all filters, the zeroth is the top frequency | |
173 for i in range(n_ch): | |
174 f = pole_freqs[i] | |
175 filter = carfac(f) # note: get the correct parameters for r and h from Dick's matlab script. Load them here from a table. | |
176 Filters.append(filter) | |
177 | |
178 | |
179 | |
180 # sweep parameters | |
181 steps = 1000 | |
182 | |
183 figure(2) | |
184 title('CarFac individual filter frequency response') | |
185 # note: the scales are linear, not logrithmic as in the book | |
186 | |
187 | |
188 for i in range(n_ch): | |
189 filter = Filters[i] | |
190 # plotting arrays | |
191 u = [] | |
192 v = [] | |
193 # calculate the frequency magnitude by stepping the frequency in radians | |
194 for j in range(steps): | |
195 | |
196 w = pi * float(j)/steps | |
197 u.append(w) | |
198 mag = filter.Hw(w) # freq mag at freq w | |
199 filter.H.append(mag) # save for later use | |
200 filter.HT.append(mag) # will be total response of cascade to this point after we do the multiplication in a step below | |
201 v.append(abs(mag)) # y plotting axis | |
202 | |
203 | |
204 plot(u,v) | |
205 | |
206 | |
207 # calculate the phase response of the same group of filters | |
208 figure(3) | |
209 title('Carfac individual filter Phase lag') | |
210 | |
211 | |
212 for i in range(n_ch): | |
213 filter = Filters[i] | |
214 | |
215 u = [] | |
216 v = [] | |
217 for j in range(steps): | |
218 x = pi * float(j)/steps | |
219 | |
220 u.append(x) | |
221 | |
222 mag = filter.H[j] | |
223 phase = arctan2(-imag(mag),-real(mag)) - pi # this formula used to avoid wrap around | |
224 | |
225 v.append(phase) # y plotting axis | |
226 | |
227 plot(u,v) | |
228 axis([0.0,pi,-3.0,0.05]) | |
229 | |
230 | |
231 # calulate and plot cascaded frequency response | |
232 | |
233 figure(4) | |
234 title('CarFac cascaded filter frequency response') | |
235 | |
236 | |
237 for i in range(n_ch-1): | |
238 | |
239 filter = Filters[i] | |
240 next = Filters[i+1] | |
241 | |
242 | |
243 u = [] | |
244 v = [] | |
245 for j in range(steps): | |
246 w = pi * float(j)/steps | |
247 u.append(w) | |
248 mag = filter.HT[j] * next.HT[j] | |
249 next.HT[j] = mag | |
250 v.append(abs(mag)) | |
251 | |
252 | |
253 plot(u,v) | |
254 | |
255 | |
256 | |
257 # calculate and plot the phase responses of the cascaded filters | |
258 | |
259 figure(5) | |
260 title('Carfac cascaded filter Phase lag') | |
261 | |
262 for i in range(n_ch): | |
263 | |
264 filter = Filters[i] | |
265 | |
266 | |
267 u = [] | |
268 v = [] # store list of phases | |
269 w = [] # second copy of phases needed for phase unwrapping | |
270 for j in range(steps): | |
271 x = pi * float(j)/steps | |
272 | |
273 u.append(x) | |
274 mag = filter.HT[j] | |
275 a = imag(mag) | |
276 b = real(mag) | |
277 phase = arctan2(a,b) | |
278 | |
279 v.append(phase) | |
280 w.append(phase) | |
281 | |
282 # unwrap the phase | |
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 # convert delay to cycles | |
297 for i in range(len(w)): | |
298 w[i] /= 2.0 * pi | |
299 | |
300 | |
301 plot(u,w) | |
302 axis([0.0,pi,-5.0,0.05]) | |
303 | |
304 # calculate group delay as cascaded lag/filter center frequency | |
305 | |
306 figure(6) | |
307 title('Carfac group delay') | |
308 | |
309 for i in range(n_ch): | |
310 | |
311 filter = Filters[i] | |
312 | |
313 | |
314 u = [] | |
315 v = [] # store list of phases | |
316 w = [] # second copy of phases needed for phase unwrapping | |
317 for j in range(1,steps): | |
318 x = pi * float(j)/steps | |
319 | |
320 u.append(x) | |
321 mag = filter.HT[j] | |
322 a = imag(mag) | |
323 b = real(mag) | |
324 phase = arctan2(a,b) | |
325 | |
326 v.append(phase) | |
327 w.append(phase) | |
328 | |
329 | |
330 for i in range(1,len(v)): | |
331 diff = v[i]-v[i-1] | |
332 if diff > pi: | |
333 for j in range(i,len(w)): | |
334 w[j] -= 2.0 * pi | |
335 elif diff < -pi: | |
336 for j in range(i,len(w)): | |
337 w[j] += 2.0 * pi | |
338 | |
339 else: continue | |
340 | |
341 # calculate the group delay from: GroupDelay(n)=-[((ph(n+1)-ph(n-1))/(w(n+1)-w(n-1))]/2pi # w in radians | |
342 # or gd[n] = - ((delta ph)/(delta w))/2pi | |
343 # delta ph = w[n+1] - w[n-1] | |
344 # delta w = pi* fs/steps # we divide up the frequency range fs into fractions of pi radians. | |
345 # gd[n] = - steps(w[n+1] - w[n-1])/fs | |
346 | |
347 A = -(float(steps))/(2 *fs) # note. could have calculated this once outside the filter loop | |
348 | |
349 # gd[n] = A *(w[n+1] - w[n-1]) | |
350 | |
351 gd = [] # in radians | |
352 gd.append(0.0) # pad to equalize size of u array, end points are then meaningless | |
353 for n in range(1,len(w)-1): | |
354 gd.append(A * (w[n+1] - w[n-1])) | |
355 | |
356 gd.append(0.0) | |
357 | |
358 plot(u,gd) | |
359 axis([0.1,pi,-0.01,0.05]) | |
360 | |
361 show() | |
362 |