Mercurial > hg > aimc
comparison trunk/matlab/bmm/carfac/Carfac.py @ 522:c3c85000f804
(none)
author | alan.strelzoff |
---|---|
date | Mon, 27 Feb 2012 21:50:20 +0000 |
parents | |
children | acd08b2ff774 |
comparison
equal
deleted
inserted
replaced
521:065a3765b3d2 | 522:c3c85000f804 |
---|---|
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 | |
3 | |
4 from numpy import cos, sin, tan, sinh, arctan, pi, e, real,imag,arccos,arcsin,arctan2,log10,log | |
5 | |
6 from pylab import figure, clf, plot,loglog, xlabel, ylabel, xlim, ylim, title, grid, axes, axis, show | |
7 | |
8 fs = 22050.0 # sampling rate | |
9 Nyq = fs/2.0 # nyquist frequency | |
10 | |
11 | |
12 # given a frequency f, return the ERB | |
13 def ERB_Hz(f): | |
14 # Ref: Glasberg and Moore: Hearing Research, 47 (1990), 103-138 | |
15 return 24.7 * (1.0 + 4.37 * f / 1000.0) | |
16 | |
17 | |
18 # ERB parameters | |
19 ERB_Q = 1000.0/(24.7*4.37) # 9.2645 | |
20 ERB_break_freq = 1000/4.37 # 228.833 | |
21 | |
22 ERB_per_step = 0.3333 | |
23 | |
24 # set up channels | |
25 | |
26 first_pole_theta = .78 * pi # We start at the top frequency. | |
27 pole_Hz = first_pole_theta * fs / (2.0*pi) # frequency of top pole | |
28 min_pole_Hz = 40.0 # bottom frequency | |
29 | |
30 # set up the pole frequencies according to the above parameters | |
31 pole_freqs = [] # empty list of pole frequencies to fill, zeroth will be the top | |
32 while pole_Hz > min_pole_Hz: | |
33 pole_Hz = pole_Hz - ERB_per_step * ERB_Hz(pole_Hz) | |
34 pole_freqs.append(pole_Hz) | |
35 | |
36 n_ch = len(pole_freqs) # n_ch is the number of channels or frequency steps | |
37 print('num channels',n_ch) | |
38 | |
39 # Now we have n_ch, the number of channels, so can make the array of filters by instantiating the filter class (see below) | |
40 | |
41 # before we make the filters, let's plot the position of the frequencies and the values of ERB at each. | |
42 | |
43 fscale = [] | |
44 erbs = [] | |
45 | |
46 figure(0) | |
47 for i in range(n_ch): | |
48 | |
49 f = pole_freqs[i] # the frequencies from the list | |
50 ERB = ERB_Hz(f) # the ERB value at each frequency | |
51 fscale.append(f) | |
52 erbs.append(ERB) | |
53 | |
54 # plot a verticle hash at each frequency: | |
55 u = [] | |
56 v = [] | |
57 for j in range(5): | |
58 u.append(f) | |
59 v.append(10.0 + float(j)) | |
60 | |
61 plot(u,v) | |
62 | |
63 loglog(fscale,erbs) | |
64 | |
65 title('ERB scale') | |
66 | |
67 | |
68 | |
69 # 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. | |
71 | |
72 | |
73 #########################################################The Carfac filter class################################################################################# | |
74 | |
75 # fixed parameters | |
76 min_zeta = 0.12 | |
77 | |
78 class carfac(): | |
79 | |
80 | |
81 # instantiate the class (in C++, the constructor) | |
82 def __init__(self,f): | |
83 | |
84 self.frequency = f | |
85 | |
86 theta = 2.0 * pi * f/fs | |
87 | |
88 r = 1.0 - sin(theta) * min_zeta | |
89 | |
90 | |
91 a = r * cos(theta) | |
92 c = r * sin(theta) | |
93 | |
94 | |
95 h = c | |
96 | |
97 g = 1.0/(1.0 + h * r * sin(theta) / (1.0 - 2.0 * r * cos(theta) + r ** 2)) | |
98 | |
99 # make all parameters properties of the class | |
100 self.a = a | |
101 self.c = c | |
102 self.r = r | |
103 self.theta = theta | |
104 self.h = h | |
105 self.g = g | |
106 | |
107 | |
108 # the two storage elements. Referring to diagram 14.3 on p.263, z2 is the upper storage register, z1, the lower | |
109 self.z1 = 0.0 | |
110 self.z2 = 0.0 | |
111 | |
112 | |
113 # frequency response of this filter | |
114 self.H = [] | |
115 | |
116 | |
117 | |
118 # 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) | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 # 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. | |
128 def input(self,X): | |
129 | |
130 # recover the class definitions of these variables. These statements below take up zero time at execution since they are just compiler declarations. | |
131 | |
132 | |
133 a = self.a | |
134 c = self.c | |
135 h = self.h | |
136 g = self.g | |
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: view this as next_z1 = a*z1 + (-c*z2) so that it is a 2 element multiply accumulate | |
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. | |
144 | |
145 #stores | |
146 z2 = (a * z2) + (c * z1) #Note: this is a 2 element multiply accumulate | |
147 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 )) # from page ?? of Lyon's book. | |
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 | |
169 | |
170 ######################################################End of Carfac filter class######################################################################## | |
171 | |
172 # instantiate the filters | |
173 | |
174 # n_ch is the number of filters as determined above | |
175 | |
176 Filters = [] # the list of all filters, the zeroth is the top frequency | |
177 for i in range(n_ch): | |
178 f = pole_freqs[i] | |
179 filter = carfac(f) # note: get the correct parameters for r and h from Dick's matlab script. Load them here from a table. | |
180 Filters.append(filter) | |
181 | |
182 | |
183 | |
184 # sweep parameters | |
185 steps = 1000 | |
186 | |
187 sum = [] # array to hold the magnitude sum | |
188 for i in range(steps): sum.append( 0.0 ) | |
189 | |
190 figure(1) | |
191 title('CarFac frequency response') | |
192 | |
193 for i in range(n_ch): | |
194 filter = Filters[i] | |
195 # plotting arrays | |
196 u = [] | |
197 v = [] | |
198 # calculate the frequency magnitude by stepping the frequency in radians | |
199 for j in range(steps): | |
200 | |
201 w = pi * float(j)/steps | |
202 u.append(w) | |
203 mag = filter.Hw(w) # freq mag at freq w | |
204 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 | |
206 v.append(real(mag)) # y plotting axis | |
207 sum[j]+= mag | |
208 | |
209 | |
210 plot(u,v) | |
211 | |
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 | |
219 # calculate the phase response of the same group of filters | |
220 figure(3) | |
221 title('Filter Phase') | |
222 | |
223 | |
224 for i in range(n_ch): | |
225 filter = Filters[i] | |
226 | |
227 u = [] | |
228 v = [] | |
229 for j in range(steps): | |
230 x = float(j)/Nyq | |
231 | |
232 u.append(x) | |
233 | |
234 mag = filter.H[j] | |
235 phase = arctan2(-imag(mag),-real(mag)) + pi # this formula used to avoid wrap around | |
236 | |
237 v.append(phase) # y plotting axis | |
238 | |
239 plot(u,v) | |
240 | |
241 | |
242 | |
243 # calulate and plot cascaded frequency response and summed magnitude | |
244 sum = [] # array to hold the magnitude sum | |
245 for i in range(steps): sum.append( 0.0 ) | |
246 | |
247 | |
248 figure(4) | |
249 title('CarFac Cascaded frequency response') | |
250 | |
251 | |
252 for i in range(n_ch-1): | |
253 | |
254 filter = Filters[i] | |
255 next = Filters[i+1] | |
256 | |
257 | |
258 u = [] | |
259 v = [] | |
260 for j in range(steps): | |
261 u.append(float(j)/Nyq) | |
262 mag = filter.HT[j] * next.HT[j] | |
263 filter.HT[j] = mag | |
264 v.append(real(mag)) | |
265 sum[j]+= mag | |
266 | |
267 | |
268 plot(u,v) | |
269 | |
270 | |
271 | |
272 figure(5) | |
273 title('Summed cascaded frequency magnitudes') | |
274 for i in range(steps): sum[i] = abs(sum[i])/n_ch | |
275 plot(u,sum) | |
276 | |
277 # calculate and plot the phase responses of the cascaded filters | |
278 | |
279 figure(6) | |
280 title('Filter cascaded Phase') | |
281 | |
282 | |
283 for i in range(n_ch): | |
284 filter = Filters[i] | |
285 | |
286 | |
287 u = [] | |
288 v = [] | |
289 for j in range(steps): | |
290 x = float(j)/Nyq | |
291 | |
292 u.append(x) | |
293 mag = filter.HT[j] | |
294 phase = arctan2(-imag(mag),-real(mag)) + pi | |
295 | |
296 v.append(phase) # y plotting axis | |
297 | |
298 | |
299 | |
300 | |
301 plot(u,v) | |
302 | |
303 show() | |
304 |