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