tomwalters@0
|
1 /*
|
tomwalters@0
|
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
|
tomwalters@0
|
3 ===========================================================================
|
tomwalters@0
|
4
|
tomwalters@0
|
5 Permission to use, copy, modify, and distribute this software without fee
|
tomwalters@0
|
6 is hereby granted for research purposes, provided that this copyright
|
tomwalters@0
|
7 notice appears in all copies and in all supporting documentation, and that
|
tomwalters@0
|
8 the software is not redistributed for any fee (except for a nominal shipping
|
tomwalters@0
|
9 charge). Anyone wanting to incorporate all or part of this software in a
|
tomwalters@0
|
10 commercial product must obtain a license from the Medical Research Council.
|
tomwalters@0
|
11
|
tomwalters@0
|
12 The MRC makes no representations about the suitability of this
|
tomwalters@0
|
13 software for any purpose. It is provided "as is" without express or implied
|
tomwalters@0
|
14 warranty.
|
tomwalters@0
|
15
|
tomwalters@0
|
16 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
tomwalters@0
|
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
|
tomwalters@0
|
18 A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
tomwalters@0
|
19 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
tomwalters@0
|
20 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
tomwalters@0
|
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
tomwalters@0
|
22 */
|
tomwalters@0
|
23
|
tomwalters@0
|
24 /*
|
tomwalters@0
|
25 Acknowledgment:
|
tomwalters@0
|
26 ==============
|
tomwalters@0
|
27
|
tomwalters@0
|
28 The source code provided in this file was originally developed by
|
tomwalters@0
|
29 Christian Giguere as part of a Ph.D degree at the Department of
|
tomwalters@0
|
30 Engineering of the University of Cambridge from April 1990 to
|
tomwalters@0
|
31 November 1993. The code was subsequently adapted under a grant
|
tomwalters@0
|
32 from the Hearing Research Trust for full compatibility with
|
tomwalters@0
|
33 AIM Release 6.15.
|
tomwalters@0
|
34
|
tomwalters@0
|
35 Christian Giguere 25/03/94
|
tomwalters@0
|
36
|
tomwalters@0
|
37 */
|
tomwalters@0
|
38
|
tomwalters@0
|
39 /*
|
tomwalters@0
|
40 =============================================================
|
tomwalters@0
|
41 wdf_tl.c
|
tomwalters@0
|
42 =============================================================
|
tomwalters@0
|
43
|
tomwalters@0
|
44 Wave digital filter (WDF) implementation of the cochlear
|
tomwalters@0
|
45 transmission line (TL) network.
|
tomwalters@0
|
46
|
tomwalters@0
|
47 Author : Christian Giguere
|
tomwalters@0
|
48 First written : 01st April, 1991
|
tomwalters@0
|
49 Last edited : 18th February, 1994
|
tomwalters@0
|
50
|
tomwalters@0
|
51 References:
|
tomwalters@0
|
52 (1) C.Giguere and P.C.Woodland (1994). JASA 95(1): 331-342.
|
tomwalters@0
|
53 (2) A.Fettweis (1986). Proceedings IEEE 74(2): 270-327.
|
tomwalters@0
|
54 =============================================================
|
tomwalters@0
|
55 */
|
tomwalters@0
|
56
|
tomwalters@0
|
57 /***** includes *****/
|
tomwalters@0
|
58
|
tomwalters@0
|
59 #include <math.h>
|
tomwalters@0
|
60 #include <stdio.h>
|
tomwalters@0
|
61 #include "stitch.h"
|
tomwalters@0
|
62 #include "source.h"
|
tomwalters@0
|
63 #include "calc.h"
|
tomwalters@0
|
64 #include "calc_tl.h"
|
tomwalters@0
|
65 #include "bank_tl.h"
|
tomwalters@0
|
66 #include "wdf_tl.h"
|
tomwalters@0
|
67 #include "wdf_ear.h"
|
tomwalters@0
|
68
|
tomwalters@0
|
69 /***** defines *****/
|
tomwalters@0
|
70
|
tomwalters@0
|
71 #if 0
|
tomwalters@0
|
72 #define _DEBUG_
|
tomwalters@0
|
73 #define _OVERFLOW_
|
tomwalters@0
|
74 #endif
|
tomwalters@0
|
75
|
tomwalters@0
|
76 #if 0
|
tomwalters@0
|
77 #define _IMPULSE_ /* bypasses input wave with a delta impulse */
|
tomwalters@0
|
78 #endif
|
tomwalters@0
|
79
|
tomwalters@0
|
80 #if 0 /* bypasses input wave with a pure tone and dumps */
|
tomwalters@0
|
81 #define _BMCURVES_ /* the rms value of basilar membrane velocity on stdout */
|
tomwalters@0
|
82 #endif /* (see below for other parameters to set) */
|
tomwalters@0
|
83
|
tomwalters@0
|
84 #if 0
|
tomwalters@0
|
85 #define _EAR_ /* dumps stapes velocity and eardrum pressure on stdout */
|
tomwalters@0
|
86 #endif
|
tomwalters@0
|
87
|
tomwalters@0
|
88 #define NUMBER_OF_STATES ( 14 ) /* per TLF segment */
|
tomwalters@0
|
89 #define NUMBER_OF_COEFFS ( 0 ) /* per TLF segment */
|
tomwalters@0
|
90
|
tomwalters@0
|
91
|
tomwalters@0
|
92 /***** functions *****/
|
tomwalters@0
|
93
|
tomwalters@0
|
94 /******************************** WDF set-up function *************************************
|
tomwalters@0
|
95 * name: function:
|
tomwalters@0
|
96 *
|
tomwalters@0
|
97 * WDFilterState() Set-up function for the WDF implementation of the cochlear network
|
tomwalters@0
|
98 * (Giguere and Woodland, 1994, Figs. 3 and 10). It generates the
|
tomwalters@0
|
99 * multiplier coefficients and initializes the states of the filter.
|
tomwalters@0
|
100 * It is called by function ``TLF_GenBank()'' in file ``bank_tl.c''
|
tomwalters@0
|
101 * once for each segment of the transmission line starting from the most
|
tomwalters@0
|
102 * apical segment. It returns a pointer to a structure containing all
|
tomwalters@0
|
103 * the relevant information for the computation of the current filter
|
tomwalters@0
|
104 * segment.
|
tomwalters@0
|
105 *
|
tomwalters@0
|
106 * Note: The code that sets up the WDF implementation of the outer ear
|
tomwalters@0
|
107 * and middle ear is located in file ``wdf_ear.c''.
|
tomwalters@0
|
108 ******************************************************************************************/
|
tomwalters@0
|
109
|
tomwalters@0
|
110 /************************************ WDFilterState() ************************************/
|
tomwalters@0
|
111
|
tomwalters@0
|
112 WDFilterState *WDFilter( samplerate, center_frequency, scale_vel, scale_disp, rho, scala_area,
|
tomwalters@0
|
113 width, qfactor, mass_per_area, seglength, Lt, warping, active, zov,
|
tomwalters@0
|
114 OHC_gain, OHC_sat )
|
tomwalters@0
|
115
|
tomwalters@0
|
116 double samplerate, center_frequency, scale_vel, scale_disp ;
|
tomwalters@0
|
117 double rho, scala_area, width, qfactor, mass_per_area, seglength, Lt ;
|
tomwalters@0
|
118 int warping, active ;
|
tomwalters@0
|
119 double *zov, OHC_gain, OHC_sat ;
|
tomwalters@0
|
120 {
|
tomwalters@0
|
121 static int apex = 1 ;
|
tomwalters@0
|
122 DeclareNew( WDFilterState *, filter_state ) ;
|
tomwalters@0
|
123 CoeffType *cf ;
|
tomwalters@0
|
124 double an, bn, mn, d, fs, fn ;
|
tomwalters@0
|
125 double Lsn, Ln, Cn, Rn ;
|
tomwalters@0
|
126 double r1, r2, r3, r4, g1, g2, g3, zn, zcn ;
|
tomwalters@0
|
127
|
tomwalters@0
|
128 /***** cochlear parameters for current BM segment *****/
|
tomwalters@0
|
129 an = scala_area ; /* cross-sectional area of each scala (cm2) */
|
tomwalters@0
|
130 bn = width ; /* BM width (cm) */
|
tomwalters@0
|
131 mn = mass_per_area ; /* transversal mass-per-area-of-BM (g/cm2) */
|
tomwalters@0
|
132 d = seglength ; /* BM segment length (cm) */
|
tomwalters@0
|
133
|
tomwalters@0
|
134 /***** frequency warping compensation due to bilinear transform *****/
|
tomwalters@0
|
135 fs = samplerate ;
|
tomwalters@0
|
136 if ( warping == 0 )
|
tomwalters@0
|
137 fn = center_frequency ;
|
tomwalters@0
|
138 else
|
tomwalters@0
|
139 fn = fs / Pi * tan( Pi * center_frequency / fs ) ;
|
tomwalters@0
|
140
|
tomwalters@0
|
141 /***** electrical circuit elements (CGS units) for current segment *****/
|
tomwalters@0
|
142 Ln = mn / ( bn * d ) ; /* shunt inductor */
|
tomwalters@0
|
143 Cn = 1. / ( ( TwoPi * TwoPi * fn * fn ) * Ln ) ; /* shunt capacitor */
|
tomwalters@0
|
144 Rn = sqrt( Ln / Cn ) / qfactor ; /* shunt resistor */
|
tomwalters@0
|
145 Lsn = ( 2. * rho * d ) / an ; /* series inductor */
|
tomwalters@0
|
146
|
tomwalters@0
|
147
|
tomwalters@0
|
148 /***** WDF multiplier coefficients for current TL segment *****/
|
tomwalters@0
|
149
|
tomwalters@0
|
150 /*** initialise filter coeffs ***/
|
tomwalters@0
|
151 filter_state->coeffs = ( char * ) NewZeroedArray( CoeffType, NUMBER_OF_COEFFS,
|
tomwalters@0
|
152 "wdf_tl.c for filter coeffs\n" ) ;
|
tomwalters@0
|
153 cf = ( CoeffType * ) filter_state->coeffs ;
|
tomwalters@0
|
154
|
tomwalters@0
|
155 /* Adaptor 25 */
|
tomwalters@0
|
156 r1 = zcn = 1. / (2. * fs * Cn ) ; /* Zcn */
|
tomwalters@0
|
157 r2 = Rn ; /* Zrn */
|
tomwalters@0
|
158 r3 = 2. * fs * Ln ; /* Zln */
|
tomwalters@0
|
159 r4 = zn = r1 + r2 + r3 ;
|
tomwalters@0
|
160 filter_state->gamma251 = r1 / r4 ;
|
tomwalters@0
|
161 filter_state->gamma252 = r2 / r4 ;
|
tomwalters@0
|
162
|
tomwalters@0
|
163 /* Adaptor 24 */
|
tomwalters@0
|
164 g1 = 1. / zn ;
|
tomwalters@0
|
165 if( apex ) {
|
tomwalters@0
|
166 g2 = 1. / ( 2. * fs * Lt ) ; /* (1 / Zlt) */
|
tomwalters@0
|
167 apex = 0 ;
|
tomwalters@0
|
168 }
|
tomwalters@0
|
169 else
|
tomwalters@0
|
170 g2 = 1. / *zov ; /* Zov (at the base) */
|
tomwalters@0
|
171 g3 = g1 + g2 ;
|
tomwalters@0
|
172 filter_state->gamma241 = g1 / g3 ;
|
tomwalters@0
|
173
|
tomwalters@0
|
174 /* Adaptor 23 */
|
tomwalters@0
|
175 r1 = 2. * fs * Lsn ; /* Zlsn */
|
tomwalters@0
|
176 r2 = 1. / g3 ;
|
tomwalters@0
|
177 r3 = *zov = r1 + r2 ; /* Zov */
|
tomwalters@0
|
178 filter_state->gamma231 = r1 / r3 ;
|
tomwalters@0
|
179
|
tomwalters@0
|
180 #ifdef _DEBUG_
|
tomwalters@0
|
181 fprintf( stderr, "gamma251=%f gamma252=%f\n", filter_state->gamma251
|
tomwalters@0
|
182 , filter_state->gamma252 ) ;
|
tomwalters@0
|
183 fprintf( stderr, "gamma241=%f \n", filter_state->gamma241 ) ;
|
tomwalters@0
|
184 fprintf( stderr, "gamma231=%f \n", filter_state->gamma231 ) ;
|
tomwalters@0
|
185 #endif
|
tomwalters@0
|
186
|
tomwalters@0
|
187 /***** scaling to convert output to transversal motion of BM segment *****/
|
tomwalters@0
|
188 filter_state->out_scale_disp = scale_disp * Cn / ( 2. * bn * d ) ;
|
tomwalters@0
|
189 filter_state->out_scale_vel = scale_vel / ( 2. * zcn * bn * d ) ;
|
tomwalters@0
|
190
|
tomwalters@0
|
191 /***** multiplier coefficients for OHC source *****/
|
tomwalters@0
|
192 filter_state->OHC_sat = OHC_sat * scale_disp / filter_state->out_scale_disp ;
|
tomwalters@0
|
193 filter_state->OHC_gain = - OHC_gain * Rn * filter_state->OHC_sat / ( 2. * zcn ) ;
|
tomwalters@0
|
194
|
tomwalters@0
|
195 #ifdef _BMCURVES_
|
tomwalters@0
|
196 /***** initialise rms detection *****/
|
tomwalters@0
|
197 filter_state->rms = 0.0 ;
|
tomwalters@0
|
198 filter_state->sample = 0 ;
|
tomwalters@0
|
199 #endif
|
tomwalters@0
|
200
|
tomwalters@0
|
201 /***** initialise filter states *****/
|
tomwalters@0
|
202 filter_state->states = ( char * ) NewZeroedArray( StateType, NUMBER_OF_STATES,
|
tomwalters@0
|
203 "wdf_tl.c for filter states\n" ) ;
|
tomwalters@0
|
204
|
tomwalters@0
|
205 /***** is channel active for display ? *****/
|
tomwalters@0
|
206 filter_state->active = active ;
|
tomwalters@0
|
207
|
tomwalters@0
|
208 /***** return *****/
|
tomwalters@0
|
209 return( filter_state ) ;
|
tomwalters@0
|
210 }
|
tomwalters@0
|
211
|
tomwalters@0
|
212
|
tomwalters@0
|
213 /*********************************** WDF procedures ***************************************
|
tomwalters@0
|
214 * name: function:
|
tomwalters@0
|
215 *
|
tomwalters@0
|
216 * DoWDFdataArray() WDF realization of the outer ear, middle ear and cochlear networks.
|
tomwalters@0
|
217 * It is called by function ``tlf_bank_callback()'' in file ``bank_tl.c''
|
tomwalters@0
|
218 * once for a specified number of input points. It computes the BM
|
tomwalters@0
|
219 * displacement or velocity for each segment and keeps track of the
|
tomwalters@0
|
220 * filter states.
|
tomwalters@0
|
221 *
|
tomwalters@0
|
222 * CloseWDF() Deletes all private data structures and arrays of the cochlear
|
tomwalters@0
|
223 * transmission line filter upon completion of filtering. It is called
|
tomwalters@0
|
224 * by function ``tlf_bank_callbank()'' in file ``bank_tl.c''.
|
tomwalters@0
|
225 ******************************************************************************************/
|
tomwalters@0
|
226
|
tomwalters@0
|
227 /********************************** DoWDFdataArray() **********************************/
|
tomwalters@0
|
228
|
tomwalters@0
|
229 void DoWDFdataArray( bankInfo, filter_states, input, output, points, channels,
|
tomwalters@0
|
230 ws, eartube_states, ms, tube_segments )
|
tomwalters@0
|
231 register TLF_BankInfo *bankInfo ;
|
tomwalters@0
|
232 register WDFilterState **filter_states ;
|
tomwalters@0
|
233 register DataType *input ;
|
tomwalters@0
|
234 register DataType *output ;
|
tomwalters@0
|
235 register int points, channels ;
|
tomwalters@0
|
236 register WaveWDFstate *ws ;
|
tomwalters@0
|
237 register EartubeWDFstate **eartube_states ;
|
tomwalters@0
|
238 register EarmiddleWDFstate *ms ;
|
tomwalters@0
|
239 register int tube_segments ;
|
tomwalters@0
|
240 {
|
tomwalters@0
|
241 register WDFilterState *fs ;
|
tomwalters@0
|
242 register EartubeWDFstate *ts ;
|
tomwalters@0
|
243 register StateType *st ;
|
tomwalters@0
|
244 register StateType dn, in, out ;
|
tomwalters@0
|
245 register StateType a0, an_1, b1, b2, b3, b63, b161, b202, b212 ;
|
tomwalters@0
|
246 static StateType bn = 0. ;
|
tomwalters@0
|
247 register CoeffType *cf ;
|
tomwalters@0
|
248 register int decimateCount = bankInfo->decimateCount ;
|
tomwalters@0
|
249 register int decimate_factor = bankInfo->decimate_factor ;
|
tomwalters@0
|
250 register int channelActive, pointActive, motion = bankInfo->output_var ;
|
tomwalters@0
|
251 register int channel = -1, tube_segment = -1 ;
|
tomwalters@0
|
252 #ifdef _BMCURVES_
|
tomwalters@0
|
253 static long sample = -1 ;
|
tomwalters@0
|
254 int period = 48 ; /* in samples */
|
tomwalters@0
|
255 double samplerate = 48000. ; /* samples per sec */
|
tomwalters@0
|
256 double rise_time = 2.0 ; /* sec */
|
tomwalters@0
|
257 double start_time = 4.0 ; /* sec */
|
tomwalters@0
|
258 #endif
|
tomwalters@0
|
259 #ifdef _IMPULSE_
|
tomwalters@0
|
260 static int impulse = 10000 ;
|
tomwalters@0
|
261 #endif
|
tomwalters@0
|
262
|
tomwalters@0
|
263 /***** update stapedial muscle state *****/
|
tomwalters@0
|
264
|
tomwalters@0
|
265 ( void ) ms->update_proc( ms ) ;
|
tomwalters@0
|
266
|
tomwalters@0
|
267 /***** for all points ******/
|
tomwalters@0
|
268
|
tomwalters@0
|
269 #ifdef _DEBUG_
|
tomwalters@0
|
270 fprintf( stderr, "DoWDFdataArray() = %d points X %d channels\n", points, channels ) ;
|
tomwalters@0
|
271 #endif
|
tomwalters@0
|
272
|
tomwalters@0
|
273 while( points-- > 0 ) {
|
tomwalters@0
|
274
|
tomwalters@0
|
275 if( decimateCount == decimate_factor )
|
tomwalters@0
|
276 decimateCount = 0 ;
|
tomwalters@0
|
277 pointActive = !decimateCount ;
|
tomwalters@0
|
278 decimateCount++ ;
|
tomwalters@0
|
279
|
tomwalters@0
|
280 output += bankInfo->output_chans * pointActive ;
|
tomwalters@0
|
281
|
tomwalters@0
|
282 /*** for all TL channels in BACKWARD direction for current input point ***/
|
tomwalters@0
|
283
|
tomwalters@0
|
284 while( ++channel < channels ) {
|
tomwalters@0
|
285
|
tomwalters@0
|
286 /* get states and coefficients */
|
tomwalters@0
|
287 fs = *filter_states++ ;
|
tomwalters@0
|
288 st = ( StateType * ) fs->states ;
|
tomwalters@0
|
289 cf = ( CoeffType * ) fs->coeffs ;
|
tomwalters@0
|
290
|
tomwalters@0
|
291 /* Adaptor 25 */
|
tomwalters@0
|
292 st[10] = st[1] ; /* a251 */
|
tomwalters@0
|
293 st[3] = st[2] - st[4] - st[1] ; /* b254 = a221 */
|
tomwalters@0
|
294
|
tomwalters@0
|
295 /* Adaptor 24 */
|
tomwalters@0
|
296 st[9] = bn ; /* -a242 */
|
tomwalters@0
|
297 st[5] = fs->gamma241 * ( st[3] + st[9] ) ; /* b240 */
|
tomwalters@0
|
298 st[6] = st[5] - st[9] ; /* b243 = a232 */
|
tomwalters@0
|
299
|
tomwalters@0
|
300 /* Adaptor 23 */
|
tomwalters@0
|
301 st[7] = st[8] - st[6] ; /* b233 */
|
tomwalters@0
|
302 bn = st[7] ;
|
tomwalters@0
|
303 }
|
tomwalters@0
|
304
|
tomwalters@0
|
305 /*** input point ***/
|
tomwalters@0
|
306
|
tomwalters@0
|
307 in = ( StateType ) *input++ ;
|
tomwalters@0
|
308
|
tomwalters@0
|
309 #ifdef _IMPULSE_
|
tomwalters@0
|
310 if( impulse != 0 ) {
|
tomwalters@0
|
311 in = ( StateType ) impulse ;
|
tomwalters@0
|
312 impulse = 0 ;
|
tomwalters@0
|
313 }
|
tomwalters@0
|
314 else
|
tomwalters@0
|
315 in = ( StateType ) 0 ;
|
tomwalters@0
|
316 #endif
|
tomwalters@0
|
317
|
tomwalters@0
|
318 #ifdef _BMCURVES_
|
tomwalters@0
|
319 if( ++sample < ( long ) ( samplerate * rise_time ) )
|
tomwalters@0
|
320 in = 0.28284 * ( double ) sample / ( samplerate * rise_time ) *
|
tomwalters@0
|
321 sin( TwoPi * ( double ) ( sample % period ) / ( double ) period ) ;
|
tomwalters@0
|
322 else
|
tomwalters@0
|
323 in = 0.28284 * sin( TwoPi * ( double ) ( sample % period ) / ( double ) period ) ;
|
tomwalters@0
|
324 #endif
|
tomwalters@0
|
325
|
tomwalters@0
|
326 /*** computation of outer and middle ear in FORWARD direction for current input point ***/
|
tomwalters@0
|
327
|
tomwalters@0
|
328 /* freefield - external ear */
|
tomwalters@0
|
329
|
tomwalters@0
|
330 /* get states */
|
tomwalters@0
|
331 st = ( StateType * ) ws->states ;
|
tomwalters@0
|
332
|
tomwalters@0
|
333 /* Adaptor 0 */
|
tomwalters@0
|
334 st[4] = ws->gamma01 * ( st[3] - in ) ; /* b00 */
|
tomwalters@0
|
335 st[5] = st[4] + in + in ; /* b03 = -a11 */
|
tomwalters@0
|
336
|
tomwalters@0
|
337 /* Adaptor 2 */
|
tomwalters@0
|
338 st[1] = -ws->gamma21 * st[0] ; /* b20 */
|
tomwalters@0
|
339 st[2] = st[1] ; /* b23 = a12 */
|
tomwalters@0
|
340
|
tomwalters@0
|
341 /* Adaptor 1 */
|
tomwalters@0
|
342 st[6] = st[5] - st[2] ; /* b13 = a32 */
|
tomwalters@0
|
343 an_1 = st[6] ;
|
tomwalters@0
|
344
|
tomwalters@0
|
345 /* concha and auditory canal */
|
tomwalters@0
|
346
|
tomwalters@0
|
347 while( ++tube_segment < tube_segments ) {
|
tomwalters@0
|
348
|
tomwalters@0
|
349 /* get states */
|
tomwalters@0
|
350 ts = *eartube_states++ ;
|
tomwalters@0
|
351 st = ( StateType * ) ts->states ;
|
tomwalters@0
|
352
|
tomwalters@0
|
353 /* Adaptor 3 */
|
tomwalters@0
|
354 st[3] = st[4] - an_1 ; /* b33 = a41 */
|
tomwalters@0
|
355
|
tomwalters@0
|
356 /* Adaptor 5 */
|
tomwalters@0
|
357 st[0] = -ts->gamma51 * st[1] ; /* b50 */
|
tomwalters@0
|
358 st[2] = st[0] + st[1] ; /* b53 = a42 */
|
tomwalters@0
|
359
|
tomwalters@0
|
360 /* Adaptor 4 */
|
tomwalters@0
|
361 st[5] = st[3] - st[2] ; /* -a42+a41 */
|
tomwalters@0
|
362 st[6] = ts->gamma41 * st[5] ; /* b40 */
|
tomwalters@0
|
363 st[7] = st[6] + st[2] ; /* b43 = a61 */
|
tomwalters@0
|
364
|
tomwalters@0
|
365 /* Adaptor 6 */
|
tomwalters@0
|
366 st[8] = st[9] - st[7] ; /* b63 = a32 */
|
tomwalters@0
|
367 an_1 = b63 = st[8] ;
|
tomwalters@0
|
368 }
|
tomwalters@0
|
369
|
tomwalters@0
|
370 /* middle ear */
|
tomwalters@0
|
371
|
tomwalters@0
|
372 /* get states */
|
tomwalters@0
|
373 st = ( StateType * ) ms->states ;
|
tomwalters@0
|
374
|
tomwalters@0
|
375 /* Adaptor 9 */
|
tomwalters@0
|
376 st[31] = st[30] - st[29] ; /* b94 = a81 */
|
tomwalters@0
|
377
|
tomwalters@0
|
378 /* Adaptor 8 */
|
tomwalters@0
|
379 st[32] = st[35] - st[31] ; /* a83-a81 */
|
tomwalters@0
|
380 st[33] = -ms->gamma81 * st[32] - ms->gamma82 * st[35] ; /* b80 */
|
tomwalters@0
|
381 st[34] = st[33] + st[35] ; /* b84 = a71 */
|
tomwalters@0
|
382
|
tomwalters@0
|
383 /* Adaptor 7 */
|
tomwalters@0
|
384 st[36] = -st[34] - an_1 ; /* b73 = a102 */
|
tomwalters@0
|
385
|
tomwalters@0
|
386 /* Adaptor 13 */
|
tomwalters@0
|
387 st[15] = -st[14] ; /* b133 = a122 */
|
tomwalters@0
|
388
|
tomwalters@0
|
389 /* Adaptor 12 */
|
tomwalters@0
|
390 st[16] = st[15] + st[18] ; /* a122-a121 */
|
tomwalters@0
|
391 st[17] = -ms->gamma121 * st[16] ; /* b120 */
|
tomwalters@0
|
392 st[19] = st[17] + st[15] ; /* b123 = a112 */
|
tomwalters@0
|
393
|
tomwalters@0
|
394 /* Adaptor 14 */
|
tomwalters@0
|
395 st[21] = -ms->gamma141 * st[20] ; /* b140 */
|
tomwalters@0
|
396 st[22] = st[21] + st[20] ; /* b143 = a111 */
|
tomwalters@0
|
397
|
tomwalters@0
|
398 /* Adaptor 15 */
|
tomwalters@0
|
399 st[23] = -st[24] ; /* b153 = a113 */
|
tomwalters@0
|
400
|
tomwalters@0
|
401 /* Adaptor 11 */
|
tomwalters@0
|
402 st[25] = -st[22] - st[19] - st[23] ; /* b114 = a101 */
|
tomwalters@0
|
403
|
tomwalters@0
|
404 /* Adaptor 10 */
|
tomwalters@0
|
405 st[26] = st[25] - st[36] ; /* -a102+a101 */
|
tomwalters@0
|
406 st[27] = ms->gamma101 * st[26] ; /* b100 */
|
tomwalters@0
|
407 st[28] = st[27] + st[36] ; /* b103 = a161 */
|
tomwalters@0
|
408
|
tomwalters@0
|
409 /* Adaptor 17 */
|
tomwalters@0
|
410 st[10] = st[12] - st[11] ; /* b174 = a162 */
|
tomwalters@0
|
411
|
tomwalters@0
|
412 /* Adaptor 16 */
|
tomwalters@0
|
413 st[13] = -st[28] - st[10] ; /* b163 = a181 */
|
tomwalters@0
|
414
|
tomwalters@0
|
415 /* Adaptor 19 */
|
tomwalters@0
|
416 st[5] = -st[6] ; /* b193 = a182 */
|
tomwalters@0
|
417
|
tomwalters@0
|
418 /* Adaptor 18 */
|
tomwalters@0
|
419 st[7] = st[13] - st[5] ; /* -a182+a181 */
|
tomwalters@0
|
420 st[8] = ms->gamma181 * st[7] ; /* b180 */
|
tomwalters@0
|
421 st[9] = st[8] + st[5] ; /* b183 = a203 */
|
tomwalters@0
|
422
|
tomwalters@0
|
423 /* Adaptor 20 */
|
tomwalters@0
|
424 st[40] = - bn / ms->ratio ; /* a202 */
|
tomwalters@0
|
425 st[3] = -st[40] - st[9] ; /* b204 = a212 */
|
tomwalters@0
|
426
|
tomwalters@0
|
427 /* Adaptor 21 */
|
tomwalters@0
|
428 st[0] = st[2] - st[1] - st[3] ; /* b214 = a222 */
|
tomwalters@0
|
429
|
tomwalters@0
|
430
|
tomwalters@0
|
431 /*** computation of outer and middle ear in BACKWARD direction for current input point ***/
|
tomwalters@0
|
432
|
tomwalters@0
|
433 /* middle ear */
|
tomwalters@0
|
434
|
tomwalters@0
|
435 /* Adaptor 22 */
|
tomwalters@0
|
436 a0 = st[4] + st[0] ; /* a220 */
|
tomwalters@0
|
437 st[4] = st[4] - ms->gamma221 * a0 ; /* b221 */
|
tomwalters@0
|
438 b2 = -st[4] - a0 ; /* b222 = a214 */
|
tomwalters@0
|
439
|
tomwalters@0
|
440 /* Adaptor 21 */
|
tomwalters@0
|
441 a0 = b2 - st[0] ; /* a210 */
|
tomwalters@0
|
442 st[1] = st[1] - ms->gamma211 * a0 ; /* b211 */
|
tomwalters@0
|
443 b212 = st[3] - ms->gamma212 * a0 ; /* b212 = a204 */
|
tomwalters@0
|
444 st[2] = -st[1] - b212 - b2 ; /* b213 */
|
tomwalters@0
|
445
|
tomwalters@0
|
446 /* Adaptor 20 */
|
tomwalters@0
|
447 a0 = b212 - st[3] ; /* a200 */
|
tomwalters@0
|
448 b202 = st[40] - ms->gamma202 * a0 ; /* b202 */
|
tomwalters@0
|
449 b3 = ms->gamma201 * a0 - b202 - b212 ; /* b203 = a183 */
|
tomwalters@0
|
450
|
tomwalters@0
|
451 /* Adaptor 18 */
|
tomwalters@0
|
452 b2 = st[8] + b3 ; /* b182 = a193 */
|
tomwalters@0
|
453 b1 = b2 - st[7] ; /* b181 = a163 */
|
tomwalters@0
|
454
|
tomwalters@0
|
455 /* Adaptor 19 */
|
tomwalters@0
|
456 st[6] = st[6] + ms->gamma191 * ( st[5] - b2 ) ; /* b191 */
|
tomwalters@0
|
457
|
tomwalters@0
|
458 /* Adaptor 16 */
|
tomwalters@0
|
459 b161 = st[28] + ms->gamma161 * ( st[13] - b1 ) ; /* b161 = a103 */
|
tomwalters@0
|
460 b2 = -b161 - b1 ; /* b162 = a174 */
|
tomwalters@0
|
461
|
tomwalters@0
|
462 /* Adaptor 17 */
|
tomwalters@0
|
463 a0 = b2 - st[10] ; /* a170 */
|
tomwalters@0
|
464 st[11] = st[11] - ms->gamma171 * a0 ; /* b171 */
|
tomwalters@0
|
465 st[12] = ms->gamma172 * a0 - b2 - st[11] ; /* b173 */
|
tomwalters@0
|
466
|
tomwalters@0
|
467 /* Adaptor 10 */
|
tomwalters@0
|
468 st[37] = st[27] + b161 ; /* b102 = a73 */
|
tomwalters@0
|
469 st[38] = st[37] - st[26] ; /* b101 = a114 */
|
tomwalters@0
|
470
|
tomwalters@0
|
471 /* Adaptor 11 */
|
tomwalters@0
|
472 a0 = st[38] - st[25] ; /* a110 */
|
tomwalters@0
|
473 b1 = st[22] - ms->gamma111 * a0 ; /* b111 = a143 */
|
tomwalters@0
|
474 b2 = st[19] - ms->gamma112 * a0 ; /* b112 = a123 */
|
tomwalters@0
|
475 b3 = -b1 -b2 - st[38] ; /* b113 = a153 */
|
tomwalters@0
|
476
|
tomwalters@0
|
477 /* Adaptor 15 */
|
tomwalters@0
|
478 st[24] = st[24] + ms->gamma151 * ( st[23] - b3 ) ; /* b151 */
|
tomwalters@0
|
479
|
tomwalters@0
|
480 /* Adaptor 14 */
|
tomwalters@0
|
481 st[20] = st[21] + b1 ; /* b142 */
|
tomwalters@0
|
482
|
tomwalters@0
|
483 /* Adaptor 12 */
|
tomwalters@0
|
484 b2 = st[17] + b2 ; /* b122 = a133 */
|
tomwalters@0
|
485 st[18] = b2 + st[16] ; /* b121 */
|
tomwalters@0
|
486
|
tomwalters@0
|
487 /* Adaptor 13 */
|
tomwalters@0
|
488 st[14] = st[14] + ms->gamma131 * ( st[15] - b2 ) ; /* b131 */
|
tomwalters@0
|
489
|
tomwalters@0
|
490 /* Adaptor 7 */
|
tomwalters@0
|
491 b1 = st[34] + ms->gamma71 * ( st[36] - st[37] ) ; /* b71 = a84 */
|
tomwalters@0
|
492 st[39] = -b1 - st[37] ; /* b72 = a63 */
|
tomwalters@0
|
493
|
tomwalters@0
|
494 /* Adaptor 8 */
|
tomwalters@0
|
495 st[35] = st[33] + b1 ; /* b83 */
|
tomwalters@0
|
496 b1 = st[35] + st[32] ; /* b81 = a94 */
|
tomwalters@0
|
497
|
tomwalters@0
|
498 /* Adaptor 9 */
|
tomwalters@0
|
499 a0 = b1 - st[31] ; /* a90 */
|
tomwalters@0
|
500 st[29] = st[29] - ms->gamma91 * a0 ; /* b91 */
|
tomwalters@0
|
501 st[30] = -st[29] + ms->gamma92 * a0 - b1 ; /* b93 */
|
tomwalters@0
|
502
|
tomwalters@0
|
503 bn = st[39] ;
|
tomwalters@0
|
504
|
tomwalters@0
|
505 /* concha and auditory canal */
|
tomwalters@0
|
506
|
tomwalters@0
|
507 while( tube_segment-- > 0 ) {
|
tomwalters@0
|
508
|
tomwalters@0
|
509 /* get states */
|
tomwalters@0
|
510 ts = *--eartube_states ;
|
tomwalters@0
|
511 st = ( StateType * ) ts->states ;
|
tomwalters@0
|
512
|
tomwalters@0
|
513 /* Adaptor 6 */
|
tomwalters@0
|
514 b1 = st[7] - ts->gamma61 * ( bn - st[8] ) ; /* b61 = a43 */
|
tomwalters@0
|
515 st[9] = -b1 - bn ; /* b62 */
|
tomwalters@0
|
516
|
tomwalters@0
|
517 /* Adaptor 4 */
|
tomwalters@0
|
518 b2 = st[6] + b1 ; /* b42 = a53 */
|
tomwalters@0
|
519 b1 = b2 - st[5] ; /* b41 = a33 */
|
tomwalters@0
|
520
|
tomwalters@0
|
521 /* Adaptor 5 */
|
tomwalters@0
|
522 st[1] = st[0] + b2 ; /* b52 */
|
tomwalters@0
|
523
|
tomwalters@0
|
524 /* Adaptor 3 */
|
tomwalters@0
|
525 st[4] = ts->gamma31 * ( st[3] - b1 ) - st[4] ; /* b31 */
|
tomwalters@0
|
526 bn = -st[4] - b1 ; /* b32 = a63 */
|
tomwalters@0
|
527 }
|
tomwalters@0
|
528
|
tomwalters@0
|
529 /* freefield - external ear */
|
tomwalters@0
|
530
|
tomwalters@0
|
531 /* get states */
|
tomwalters@0
|
532 st = ( StateType * ) ws->states ;
|
tomwalters@0
|
533
|
tomwalters@0
|
534 /* Adaptor 1 */
|
tomwalters@0
|
535 b1 = ws->gamma11 * ( st[6] - bn ) - st[5] ; /* b11 = -a03 */
|
tomwalters@0
|
536 b2 = -b1 - bn ; /* b12 = a23 */
|
tomwalters@0
|
537
|
tomwalters@0
|
538 /* Adaptor 2 */
|
tomwalters@0
|
539 st[0] = st[1] + b2 + st[0] ; /* b61 */
|
tomwalters@0
|
540
|
tomwalters@0
|
541 /* Adaptor 0 */
|
tomwalters@0
|
542 st[3] = b1 - st[4] + st[3] ; /* -b01 + p */
|
tomwalters@0
|
543
|
tomwalters@0
|
544 an_1 = - b202 * ms->ratio ;
|
tomwalters@0
|
545
|
tomwalters@0
|
546
|
tomwalters@0
|
547 /* for all channels in FORWARD direction for current input point */
|
tomwalters@0
|
548
|
tomwalters@0
|
549 while( channel-- > 0 ) {
|
tomwalters@0
|
550
|
tomwalters@0
|
551 /* get states and coefficients */
|
tomwalters@0
|
552 fs = *--filter_states ;
|
tomwalters@0
|
553 st = ( StateType * ) fs->states ;
|
tomwalters@0
|
554 cf = ( CoeffType * ) fs->coeffs ;
|
tomwalters@0
|
555 channelActive = fs->active ;
|
tomwalters@0
|
556
|
tomwalters@0
|
557 /* Adaptor 23 */
|
tomwalters@0
|
558 st[8] = fs->gamma231 * ( st[7] - an_1 ) - st[8] ; /* b231 */
|
tomwalters@0
|
559 b2 = an_1 + st[8] ; /* -b232 = -a243 */
|
tomwalters@0
|
560
|
tomwalters@0
|
561 /* Adaptor 24 */
|
tomwalters@0
|
562 an_1 = b2 - st[5] ; /* -b242 */
|
tomwalters@0
|
563 b1 = -an_1 - st[3] - st[9] ; /* b241 = a254 */
|
tomwalters@0
|
564
|
tomwalters@0
|
565 /* Adaptor 25 */
|
tomwalters@0
|
566 a0 = b1 - st[3] ; /* a250 */
|
tomwalters@0
|
567 st[1] = st[10] - fs->gamma251 * a0 ; /* b251 */
|
tomwalters@0
|
568 st[2] = fs->gamma252 * a0 - st[4] - st[1] - b1 ; /* b253 */
|
tomwalters@0
|
569 dn = st[1] + st[10] ;
|
tomwalters@0
|
570 in = st[1] - st[10] ;
|
tomwalters@0
|
571
|
tomwalters@0
|
572 /* output storage */
|
tomwalters@0
|
573 if( channelActive * pointActive ) {
|
tomwalters@0
|
574
|
tomwalters@0
|
575 if( motion == DISPLACEMENT )
|
tomwalters@0
|
576 out = fs->out_scale_disp * dn ;
|
tomwalters@0
|
577 else
|
tomwalters@0
|
578 out = fs->out_scale_vel * in ;
|
tomwalters@0
|
579 #ifdef _OVERFLOW_
|
tomwalters@0
|
580 if( out > _MaxOutput_ || out < _MinOutput_ )
|
tomwalters@0
|
581 fprintf( stderr, "Overflow error in BMM output=%e\n", ( double ) out ) ;
|
tomwalters@0
|
582 #endif
|
tomwalters@0
|
583 *(--output) = ( DataType ) ( out ) ;
|
tomwalters@0
|
584 }
|
tomwalters@0
|
585
|
tomwalters@0
|
586 /* OHC nonlinear voltage source */
|
tomwalters@0
|
587 if( dn < 0. )
|
tomwalters@0
|
588 dn = -dn ;
|
tomwalters@0
|
589 st[4] = fs->OHC_gain * in / ( fs->OHC_sat + dn ) ; /* -Vn(ohc) */
|
tomwalters@0
|
590
|
tomwalters@0
|
591 #ifdef _BMCURVES_
|
tomwalters@0
|
592 if( sample > ( long ) ( start_time * samplerate ) ) {
|
tomwalters@0
|
593 in = fs->out_scale_vel * in ;
|
tomwalters@0
|
594 fs->rms = fs->rms + in*in ;
|
tomwalters@0
|
595 fs->sample++ ;
|
tomwalters@0
|
596 }
|
tomwalters@0
|
597 #endif
|
tomwalters@0
|
598
|
tomwalters@0
|
599 }
|
tomwalters@0
|
600 bn = -an_1 ; /* apical boundary condition */
|
tomwalters@0
|
601 output += bankInfo->output_chans * pointActive ;
|
tomwalters@0
|
602
|
tomwalters@0
|
603 #ifdef _EAR_
|
tomwalters@0
|
604 st = ( StateType * ) ms->states ;
|
tomwalters@0
|
605 printf( "stapes=%e eardrum=%e\n", 0.5 * ( st[40] - b202 ), 0.5 * ( st[39] + b63 ) ) ;
|
tomwalters@0
|
606 #endif
|
tomwalters@0
|
607
|
tomwalters@0
|
608 }
|
tomwalters@0
|
609
|
tomwalters@0
|
610 return ;
|
tomwalters@0
|
611 }
|
tomwalters@0
|
612
|
tomwalters@0
|
613
|
tomwalters@0
|
614 /******************************* CloseWDF() *************************************/
|
tomwalters@0
|
615
|
tomwalters@0
|
616 void CloseWDF( states, channels, bank )
|
tomwalters@0
|
617 register WDFilterState **states ;
|
tomwalters@0
|
618 register int channels ;
|
tomwalters@0
|
619 register TLF_BankInfo *bank ;
|
tomwalters@0
|
620 {
|
tomwalters@0
|
621 int channel ;
|
tomwalters@0
|
622
|
tomwalters@0
|
623 for( channel = 0 ; channel < channels ; channel++ ) {
|
tomwalters@0
|
624 #ifdef _BMCURVES_
|
tomwalters@0
|
625 printf( "%d %e\n", channel+1, sqrt(states[channel]->rms / states[channel]->sample) ) ;
|
tomwalters@0
|
626 #endif
|
tomwalters@0
|
627 Delete( states[channel]->states ) ;
|
tomwalters@0
|
628 Delete( states[channel]->coeffs ) ;
|
tomwalters@0
|
629 }
|
tomwalters@0
|
630 Delete( states ) ;
|
tomwalters@0
|
631
|
tomwalters@0
|
632 Delete( bank ) ;
|
tomwalters@0
|
633
|
tomwalters@0
|
634 return ;
|
tomwalters@0
|
635
|
tomwalters@0
|
636 }
|
tomwalters@0
|
637
|