comparison toolboxes/MIRtoolbox1.3.2/AuditoryToolbox/SeneffEarSetup.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e9a9cd732c1e
1 function [SeneffPreemphasis, SeneffFilterBank, SeneffForward, SeneffBackward] ...
2 = SeneffEarSetup(fs)
3
4 % This m-function is based on data from the following paper:
5 % Benjamin D. Bryant and John D. Gowdy, "Simulation of Stages
6 % I and II of Seneff's Auditory Model (SAM) Using Matlab", and
7 % published in the Proceedings of the 1993 Matlab User's Group
8 % Conference.
9 % Thanks to Benjamin Bryant for supplying us with his filter
10 % coefficients and the initial organization of this implementation.
11
12 % (c) 1998 Interval Research Corporation
13
14 % Set the following variable to a non-zero value to see a summary
15 % of the filter bank's behaviour.
16 plotTests = 0;
17
18 % The following values were taken from Figure 2 of Bryant's paper.
19 PreemphasisRTheta = [0.86 3.1148863;0.99 0; 0.5 0; 0.95 3.14159];
20
21 % The following values were taken from Table 1 of Bryant's paper.
22 % They represent the cascade zeros (R-z and Theta-z), and the
23 % second order poles (radius and theta) and zeros (radius and theta/2).
24 %
25 % R-z Theta-z Radius Theta R-z2
26 FilterBankRTheta = [
27 0 3.14159 0.740055 2.633909 0.8
28 0.86 2.997077 0.753637 2.178169 0.8
29 0.86 2.879267 0.775569 1.856744 0.8
30 0.86 2.761458 0.798336 1.617919 0.8
31 0.86 2.643648 0.819169 1.433496 0.8
32 0.86 2.525839 0.837158 1.286795 0.8
33 0.8 2.964876 0.852598 1.167321 0.8
34 0.86 2.408029 0.865429 1.068141 0.8
35 0.86 2.29022 0.876208 0.984489 0.8
36 0.86 2.17241 0.885329 0.912985 0.8
37 0.86 2.054601 0.893116 0.851162 0.8
38 0.86 1.936791 0.899823 0.797179 0.8
39 0.8 2.788161 0.906118 0.749633 0.8
40 0.86 1.818981 0.911236 0.70744 0.8
41 0.86 1.701172 0.915747 0.669742 0.8
42 0.86 1.583362 0.919753 0.635858 0.8
43 0.86 1.465552 0.923335 0.605237 0.8
44 0.86 1.347743 0.926565 0.57743 0.8
45 0.8 2.611447 0.929914 0.552065 0.8
46 0.86 1.229933 0.932576 0.528834 0.8
47 0.86 1.112123 0.944589 0.487783 0.75
48 0.86 0.994314 0.957206 0.452645 0.660714
49 0.86 0.876504 0.956548 0.42223 0.672143
50 0.86 0.758694 0.956653 0.395644 0.682143
51 0.8 2.434732 0.956518 0.372208 0.690966
52 0.86 0.640885 0.956676 0.351393 0.69881
53 0.86 0.523075 0.956741 0.316044 0.712143
54 0.8 2.258018 0.956481 0.287157 0.723052
55 0.8 2.081304 0.956445 0.263108 0.732143
56 0.8 1.904589 0.956481 0.242776 0.739835
57 0.86 0.405265 0.958259 0.217558 0.749384
58 0.8 1.727875 0.963083 0.197086 0.757143
59 0.8 1.55116 0.969757 0.175115 0.769048
60 0.8 1.374446 0.97003 0.153697 0.780662
61 0.8 1.197732 0.970382 0.134026 0.791337
62 0.8 1.021017 0.970721 0.118819 0.799596
63 0.8 1.5 0.970985 0.106711 0.8
64 0.8 1.2 0.971222 0.096843 0.8
65 0.8 1 0.97144 0.088645 0.8
66 0.8 0.9 0.971645 0.081727 0.8];
67
68 % Let's plot the cascade zero locations and the locations of the
69 % pole and zeros in the resonator.
70 if plotTests
71 clf;
72 subplot(3,3,1);
73 plot(FilterBankRTheta(:,1).*exp(i*FilterBankRTheta(:,2)))
74 axis([-1 1 0 1])
75 title('Cascade Zero Locations')
76
77 subplot(3,3,2);
78 plot([FilterBankRTheta(:,3).*exp(i*FilterBankRTheta(:,4)) ...
79 FilterBankRTheta(:,5).*exp(i*FilterBankRTheta(:,4)/2)],'+')
80 title('Resonator Pole/Zero')
81 drawnow;
82 end
83
84 % Convert r-theta form, first into a list of roots, then a polynomial
85 roots=exp(i*PreemphasisRTheta(:,2)).*PreemphasisRTheta(:,1);
86 SeneffPreemphasis=real(poly([roots;conj(roots)]));
87
88 % Plot the preemphasis filter response, if desired
89 if plotTests
90 subplot(3,3,3);
91 freqScale=(0:255)/256*8000;
92 freqresp = FreqResp(SeneffPreemphasis,[1], freqScale, 16000);
93 semilogx(freqScale,freqresp)
94 title('Preemphasis Response');
95 axis([100 10000 -60 20])
96 drawnow;
97 end
98
99 % Now figure out the second order sections that make up the main
100 % filter bank cascade. We put the zeros into the numerator (b's)
101 % and there are no poles. Just to keep things simpler, we adjust
102 % the gain of each filter to keep it unity gain at DC.
103 [channels,width] = size(FilterBankRTheta);
104 roots=exp(i*FilterBankRTheta(:,2)).*FilterBankRTheta(:,1);
105 SeneffFilterBank = zeros(channels,5);
106 for j=1:channels
107 SeneffFilterBank(j,1:3) = poly([roots(j) conj(roots(j))]);
108 SeneffFilterBank(j,1:3) = SeneffFilterBank(j,1:3)/sum(SeneffFilterBank(j,1:3));
109 end
110
111 % Plot the cascade zero responses, if desired.
112 if plotTests
113 subplot(3,3,4);
114 y=soscascade([1 zeros(1,511)],SeneffFilterBank);
115 freqresp=20*log10(abs(fft(y(1:5:40,:)')));
116 freqScale=(0:511)/512*16000;
117 semilogx(freqScale(1:256),freqresp(1:256,:))
118 axis([100 10000 -150 0]);
119 title('Cascade Response');
120 drawnow;
121 end
122
123 % Now figure out the resonating filters. Each of these resonators
124 % is a double pole-zero pair.
125 zlocs = FilterBankRTheta(:,5).*exp(i*FilterBankRTheta(:,4)/2);
126 plocs = FilterBankRTheta(:,3).*exp(i*FilterBankRTheta(:,4));
127 SeneffForward = zeros(5,channels);
128 SeneffBackward = zeros(5,channels);
129
130 for j=1:channels
131 SeneffForward(:,j) = real(poly([zlocs(j) conj(zlocs(j)) ...
132 zlocs(j) conj(zlocs(j))]))';
133 SeneffBackward(:,j) = real(poly([plocs(j) conj(plocs(j)) ...
134 plocs(j) conj(plocs(j))]))';
135 end
136
137 % Now plot the frequency response of just the resonating filters.
138 % These are all bandpass filters.
139 if plotTests
140 subplot(3,3,5);
141 impulse = [1 zeros(1,255)];
142 y=zeros(256,channels);
143 for j=1:40
144 y(:,j) = filter(SeneffForward(:,j),SeneffBackward(:,j),impulse)';
145 end
146 freqresp=20*log10(abs(fft(y(:,1:5:40))));
147 freqScale=(0:255)/256*16000;
148 semilogx(freqScale(1:128),freqresp(1:128,:))
149 axis([100 10000 -30 40]);
150 title('Resonators Response')
151 drawnow;
152 end
153
154 % The plot below shows the overall response of the preemphasis filters
155 % along with the just-designed cascade of zeros.
156 if plotTests
157 subplot(3,3,6);
158 impulse = [1 zeros(1,511)];
159 y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
160 SeneffFilterBank);
161 freqresp=20*log10(abs(fft(y(1:5:40,:)')));
162 freqScale=(0:511)/512*16000;
163 semilogx(freqScale(1:256),freqresp(1:256,:))
164 axis([100 10000 -100 25]);
165 title('Preemphasis+Cascade');
166 drawnow;
167 end
168
169 % Now we need to normalize the gain of each channel. We run an impulse
170 % through the preemphasis filter, and then through the cascade of zeros.
171 % Finally, we run it through each of the resonator filters.
172 impulse = [1 zeros(1,255)];
173 y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
174 SeneffFilterBank);
175 for j=1:channels
176 y(j,:) = filter(SeneffForward(:,j),SeneffBackward(:,j),y(j,:));
177 end
178
179 % Now we have impulse responses from each filter. We can find the FFT
180 % and then find the gain peak. We divide each forward polynomial by the
181 % maximum gain (to normalize) and then multiply by the desired low
182 % frequency roll-off. The Bryant paper says that the last 24 channels
183 % should be cut at 6dB per octave and that this occurs at 1600 Hz, but
184 % it looks to me like the gain change happens at 3200 Hz.
185 freqresp=abs(fft(y'));
186 gain = ones(1,channels)./max(freqresp);
187 cfs = FilterBankRTheta(:,4)/pi*fs/2;
188 rolloff = min(cfs/1600,1);
189
190 for j=1:channels
191 SeneffForward(:,j)=SeneffForward(:,j)*gain(j)*rolloff(j);
192 end
193
194 % All Done. The figure below should match Figure 3 of Bryant's paper.
195 if plotTests
196 subplot(3,3,8);
197 impulse = [1 zeros(1,511)];
198 y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
199 SeneffFilterBank);
200 for j=1:channels
201 y(j,:) = filter(SeneffForward(:,j),SeneffBackward(:,j),y(j,:));
202 end
203
204 freqresp=20*log10(abs(fft(y(1:5:40,:)')));
205 freqScale=(0:511)/512*16000;
206 plot(freqScale(1:256),freqresp(1:256,:))
207 axis([100 10000 -120 0]);
208 title('Magnitude Response vs. Linear Frequency');
209 drawnow;
210 end
211
212
213 function mag=FreqResp(b,a,f,fs)
214 cf = exp(i*2*pi*f/fs);
215 num = 0;
216 for i=1:length(b)
217 num = num + b(end-i+1)*cf.^i;
218 end
219
220 denom = 0;
221 for i=1:length(a)
222 denom = denom + a(end-i+1)*cf.^i;
223 end
224 mag = 20*log10(abs(num./denom));