view 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
line wrap: on
line source
function [SeneffPreemphasis, SeneffFilterBank, SeneffForward, SeneffBackward] ...
			= SeneffEarSetup(fs)
			
% This m-function is based on data from the following paper:
%	Benjamin D. Bryant and John D. Gowdy, "Simulation of Stages
%	I and II of Seneff's Auditory Model (SAM) Using Matlab", and 
%	published in the Proceedings of the 1993 Matlab User's Group
%	Conference.
% Thanks to Benjamin Bryant for supplying us with his filter 
% coefficients and the initial organization of this implementation.

% (c) 1998 Interval Research Corporation  

% Set the following variable to a non-zero value to see a summary
% of the filter bank's behaviour.
plotTests = 0;

% The following values were taken from Figure 2 of Bryant's paper.
PreemphasisRTheta = [0.86 3.1148863;0.99 0; 0.5 0; 0.95 3.14159];

% The following values were taken from Table 1 of Bryant's paper.
% They represent the cascade zeros (R-z and Theta-z), and the 
% second order poles (radius and theta) and zeros (radius and theta/2).
%
%    R-z       Theta-z       Radius       Theta       R-z2
FilterBankRTheta = [
     0         3.14159       0.740055     2.633909    0.8
     0.86      2.997077      0.753637     2.178169    0.8
     0.86      2.879267      0.775569     1.856744    0.8
     0.86      2.761458      0.798336     1.617919    0.8
     0.86      2.643648      0.819169     1.433496    0.8
     0.86      2.525839      0.837158     1.286795    0.8
     0.8       2.964876      0.852598     1.167321    0.8
     0.86      2.408029      0.865429     1.068141    0.8
     0.86      2.29022       0.876208     0.984489    0.8
     0.86      2.17241       0.885329     0.912985    0.8
     0.86      2.054601      0.893116     0.851162    0.8
     0.86      1.936791      0.899823     0.797179    0.8
     0.8       2.788161      0.906118     0.749633    0.8
     0.86      1.818981      0.911236     0.70744     0.8
     0.86      1.701172      0.915747     0.669742    0.8
     0.86      1.583362      0.919753     0.635858    0.8
     0.86      1.465552      0.923335     0.605237    0.8
     0.86      1.347743      0.926565     0.57743     0.8
     0.8       2.611447      0.929914     0.552065    0.8
     0.86      1.229933      0.932576     0.528834    0.8
     0.86      1.112123      0.944589     0.487783    0.75
     0.86      0.994314      0.957206     0.452645    0.660714
     0.86      0.876504      0.956548     0.42223     0.672143
     0.86      0.758694      0.956653     0.395644    0.682143
     0.8       2.434732      0.956518     0.372208    0.690966
     0.86      0.640885      0.956676     0.351393    0.69881
     0.86      0.523075      0.956741     0.316044    0.712143
     0.8       2.258018      0.956481     0.287157    0.723052
     0.8       2.081304      0.956445     0.263108    0.732143
     0.8       1.904589      0.956481     0.242776    0.739835
     0.86      0.405265      0.958259     0.217558    0.749384
     0.8       1.727875      0.963083     0.197086    0.757143
     0.8       1.55116       0.969757     0.175115    0.769048
     0.8       1.374446      0.97003      0.153697    0.780662
     0.8       1.197732      0.970382     0.134026    0.791337
     0.8       1.021017      0.970721     0.118819    0.799596
     0.8       1.5           0.970985     0.106711    0.8
     0.8       1.2           0.971222     0.096843    0.8
     0.8       1             0.97144      0.088645    0.8
     0.8       0.9           0.971645     0.081727    0.8];

% Let's plot the cascade zero locations and the locations of the
% pole and zeros in the resonator.
if plotTests
	clf;
	subplot(3,3,1);
	plot(FilterBankRTheta(:,1).*exp(i*FilterBankRTheta(:,2)))
	axis([-1 1 0 1])
	title('Cascade Zero Locations')

	subplot(3,3,2);
	plot([FilterBankRTheta(:,3).*exp(i*FilterBankRTheta(:,4)) ...
		  FilterBankRTheta(:,5).*exp(i*FilterBankRTheta(:,4)/2)],'+')
	title('Resonator Pole/Zero')
	drawnow;
end

% Convert r-theta form, first into a list of roots, then a polynomial
roots=exp(i*PreemphasisRTheta(:,2)).*PreemphasisRTheta(:,1);
SeneffPreemphasis=real(poly([roots;conj(roots)]));

% Plot the preemphasis filter response, if desired
if plotTests
	subplot(3,3,3);
	freqScale=(0:255)/256*8000;
	freqresp = FreqResp(SeneffPreemphasis,[1], freqScale, 16000);
	semilogx(freqScale,freqresp)
	title('Preemphasis Response');
	axis([100 10000 -60 20])
	drawnow;
end

% Now figure out the second order sections that make up the main
% filter bank cascade.  We put the zeros into the numerator (b's)
% and there are no poles.  Just to keep things simpler, we adjust
% the gain of each filter to keep it unity gain at DC.
[channels,width] = size(FilterBankRTheta);
roots=exp(i*FilterBankRTheta(:,2)).*FilterBankRTheta(:,1);
SeneffFilterBank = zeros(channels,5);
for j=1:channels
	SeneffFilterBank(j,1:3) = poly([roots(j) conj(roots(j))]);
	SeneffFilterBank(j,1:3) = SeneffFilterBank(j,1:3)/sum(SeneffFilterBank(j,1:3));
end

% Plot the cascade zero responses, if desired.
if plotTests
	subplot(3,3,4);
	y=soscascade([1 zeros(1,511)],SeneffFilterBank);
	freqresp=20*log10(abs(fft(y(1:5:40,:)')));
	freqScale=(0:511)/512*16000;
	semilogx(freqScale(1:256),freqresp(1:256,:))
	axis([100 10000 -150 0]);
	title('Cascade Response');
	drawnow;
end

% Now figure out the resonating filters.  Each of these resonators
% is a double pole-zero pair.
zlocs = FilterBankRTheta(:,5).*exp(i*FilterBankRTheta(:,4)/2);
plocs = FilterBankRTheta(:,3).*exp(i*FilterBankRTheta(:,4));
SeneffForward = zeros(5,channels);
SeneffBackward = zeros(5,channels);

for j=1:channels
	SeneffForward(:,j) = real(poly([zlocs(j) conj(zlocs(j)) ...
										zlocs(j) conj(zlocs(j))]))';
	SeneffBackward(:,j) = real(poly([plocs(j) conj(plocs(j)) ...
										plocs(j) conj(plocs(j))]))';
end

% Now plot the frequency response of just the resonating filters.
% These are all bandpass filters.
if plotTests
	subplot(3,3,5);
	impulse = [1 zeros(1,255)];
	y=zeros(256,channels);
	for j=1:40
		y(:,j) = filter(SeneffForward(:,j),SeneffBackward(:,j),impulse)';
	end
	freqresp=20*log10(abs(fft(y(:,1:5:40))));
	freqScale=(0:255)/256*16000;
	semilogx(freqScale(1:128),freqresp(1:128,:))
	axis([100 10000 -30 40]);
	title('Resonators Response')
	drawnow;
end

% The plot below shows the overall response of the preemphasis filters
% along with the just-designed cascade of zeros.
if plotTests
	subplot(3,3,6);
	impulse = [1 zeros(1,511)];
	y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
				SeneffFilterBank);
	freqresp=20*log10(abs(fft(y(1:5:40,:)')));
	freqScale=(0:511)/512*16000;
	semilogx(freqScale(1:256),freqresp(1:256,:))
	axis([100 10000 -100 25]);
	title('Preemphasis+Cascade');
	drawnow;
end

% Now we need to normalize the gain of each channel.  We run an impulse
% through the preemphasis filter, and then through the cascade of zeros.
% Finally, we run it through each of the resonator filters.
impulse = [1 zeros(1,255)];
y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
			SeneffFilterBank);
for j=1:channels
	y(j,:) = filter(SeneffForward(:,j),SeneffBackward(:,j),y(j,:));
end

% Now we have impulse responses from each filter.   We can find the FFT
% and then find the gain peak.  We divide each forward polynomial by the
% maximum gain (to normalize) and then multiply by the desired low
% frequency roll-off.  The Bryant paper says that the last 24 channels
% should be cut at 6dB per octave and that this occurs at 1600 Hz, but 
% it looks to me like the gain change happens at 3200 Hz.
freqresp=abs(fft(y'));
gain = ones(1,channels)./max(freqresp);
cfs = FilterBankRTheta(:,4)/pi*fs/2;
rolloff = min(cfs/1600,1);
	
for j=1:channels
	SeneffForward(:,j)=SeneffForward(:,j)*gain(j)*rolloff(j);
end
	
% All Done. The figure below should match Figure 3 of Bryant's paper.
if plotTests
	subplot(3,3,8);
	impulse = [1 zeros(1,511)];
	y=soscascade(filter(SeneffPreemphasis, [1], impulse), ...
				SeneffFilterBank);
	for j=1:channels
		y(j,:) = filter(SeneffForward(:,j),SeneffBackward(:,j),y(j,:));
	end

	freqresp=20*log10(abs(fft(y(1:5:40,:)')));
	freqScale=(0:511)/512*16000;
	plot(freqScale(1:256),freqresp(1:256,:))
	axis([100 10000 -120 0]);
	title('Magnitude Response vs. Linear Frequency');
	drawnow;
end


function mag=FreqResp(b,a,f,fs)
cf = exp(i*2*pi*f/fs);
num = 0;
for i=1:length(b)
	num = num + b(end-i+1)*cf.^i;
end

denom = 0;
for i=1:length(a)
	denom = denom + a(end-i+1)*cf.^i;
end
mag = 20*log10(abs(num./denom));