comparison userProgramsASRforDummies/cEssexAid.m @ 38:c2204b18f4a2 tip

End nov big change
author Ray Meddis <rmeddis@essex.ac.uk>
date Mon, 28 Nov 2011 13:34:28 +0000
parents
children
comparison
equal deleted inserted replaced
37:771a643d5c29 38:c2204b18f4a2
1 classdef cEssexAid
2 %ESSEXAID_WRAPCLASS Wrapper for the EssexAid - Nick Clark July 2011
3 % This class wraps up the EssexAid algorithm function that processes
4 % each block of samples. This wrapper closely emulates the GUI used
5 % in the lab and runs stimuli through the exact same algorithm used
6 % in the lab. It even includes a helper function to generate C code
7 % from the algorithm for use in a real-time framework.
8
9
10 %% *********************************************************
11 % properties _ _
12 % | | (_)
13 % _ __ _ __ ___ _ __ ___ _ __| |_ _ ___ ___
14 % | '_ \| '__/ _ \| '_ \ / _ \ '__| __| |/ _ \/ __|
15 % | |_) | | | (_) | |_) | __/ | | |_| | __/\__ \
16 % | .__/|_| \___/| .__/ \___|_| \__|_|\___||___/
17 % | | | |
18 % |_| |_|
19 %************************************************************
20
21 %% **********************************************************
22 % Public properties - can be set by user
23 %************************************************************
24 properties(Access = public)
25 sr = 48e3;
26 numSamples = 1024; %MAX=6912, LAB_USE=48
27 stimulusUSER
28
29 %------------------------------------------------------------------
30 % Params for audiometric freqs 250, 500, 1000, 2000, 4000, 8000 Hz
31 %------------------------------------------------------------------
32 audiometry_dB= [ 0; 0; 0; 0; 0; 0]; %Pure tone threshold in dB SPL
33 mainGain_dB = [ 0; 0; 0; 0; 0; 0]; %Gain applied at audiometric frequencies
34 TC_dBHL = [40; 40; 40; 40; 40; 40]; %Compression thresholds (in dB HL from 2nd filt)
35 TM_dBHL = [10; 10; 10; 10; 10; 10]; %MOC thresholds (in dB OUTPUT from 2nd filt)
36 DRNLc = [ 0.2; 0.2; 0.2; 0.2; 0.2; 0.2]; %Compression exponent at audiometric frequencies
37
38 %------------------------------------------------------------------
39 % Dynamic compression properties
40 %------------------------------------------------------------------
41 ARtau = 60e-3; %decay time constant
42 ARthreshold_dB = 85; %dB SPL (input signal level) =>200 to disable
43 MOCtau = 450e-3; %Time constant in Seconds
44 MOCfactor = 0.5; %dB attenuation applied to the input per dB exceeding output threshold
45
46 %------------------------------------------------------------------
47 % Band filtering properties
48 %------------------------------------------------------------------
49 bwOct = 1/2; %1/1, 1/2, 1/3, 1/4, 1/5
50 filterOrder = 2 %BUTTER=2, GTF=3
51 useGTF = false; %If false, revert to butterworth
52 end
53
54 %% **********************************************************
55 % Read only properties that are not dependent
56 %************************************************************
57 properties(SetAccess = private)
58 MOCrecord
59 end
60
61 %% **********************************************************
62 % Constant properties
63 %************************************************************
64 properties(Constant = true, Hidden = true)
65 numAudiometricFreqs = 6;
66 end
67
68 %% **********************************************************
69 % Dependent visable properties - calculated at runtime
70 %************************************************************
71 properties(Dependent = true, Hidden = false)
72 channelBFs %= 250 * 2.^((0:fNmax)'*params.bwOct);
73 numChannels %= numel(channelBFs);
74 aidOPnice %aid output reformatted to be exactly the same dimensions as the input stimulus
75 end
76
77 %% **********************************************************
78 % Dependent invisable properties - calculated at runtime
79 %************************************************************
80 properties(Dependent = true, Hidden = true)
81 TC_dBO_INTERP % Compression threshold in terms of 2nd filter o/p in dB SPL
82 TM_dBO_INTERP % MOC threshold in terms of 2nd filter o/p in dB SPL
83 bwOct_INTERP
84 DRNLb_INTERP %= ( 2e-5 .* 10.^(TCdBO/20)) .^ (1-DRNLc) ;
85 DRNLc_INTERP
86 mainGain_INTERP %Interp'd and in linear units
87
88 ARthresholdPa %= 20e-6*10^(ARthreshold_dB/20);% Pa thresh for triggering AR
89 stimulusINTERNAL %input stimulus in correct format for the Aid algo
90 end
91
92 %% **********************************************************
93 % Protected properties - The user never needs to set
94 %************************************************************
95 properties(Access = protected)
96 aidOP
97 emlc_z
98
99 %--------------------------------------------------------------
100 % ENUMERATIONS USED IN THE FRAME PROCESSOR
101 %--------------------------------------------------------------
102 enumC_ARb = 0;
103 enumC_ARa = 2;
104 enumC_MOCb = 4;
105 enumC_MOCa = 6;
106
107 % enumC_BPb1 = 8;
108 % enumC_BPa1 = 13;
109 % enumC_BPb2 = 18;
110 % enumC_BPa2 = 23;
111 % enumC_BPb3 = 28;
112 % enumC_BPa3 = 33;
113 % enumC_BPb4 = 38;
114 % enumC_BPa4 = 43;
115
116 enumS_AR = 0;
117
118 % enumS_MOC1 = 1;
119 % enumS_BPin_1_1 = 2;
120 % enumS_BPin_2_1 = 6;
121 % enumS_BPout_1_1 = 10;
122 % enumS_BPout_2_1 = 14;
123 %
124 % enumS_MOC2 = 18;
125 % enumS_BPin_1_2 = 19;
126 % enumS_BPin_2_2 = 23;
127 % enumS_BPout_1_2 = 27;
128 % enumS_BPout_2_2 = 31;
129 % ...
130 end
131
132 %% **********************************************************
133 % methods _ _ _
134 % | | | | | |
135 % _ __ ___ ___| |_| |__ ___ __| |___
136 %| '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
137 %| | | | | | __/ |_| | | | (_) | (_| \__ \
138 %|_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
139 %************************************************************
140
141 methods
142 %% **********************************************************
143 % Constructor
144 %************************************************************
145 function obj = EssexAid_WrapClass(sr, stimulus)
146
147 if nargin > 0
148 obj.sr = sr;
149 end
150
151 if nargin > 1
152 obj.stimulusUSER = stimulus;
153 else
154 obj.stimulusUSER = obj.pipSequence(obj.sr);
155 end
156 end
157
158 %% **********************************************************
159 % Get method for channelBFs
160 %************************************************************
161 function value = get.channelBFs(obj)
162 fNmax = 5/obj.bwOct;
163 value = 250 * 2.^((0:fNmax)'*obj.bwOct);
164 end
165
166 %% **********************************************************
167 % Get method for numChannels
168 %************************************************************
169 function value = get.numChannels(obj)
170 value = numel(obj.channelBFs);
171 end
172
173 %% **********************************************************
174 % Get method for ARthresholdPa
175 %************************************************************
176 function value = get.ARthresholdPa(obj)
177 value = 20e-6*10^(obj.ARthreshold_dB/20);% Pa thresh for triggering AR
178 end
179
180 %% **********************************************************
181 % Get method for TC_dBO_INTERP
182 %************************************************************
183 function value = get.TC_dBO_INTERP(obj)
184 TC_dBO = obj.audiometry_dB - obj.mainGain_dB + obj.TC_dBHL;
185 value = obj.interpPars(TC_dBO, obj.numChannels);
186 end
187
188 %% **********************************************************
189 % Get method for TM_dBO_INTERP
190 %************************************************************
191 function value = get.TM_dBO_INTERP(obj)
192 TM_dBO = obj.audiometry_dB - obj.mainGain_dB + obj.TM_dBHL;
193 value = obj.interpPars(TM_dBO, obj.numChannels);
194 end
195
196 %% **********************************************************
197 % Get method for bwOct_INTERP
198 %************************************************************
199 function value = get.bwOct_INTERP(obj)
200 value = repmat(obj.bwOct, 1, obj.numChannels);
201 end
202
203 %% **********************************************************
204 % Get method for DRNLb_INTERP
205 %************************************************************
206 function value = get.DRNLb_INTERP(obj)
207 value = ( 2e-5 .* 10.^(obj.TC_dBO_INTERP/20)) .^ (1-obj.DRNLc_INTERP);
208 end
209
210 %% **********************************************************
211 % Get method for DRNLc_INTERP
212 %************************************************************
213 function value = get.DRNLc_INTERP(obj)
214 value = obj.interpPars(obj.DRNLc, obj.numChannels);
215 end
216
217 %% **********************************************************
218 % Get method for mainGain_INTERP
219 %************************************************************
220 function value = get.mainGain_INTERP(obj)
221 mainGainLin = 10.^(obj.mainGain_dB/20); %lin units
222 value = obj.interpPars(mainGainLin, obj.numChannels);
223 end
224
225 %% ***********************************************************
226 % Get method for stimulus
227 % -----------------------
228 % The hearing aid expects a stereo signal, as the MOC control is
229 % linked for left and right channels. It would be more efficient to
230 % use a mono version of the aid for simulation in Matlab. However,
231 % I always want to use the exact same code for the hardware in the
232 % lab and current simulations. This code will make a mono signal
233 % stereo if needs be and/or rotate to 2xN array.
234 %*************************************************************
235 function value = get.stimulusINTERNAL(obj)
236 [nRows, nCols] = size(obj.stimulusUSER);
237
238 % Assume that the stimulus duration is greater than 2 samples.
239 % Therefore the number of channels is the min dim.
240 [nChans, I] = min([nRows nCols]);
241
242 if nChans == 2
243 if I == 2
244 value = obj.stimulusUSER;
245 else
246 value = obj.stimulusUSER';
247 end
248 elseif nChans == 1 %Just to be explicit
249 if I == 2
250 value = [obj.stimulusUSER obj.stimulusUSER];
251 else
252 value = [obj.stimulusUSER; obj.stimulusUSER]';
253 end
254 end
255 end
256
257 %% ***********************************************************
258 % Get method for aid output
259 % -----------------------
260 % This get method is linked to the above internal stimulus method
261 % and allows the user to extract the hearing aid output in exactly
262 % the same shape and size as the original input stimulus. This is
263 % very useful for the speech recognition work and presumably
264 % for multithreshold also.
265 %*************************************************************
266 function value = get.aidOPnice(obj)
267 if ~isempty(obj.aidOP)
268 [nRows, nCols] = size(obj.stimulusUSER);
269
270 % Assume that the stimulus duration is greater than 2 samples.
271 % Therefore the number of channels is the min dim.
272 [nChans, I] = min([nRows nCols]);
273
274 %** The aid output will ALWAYS be a 2xN array **
275 %The fist job is to remove trailing zeros that may have been
276 %introduced by the framing process
277 aidOPtruncated = obj.aidOP(:, 1:max([nRows nCols]));
278
279 %The next task is to arrange the op like the ip
280 if nChans == 2
281 if I == 1
282 value = aidOPtruncated;
283 else
284 value = aidOPtruncated';
285 end
286 elseif nChans == 1 %Just to be explicit
287 if I == 1
288 value = aidOPtruncated(1,:);
289 else
290 value = aidOPtruncated(1,:)';
291 end
292 end
293 else % ---- of if isempty statement
294 value = [];
295 end
296 end
297
298 %% ***********************************************************
299 % *** Set methods ***
300 % -----------------------
301 % This is a bunch of unexciting error hunting functions. They also
302 % flush the aid output if any parameters change. Therefore,
303 % processStim will have to be called explicity by the user once
304 % again.
305 %*************************************************************
306 function obj = set.stimulusUSER(obj,value)
307 [nRows, nCols] = size(value);
308
309 % Assume that the stimulus duration is greater than 2 samples.
310 % Therefore the number of channels is the min dim.
311 nChans = min([nRows nCols]);
312 assert(nChans<3 && nChans, 'Number of stimulus channels must be 1 or 2')
313
314 obj = obj.flushAidData; %flush any previous hearing aid data if the input stimulus changes
315 obj.stimulusUSER = value;
316 end
317 function obj = set.sr(obj,value)
318 assert(value>=20e3 && value<=192e3, 'sr must be between 20 and 192 kHz')
319 obj = obj.flushAidData;
320 obj.sr = value;
321 end
322 function obj = set.numSamples(obj,value)
323 assert(value>=48 && value<=6912, 'must be between 48 and 6912 samples')
324 obj = obj.flushAidData;
325 obj.numSamples = value;
326 end
327 function obj = set.audiometry_dB(obj,value)
328 [nRows,nCols] = size(value);
329 assert(nRows==obj.numAudiometricFreqs && nCols==1, 'must be 6x1 column vector') %#ok<MCSUP>
330 obj = obj.flushAidData;
331 obj.audiometry_dB = value;
332 end
333 function obj = set.mainGain_dB(obj,value)
334 [nRows,nCols] = size(value);
335 assert(nRows==obj.numAudiometricFreqs && nCols==1, 'must be 6x1 column vector') %#ok<MCSUP>
336 obj = obj.flushAidData;
337 obj.mainGain_dB = value;
338 end
339 function obj = set.TC_dBHL(obj,value)
340 [nRows,nCols] = size(value);
341 assert(nRows==obj.numAudiometricFreqs && nCols==1, 'must be 6x1 column vector') %#ok<MCSUP>
342 obj = obj.flushAidData;
343 obj.TC_dBHL = value;
344 end
345 function obj = set.TM_dBHL(obj,value)
346 [nRows,nCols] = size(value);
347 assert(nRows==obj.numAudiometricFreqs && nCols==1, 'must be 6x1 column vector') %#ok<MCSUP>
348 obj = obj.flushAidData;
349 obj.TM_dBHL = value;
350 end
351 function obj = set.DRNLc(obj,value)
352 [nRows,nCols] = size(value);
353 assert(nRows==obj.numAudiometricFreqs && nCols==1, 'must be 6x1 column vector') %#ok<MCSUP>
354 assert(all(value)>=0 && all(value)<=1, 'all DRNLc values must be between 0 and 1')
355 obj = obj.flushAidData;
356 obj.DRNLc = value;
357 end
358 function obj = set.ARtau(obj,value)
359 assert(value>=1e-3 && value<=1, 'must be between 1e-3 and 1s')
360 obj = obj.flushAidData;
361 obj.ARtau = value;
362 end
363 function obj = set.ARthreshold_dB(obj,value)
364 assert(value>0, 'set AR to a high value to disable it')
365 obj = obj.flushAidData;
366 obj.ARthreshold_dB = value;
367 end
368 function obj = set.MOCtau(obj,value)
369 assert(value>=1e-3 && value<=2, 'must be between 1e-3 and 2s')
370 obj = obj.flushAidData;
371 obj.MOCtau = value;
372 end
373 function obj = set.MOCfactor(obj,value)
374 assert(value>=0 && value<=1, 'must be between 0 and 1')
375 obj = obj.flushAidData;
376 obj.MOCfactor = value;
377 end
378 function obj = set.bwOct(obj,value)
379 assert(value==1/1 || value==1/2 || value==1/3 || value==1/4 || value==1/5, 'must be one of 1./(1:5)')
380 obj = obj.flushAidData;
381 obj.bwOct = value;
382 end
383 function obj = set.filterOrder(obj,value)
384 assert(value>0 && value<5, 'must be one of 1:4')
385 obj = obj.flushAidData;
386 obj.filterOrder = value;
387 end
388 function obj = set.useGTF(obj,value)
389 obj = obj.flushAidData;
390 obj.useGTF = value;
391 end
392
393 %% **********************************************************
394 % flushAidData
395 % This second function is a workaround allowing a set method to
396 % change another property value.
397 %************************************************************
398 function obj = flushAidData(obj)
399 obj.aidOP = [];
400 obj.MOCrecord = [];
401 end
402
403
404 %% **********************************************************
405 % OVERLOADED plot method
406 %************************************************************
407 function plot(obj)
408 clf
409 sig2dBSPL = @(sig)20*log10(abs(sig/20e-6)+(1/(2^32)));
410 dt = 1/obj.sr;
411 tAxis = dt:dt:dt*size(obj.stimulusINTERNAL,1);
412
413 subplot(2,1,1)
414 plot(tAxis(1:length(obj.stimulusUSER)), sig2dBSPL(obj.stimulusUSER), 'k')
415 if ~isempty(obj.aidOPnice)
416 hold on
417 plot(tAxis(1:length(obj.stimulusUSER)), sig2dBSPL(obj.aidOPnice), 'r')
418 end
419 ylim([0 100])
420 xlim([0 tAxis(length(obj.stimulusUSER))])
421 title('Level response')
422 xlabel('Time in seconds')
423 ylabel('Level in dB SPL')
424
425 subplot(2,1,2)
426 if ~isempty(obj.MOCrecord)
427 imagesc(tAxis, 1:obj.numChannels, flipud(-20*log10(obj.MOCrecord)))
428 colorbar
429 end
430 title('MOC attenuation')
431 xlabel('Time in seconds')
432 ylabel('Band frequency in Hz')
433 numSpacers = 1 + (obj.numChannels-numel(obj.DRNLc)) / (numel(obj.DRNLc)-1);
434 set(gca, 'YTick', 1:numSpacers:obj.numChannels);
435 set(gca, 'YTickLabel', num2str(flipud([250; 500; 1000; 2000; 4000; 8000])));
436 end% ------ OVERLOADED plot method
437
438 %% **********************************************************
439 % OVERLOADED soundsc method
440 %************************************************************
441 function soundsc(obj)
442 soundsc(obj.aidOPnice, obj.sr)
443 end
444
445 %% **********************************************************
446 % processStim
447 %************************************************************
448 function obj = processStim(obj)
449 %--------------------------------------------------------------
450 % EMULATION OF THE GUI PARAMETER CONVERSIONS
451 %--------------------------------------------------------------
452 biggestNumSamples = obj.numSamples;
453
454 filterStatesL = (zeros(3000,1));
455 filterStatesR = filterStatesL;
456 filterCoeffs = (zeros(5000,1));
457
458 %filter coefficients
459 ARcutOff=1/(2*pi*obj.ARtau);
460 [b,a] = butter(1,ARcutOff/(obj.sr/2));
461 filterCoeffs(obj.enumC_ARb+1:obj.enumC_ARb+2) = b;
462 filterCoeffs(obj.enumC_ARa+1:obj.enumC_ARa+2) = a;
463
464 MOCcutOff=1/(2*pi*obj.MOCtau);
465 [bMOC,aMOC] = butter(1,MOCcutOff/(obj.sr/2));
466 filterCoeffs(obj.enumC_MOCb+1:obj.enumC_MOCb+2) = bMOC;
467 filterCoeffs(obj.enumC_MOCa+1:obj.enumC_MOCa+2) = aMOC;
468
469
470 for filterCount = 1:obj.numChannels
471 %-----------------------------------
472 % nonlinear path - filter bws
473 %-----------------------------------
474 lowerCutOff=obj.channelBFs(filterCount)*2^(-obj.bwOct_INTERP(filterCount)/2);
475 upperCutOff=obj.channelBFs(filterCount)*2^( obj.bwOct_INTERP(filterCount)/2);
476
477 if obj.useGTF
478 bwHz = upperCutOff - lowerCutOff;
479 [b_DRNL,a_DRNL] = obj.gammatone(bwHz, obj.channelBFs(filterCount), 1/obj.sr);
480 filterCoeffs(10*(filterCount-1)+9 :10*(filterCount-1)+10) = b_DRNL;
481 filterCoeffs(10*(filterCount-1)+14:10*(filterCount-1)+16) = a_DRNL;
482 else
483 [b_DRNL,a_DRNL] = butter(2,[lowerCutOff upperCutOff]/(obj.sr/2));
484 filterCoeffs(10*(filterCount-1)+9 :10*(filterCount-1)+13) = b_DRNL;
485 filterCoeffs(10*(filterCount-1)+14:10*(filterCount-1)+18) = a_DRNL;
486 end
487 end
488
489 %--------------------------------------------------------------
490 % EMULATION OF THE IO CALLBACK THREAD
491 %--------------------------------------------------------------
492 frameBufferL = buffer(obj.stimulusINTERNAL(:,1), obj.numSamples);
493 frameBufferR = buffer(obj.stimulusINTERNAL(:,2), obj.numSamples);
494 nFrames = size(frameBufferL,2);
495
496 pad = zeros(1,biggestNumSamples-obj.numSamples);
497 ARampL=ones(1,biggestNumSamples);
498 ARampR = ARampL;
499 MOCcontrol = ones(obj.numChannels, biggestNumSamples);
500
501 peakIPL = zeros(5,1);
502 peakOPL = peakIPL;
503 rmsIPL = peakIPL;
504 rmsOPL = peakIPL;
505
506 peakIPR = peakIPL;
507 peakOPR = peakIPL;
508 rmsIPR = peakIPL;
509 rmsOPR = peakIPL;
510
511 MOCend = zeros(obj.numChannels,1);
512
513 op = [];
514 moc= [];
515 for nn = 1:nFrames
516 frameBufferPadL = [frameBufferL(:,nn)' pad];
517 frameBufferPadR = [frameBufferR(:,nn)' pad];
518
519 [ outBufferL, outBufferR, filterStatesL, filterStatesR, ARampL, ARampR, MOCend, peakIPL, peakOPL, rmsIPL, rmsOPL, peakIPR, peakOPR, rmsIPR, rmsOPR, MOCcontrol ] =...
520 EssexAidProcessVFrameSwitchable( ...
521 frameBufferPadL,...
522 frameBufferPadR,...
523 filterStatesL,...
524 filterStatesR,...
525 filterCoeffs,...
526 obj.numChannels,...
527 obj.numSamples,...
528 ARampL,...
529 ARampR,...
530 obj.ARthresholdPa,...
531 obj.filterOrder,...
532 obj.DRNLb_INTERP,...
533 obj.DRNLc_INTERP,...
534 obj.TM_dBO_INTERP,...
535 obj.MOCfactor,...
536 peakIPL,...
537 peakOPL,...
538 rmsIPL,...
539 rmsOPL,...
540 peakIPR,...
541 peakOPR,...
542 rmsIPR,...
543 rmsOPR,...
544 MOCend,...
545 MOCcontrol,...
546 obj.mainGain_INTERP,...
547 obj.useGTF);
548
549
550 outBuffer = ( [outBufferL(:, 1:obj.numSamples); outBufferR(:, 1:obj.numSamples)] );
551 op = [op outBuffer]; %#ok<AGROW>
552 moc= [moc MOCcontrol]; %#ok<AGROW>
553
554 end %End of frame processing emulation loop
555 obj.aidOP = op;
556 obj.MOCrecord=moc;
557
558
559 end %End of process stim method
560
561 end %End of methods block
562
563 %% *********************************************************
564 % _ _ _ _ _ _
565 % | | | | (_) | | | | | |
566 % ___| |_ __ _| |_ _ ___ _ __ ___ ___| |_| |__ ___ __| |___
567 % / __| __/ _` | __| |/ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
568 % \__ \ || (_| | |_| | (__ | | | | | | __/ |_| | | | (_) | (_| \__ \
569 % |___/\__\__,_|\__|_|\___| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
570 %************************************************************
571
572 methods(Static)
573 %% ********************************************************
574 % pipOut - sequence of tone pips at various levels
575 %**********************************************************
576 function pipOut = pipSequence(sampleRate, freq, dBlevs, pulseDur, silDur)
577 if nargin < 5
578 silDur = 0.3;
579 end
580 if nargin < 4
581 pulseDur = 0.1;
582 end
583 if nargin < 3
584 dBlevs = 20:20:100;
585 end
586 if nargin < 2
587 freq = 500;
588 end
589 if nargin < 1
590 sampleRate = 48e3;
591 end
592
593 dt = 1/sampleRate;
594 tAxis = dt:dt:pulseDur;
595 sPulse = sin(2*pi*freq*tAxis);
596 sPulse = sPulse./sqrt(mean(sPulse.^2));
597 rms2dBspl = @(dBspl)20e-6*10^(dBspl/20); %sneaky short-hand function by (ab)using function handles
598 zPad = zeros(1,ceil(sampleRate*silDur));
599
600 pipOut = [];
601 for nn = 1:numel(dBlevs)
602 pipOut = [ pipOut sPulse*rms2dBspl(dBlevs(nn)) zPad]; %#ok<AGROW>
603 end
604
605 end% ------ OF pipSequence
606
607 %% ********************************************************
608 % interpPars - Linear interpolation of given parameter to mimic GUI
609 % fitting functionality.
610 %**********************************************************
611 function fullArray = interpPars(shortArray, numBands)
612 nGUIbands = numel(shortArray);
613 if numBands == nGUIbands
614 fullArray = shortArray;
615 else
616 numSpacers = (numBands-nGUIbands) / (nGUIbands-1);
617 fullArray = shortArray(1);
618 for nn = 2:nGUIbands
619 fullArray = [fullArray,...
620 repmat(mean([shortArray(nn) shortArray(nn-1)]),1,numSpacers),...
621 shortArray(nn)]; %#ok<AGROW>
622 end
623 end
624 end% ----- OF interpPars
625
626 %% ********************************************************
627 % gammatone - get filter coefficients
628 %**********************************************************
629 function [b,a] = gammatone(bw, cf, dt)
630 phi = 2 * pi * bw * dt;
631 theta = 2 * pi * cf * dt;
632 cos_theta = cos(theta);
633 sin_theta = sin(theta);
634 alpha = -exp(-phi) * cos_theta;
635 b0 = 1.0;
636 b1 = 2 * alpha;
637 b2 = exp(-2 * phi);
638 z1 = (1 + alpha * cos_theta) - (alpha * sin_theta) * 1i;
639 z2 = (1 + b1 * cos_theta) - (b1 * sin_theta) * 1i;
640 z3 = (b2 * cos(2 * theta)) - (b2 * sin(2 * theta)) * 1i;
641 tf = (z2 + z3) / z1;
642 a0 = abs(tf);
643 a1 = alpha * a0;
644
645 a = [b0, b1, b2];
646 b = [a0, a1];
647 end% ------ OF gammatone
648 end% ------ OF static methods
649
650 end %End of classdef
651