Mercurial > hg > aim92
comparison wdf/wdf_ear.c @ 0:5242703e91d3 tip
Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author | tomwalters |
---|---|
date | Fri, 20 May 2011 15:19:45 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5242703e91d3 |
---|---|
1 /* | |
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 | |
3 =========================================================================== | |
4 | |
5 Permission to use, copy, modify, and distribute this software without fee | |
6 is hereby granted for research purposes, provided that this copyright | |
7 notice appears in all copies and in all supporting documentation, and that | |
8 the software is not redistributed for any fee (except for a nominal shipping | |
9 charge). Anyone wanting to incorporate all or part of this software in a | |
10 commercial product must obtain a license from the Medical Research Council. | |
11 | |
12 The MRC makes no representations about the suitability of this | |
13 software for any purpose. It is provided "as is" without express or implied | |
14 warranty. | |
15 | |
16 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE | |
18 A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY | |
19 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
20 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 */ | |
23 | |
24 /* | |
25 Acknowledgment: | |
26 ============== | |
27 | |
28 The source code provided in this file was originally developed by | |
29 Christian Giguere as part of a Ph.D degree at the Department of | |
30 Engineering of the University of Cambridge from April 1990 to | |
31 November 1993. The code was subsequently adapted under a grant | |
32 from the Hearing Research Trust for full compatibility with | |
33 AIM Release 6.15. | |
34 | |
35 Christian Giguere 25/03/94 | |
36 | |
37 */ | |
38 | |
39 /* | |
40 =========================================================== | |
41 wdf_ear.c | |
42 =========================================================== | |
43 | |
44 Wave digital filter (WDF) implementation of the outer and | |
45 middle ear (EAR) electroacoustic networks. | |
46 | |
47 Author : Christian Giguere | |
48 First written : 01st June, 1991 | |
49 Last edited : 18th February, 1994 | |
50 | |
51 References: | |
52 (1) C.Giguere and P.C.Woodland (1992). Technical Report | |
53 CUED/F-INFENG/TR.93, University of Cambridge. | |
54 (2) C.Giguere and P.C.Woodland (1994). JASA 95(1): 331-342. | |
55 (3) M.E.Lutman and A.M.Martin (1979). J.Sound.Vib. 64(1): 133-157 | |
56 (4) A.Fettweis (1986). Proceedings IEEE 74(2): 270-327. | |
57 | |
58 Note: Ref (1) describes an implementation where the outer | |
59 ear and middle ear module is _UNCOUPLED_ to the cochlea. | |
60 In this case, the middle ear network is that of Lutman | |
61 and Martin (1979) unmodified. | |
62 | |
63 Ref (2) describes an implementation where the outer | |
64 ear and middle ear module is _COUPLED_ to the cochlea. | |
65 In this case, the middle ear network is a modified | |
66 version of Lutman and Martin (1979) network (See Fig.2) | |
67 =========================================================== | |
68 */ | |
69 | |
70 | |
71 /***** includes *****/ | |
72 | |
73 #include <math.h> | |
74 #include <stdio.h> | |
75 #include "stitch.h" | |
76 #include "calc.h" | |
77 #include "calc_tl.h" | |
78 #include "wdf_ear.h" | |
79 | |
80 /***** defines *****/ | |
81 | |
82 #define N_OF_FREEFIELD_STATES ( 12 ) | |
83 #define N_OF_EARTUBE_STATES ( 16 ) /* per segment */ | |
84 #define N_OF_EARMIDDLE_STATES ( 48 ) | |
85 | |
86 #if 0 | |
87 #define _DEBUG_ | |
88 #define _OVERFLOW_ | |
89 #endif | |
90 | |
91 #if 0 | |
92 #define _IMPULSE_ /* bypasses input wave with a delta impulse */ | |
93 #endif | |
94 | |
95 #if 0 | |
96 #define _EARDRUM_ /* outputs eardrum pressure instead of stapes velocity */ | |
97 #endif | |
98 | |
99 /* Middle ear circuit elements in CGS units (From Lutman and Martin (1979) */ | |
100 | |
101 #define La ( 14.0e-03 ) /* Middle ear cavities */ | |
102 #define Cp ( 5.1e-06 ) | |
103 #define Ra ( 10.0 ) | |
104 #define Rm ( 390.0 ) | |
105 #define Ct ( 0.35e-06 ) | |
106 #define Rd1 ( 200.0 ) /* Eardrum losses */ | |
107 #define Cd1 ( 0.8e-06 ) | |
108 #define Cd2 ( 0.4e-06 ) | |
109 #define Rd2 ( 220.0 ) | |
110 #define Ld ( 15.0e-03 ) | |
111 #define Rd3 ( 5900.0 ) | |
112 #define Cd3 ( 0.2e-06 ) | |
113 #define Lo ( 40.0e-03 ) /* Eardrum, mallus, incus */ | |
114 #define Co ( 1.4e-06 ) | |
115 #define Ro ( 70.0 ) | |
116 #define Cs ( 0.25e-06 ) /* Incudo-stapedial joint */ | |
117 #define Rs ( 3000.0 ) | |
118 #define Lc ( 45.0e-03 ) /* Stapes and cochlea */ | |
119 #define Cc ( 0.6e-06 ) | |
120 #define Rc ( 550.0 ) | |
121 | |
122 /* Additional middle ear circuit elements in CGS units (From Giguere and Woodland (1994) */ | |
123 | |
124 #define Ral ( 100.0 ) /* annular ligaments */ | |
125 #define Kst_max ( 1./0.1e-06 ) /* max. Stapedius stiffness */ | |
126 #define Kst_min_ratio ( 0.0001 ) /* min value of Kst_ratio */ | |
127 | |
128 | |
129 /***** external variables *****/ | |
130 | |
131 double Kst_ratio = Kst_min_ratio ; /* initial fraction of Kst_max */ | |
132 /* updated by feedback module */ | |
133 static double rn_1 ; | |
134 | |
135 | |
136 /***** functions *****/ | |
137 | |
138 /******************************* WDF set-up functions ************************************ | |
139 * name: function: | |
140 * | |
141 * FreefieldWDF() Set-up function for the WDF implementation of the external ear network | |
142 * (Giguere and Woodland, 1994, Figs. 1 and 8). It generates the multiplier | |
143 * coefficients and initializes the states of the filter. | |
144 * | |
145 * In the case of the _UNCOUPLED_ ear version, it is called by the | |
146 * function ``Ear()'' in file ``ear.c''. | |
147 * In the case of the _COUPLED_ ear version, it is called by the | |
148 * function ``TLF_GenBank()'' in file ``bank_tl.c''. | |
149 * | |
150 * It returns a pointer to a structure containing all the relevant | |
151 * information for the computation of the whole filter. | |
152 * | |
153 * EartubeWDF() Set-up function for the WDF implementation of the concha and auditory | |
154 * canal transmission lines (Giguere and Woodland, 1994, Figs. 1 and 8). | |
155 * It generates the multiplier coefficients and initializes the states | |
156 * of the filter. | |
157 * | |
158 * In the case of the _UNCOUPLED_ ear version, it is called by the | |
159 * function ``Ear()'' in file ``ear.c'' once for each segment of the | |
160 * transmission lines starting from the outermost segment. | |
161 * In the case of the _COUPLED_ ear version, it is called by the | |
162 * function ``TLF_GenBank()'' in file ``bank_tl.c'' once for each segment | |
163 * of the transmission lines starting from the outermost segment. | |
164 * | |
165 * It returns a pointer to a structure containing all the relevant | |
166 * information for the current filter segment. | |
167 * | |
168 * EarmiddleWDF() Set-up function for the WDF implementation of the middle ear network | |
169 * (Giguere and Woodland, 1994, Figs. 2 and 9). It generates the multiplier | |
170 * coefficients and initializes the states of the filter. | |
171 * | |
172 * In the case of the _UNCOUPLED_ ear version, it is called by the | |
173 * function ``Ear()'' in file ``ear.c''. | |
174 * In the case of the _COUPLED_ ear version, it is called by the | |
175 * function ``TLF_GenBank()'' in file ``bank_tl.c''. | |
176 * | |
177 * It returns a pointer to a structure containing all the relevant | |
178 * information for the computation of the whole filter. | |
179 ******************************************************************************************/ | |
180 | |
181 /************************** FreefieldWDF() *****************************/ | |
182 | |
183 WaveWDFstate *FreefieldWDF( samplerate, rho, velocity, diffraction_radius, radiation_radius ) | |
184 double samplerate ; | |
185 double rho, velocity ; | |
186 double diffraction_radius, radiation_radius ; | |
187 { | |
188 DeclareNew( WaveWDFstate *, filter_state ) ; | |
189 double fs2 ; | |
190 double r1, r2, r3, g1, g2, g3 ; | |
191 double zh, zr ; | |
192 double Lh, Rh, Lr, Rr ; | |
193 | |
194 /*** electrical circuit elements (CGS) ***/ | |
195 Rh = rho * velocity / ( Pi * diffraction_radius * diffraction_radius ) ; | |
196 Lh = 0.5 * rho / ( Pi * diffraction_radius ) ; | |
197 Rr = rho * velocity / ( Pi * radiation_radius * radiation_radius ) ; | |
198 Lr = 0.7 * rho / ( Pi * radiation_radius ) ; | |
199 | |
200 /*** sampling frequency ***/ | |
201 fs2 = samplerate * 2. ; | |
202 | |
203 /*** WDF-port resistances and multiplier coefficients ***/ | |
204 | |
205 /* Adaptor 0 */ | |
206 g1 = 1. / ( fs2 * Lh ) ; /* (1 / Zlh) */ | |
207 g2 = 1. / Rh ; /* (1 / Zrh) */ | |
208 g3 = g1 + g2 ; | |
209 zh = 1. / g3 ; | |
210 filter_state->gamma01 = g1 / g3 ; | |
211 | |
212 /* Adaptor 2 */ | |
213 g1 = 1. / ( fs2 * Lr ) ; /* (1 / Zlr) */ | |
214 g2 = 1. / Rr ; /* (1 / Zrr) */ | |
215 g3 = g1 + g2 ; | |
216 zr = 1. / g3 ; | |
217 filter_state->gamma21 = g1 / g3 ; | |
218 | |
219 /* Adaptor 1 */ | |
220 r1 = zh ; | |
221 r2 = zr ; | |
222 r3 = rn_1 = r1 + r2 ; | |
223 filter_state->gamma11 = r1 / r3 ; | |
224 | |
225 #ifdef _DEBUG_ | |
226 fprintf( stderr, "Rh=%e Lh=%e Rr=%e Lr=%e\n", Rh, Lh, Rr, Lr ) ; | |
227 fprintf( stderr, "gamma01=%f\n", filter_state->gamma01 ) ; | |
228 fprintf( stderr, "gamma11=%f\n", filter_state->gamma11 ) ; | |
229 fprintf( stderr, "gamma21=%f\n", filter_state->gamma21 ) ; | |
230 #endif | |
231 | |
232 /*** initialise filter states ***/ | |
233 filter_state->Nstates = N_OF_FREEFIELD_STATES ; | |
234 filter_state->states = ( char * ) NewZeroedArray( StateType, filter_state->Nstates, | |
235 "wdf_ear.c for freefield states\n" ) ; | |
236 | |
237 /*** return ***/ | |
238 return( filter_state ) ; | |
239 } | |
240 | |
241 /************************** EartubeWDF() *****************************/ | |
242 | |
243 EartubeWDFstate *EartubeWDF( samplerate, rho, velocity, diam, seglength, attn ) | |
244 double samplerate ; | |
245 double rho, velocity ; | |
246 double diam, seglength ; | |
247 double attn ; | |
248 { | |
249 DeclareNew( EartubeWDFstate *, filter_state ) ; | |
250 double an, d, c, k, alpha, fs2 ; | |
251 double Ln, Cn, Gn, Zn ; | |
252 double r1, r2, r3, g1, g2, g3, r33, g43, g53 ; | |
253 | |
254 /*** acoustic tube parameters for current segment ***/ | |
255 an = Pi * diam * diam / 4. ; /* cross-sectional area of tube (cm2) */ | |
256 d = seglength; /* length of tube (cm) */ | |
257 c = velocity ; /* sound velocity in air (cm/s) */ | |
258 alpha = attn ; /* attenuation constant of travelling waves (1/cm) */ | |
259 | |
260 /*** sampling frequency ***/ | |
261 fs2 = samplerate * 2. ; | |
262 | |
263 /*** electrical circuit elements (CGS units) for current segment ***/ | |
264 Ln = ( rho * d ) / an ; /* series inductor (either Lch or Lcl) */ | |
265 Cn = ( an * d ) / ( rho * c * c ) ; /* shunt capacitor (either Cch or Ccl) */ | |
266 Zn = sqrt( Ln / Cn ) ; /* characteristic impedance ( either Zch or Zcl) */ | |
267 Gn = 2. / Zn * alpha * d ; /* shunt conductance (either Gch or Gcl) */ | |
268 | |
269 /*** WDF multiplier coefficients for current tube segment ***/ | |
270 | |
271 /* Adaptor 3 */ | |
272 r1 = fs2 * Ln / 2. ; /* 0.5 Zl */ | |
273 r2 = rn_1 ; | |
274 r3 = r33 = r1 + r2 ; | |
275 filter_state->gamma31 = r1 / r3 ; | |
276 | |
277 /* Adaptor 5 */ | |
278 g1 = Gn ; /* (1 / Zg ) */ | |
279 g2 = fs2 * Cn ; /* (1 / Zc ) */ | |
280 g3 = g53 = g1 + g2 ; | |
281 filter_state->gamma51 = g1 / g3 ; | |
282 | |
283 /* Adaptor 4 */ | |
284 g1 = 1 / r33 ; | |
285 g2 = g53 ; | |
286 g3 = g43 = g1 + g2 ; | |
287 filter_state->gamma41 = g1 / g3 ; | |
288 | |
289 /* Adaptor 6 */ | |
290 r1 = 1 / g43 ; | |
291 r2 = fs2 * Ln / 2. ; /* 0.5 Zl */ | |
292 r3 = rn_1 = r1 + r2 ; | |
293 filter_state->gamma61 = r1 / r3 ; | |
294 | |
295 #ifdef _DEBUG_ | |
296 fprintf( stderr, "gamma31=%f ", filter_state->gamma31 ) ; | |
297 fprintf( stderr, "gamma41=%f ", filter_state->gamma41 ) ; | |
298 fprintf( stderr, "gamma51=%f ", filter_state->gamma51 ) ; | |
299 fprintf( stderr, "gamma61=%f\n", filter_state->gamma61 ) ; | |
300 #endif | |
301 | |
302 /*** initialise filter states ***/ | |
303 filter_state->Nstates = N_OF_EARTUBE_STATES ; | |
304 filter_state->states = ( char * ) NewZeroedArray( StateType, filter_state->Nstates, | |
305 "wdf_ear.c for earcanal states\n" ) ; | |
306 | |
307 /*** return ***/ | |
308 return( filter_state ) ; | |
309 } | |
310 | |
311 | |
312 /********************** EarmiddleWDF() ***************************/ | |
313 | |
314 EarmiddleWDFstate *EarmiddleWDF( samplerate, zov, output_scale, ratio ) | |
315 double samplerate, zov, output_scale, ratio ; | |
316 { | |
317 DeclareNew( EarmiddleWDFstate *, filter_state ) ; | |
318 double fs2 ; | |
319 double r1, r2, r3, r4, g1, g2, g3, g4 ; | |
320 double r73, r84, r94, r103, r114, r123, r133, r143, r153 ; | |
321 double r163, r174, r183, r193, r204, r214 ; | |
322 void update_earmiddle_init(), update_earmiddle() ; | |
323 | |
324 /*** sampling frequency ***/ | |
325 fs2 = samplerate * 2. ; | |
326 | |
327 /*** WDF-port resistances and multiplier coefficients ***/ | |
328 | |
329 /* Adaptor 9 */ | |
330 r1 = 1. / ( fs2 * Cp ) ; /* Zcp */ | |
331 r2 = Ra ; /* Zra */ | |
332 r3 = fs2 * La ; /* Zla */ | |
333 r4 = r94 = r1 + r2 + r3 ; | |
334 filter_state->gamma91 = r1 / r4 ; | |
335 filter_state->gamma92 = r2 / r4 ; | |
336 | |
337 /* Adaptor 8 */ | |
338 g1 = 1. / r94 ; | |
339 g2 = 1. / Rm ; /* (1 / Zrm) */ | |
340 g3 = fs2 * Ct ; /* (1 / Zct) */ | |
341 g4 = g1 + g2 + g3 ; | |
342 r84 = 1. /g4 ; | |
343 filter_state->gamma81 = g1 / g4 ; | |
344 filter_state->gamma82 = g2 / g4 ; | |
345 | |
346 /* Adaptor 7 */ | |
347 r1 = r84 ; | |
348 r2 = rn_1 ; | |
349 r3 = r73 = r1 + r2 ; | |
350 filter_state->gamma71 = r1 / r3 ; | |
351 | |
352 /* Adaptor 13 */ | |
353 r1 = 1. / ( fs2 * Cd2 ) ; /* Zcd2 */ | |
354 r2 = Rd2 ; /* Zrd2 */ | |
355 r3 = r133 = r1 + r2 ; | |
356 filter_state->gamma131 = r1 / r3 ; | |
357 | |
358 /* Adaptor 12 */ | |
359 g1 = 1. / ( fs2 * Ld ) ; /* (1 / Zld) */ | |
360 g2 = 1. / r133 ; | |
361 g3 = g1 + g2 ; | |
362 r123 = 1. / g3 ; | |
363 filter_state->gamma121 = g1 / g3 ; | |
364 | |
365 /* Adaptor 14 */ | |
366 g1 = 1. / Rd3 ; /* (1 / Zrd3) */ | |
367 g2 = fs2 * Cd3 ; /* (1 / Zcd3) */ | |
368 g3 = g1 + g2 ; | |
369 r143 = 1. / g3 ; | |
370 filter_state->gamma141 = g1 / g3 ; | |
371 | |
372 /* Adaptor 15 */ | |
373 r1 = 1. / ( fs2 * Cd1 ) ; /* Zcd1 */ | |
374 r2 = Rd1 ; /* Zrd1 */ | |
375 r3 = r153 = r1 + r2 ; | |
376 filter_state->gamma151 = r1 / r3 ; | |
377 | |
378 /* Adaptor 11 */ | |
379 r1 = r143 ; | |
380 r2 = r123 ; | |
381 r3 = r153 ; | |
382 r4 = r114 = r1 + r2 + r3 ; | |
383 filter_state->gamma111 = r1 / r4 ; | |
384 filter_state->gamma112 = r2 / r4 ; | |
385 | |
386 /* Adaptor 10 */ | |
387 g1 = 1. / r114 ; | |
388 g2 = 1. / r73 ; | |
389 g3 = g1 + g2 ; | |
390 r103 = 1. /g3 ; | |
391 filter_state->gamma101 = g1 / g3 ; | |
392 | |
393 /* Adaptor 17 */ | |
394 r1 = 1. / ( fs2 * Co ) ; /* Zco */ | |
395 r2 = Ro ; /* Zro */ | |
396 r3 = fs2 * Lo ; /* Zlo */ | |
397 r4 = r174 = r1 + r2 + r3 ; | |
398 filter_state->gamma171 = r1 / r4 ; | |
399 filter_state->gamma172 = r2 / r4 ; | |
400 | |
401 /* Adaptor 16 */ | |
402 r1 = r103 ; | |
403 r2 = r174 ; | |
404 r3 = r163 = r1 + r2 ; | |
405 filter_state->gamma161 = r1 / r3 ; | |
406 | |
407 /* Adaptor 19 */ | |
408 r1 = 1. / ( fs2 * Cs ) ; /* Zcs */ | |
409 r2 = Rs ; /* Zrs */ | |
410 r3 = r193 = r1 + r2 ; | |
411 filter_state->gamma191 = r1 / r3 ; | |
412 | |
413 /* Adaptor 18 */ | |
414 g1 = 1. / r163 ; | |
415 g2 = 1. / r193 ; | |
416 g3 = g1 + g2 ; | |
417 r183 = 1. / g3 ; | |
418 filter_state->gamma181 = g1 / g3 ; | |
419 | |
420 /* Adaptor 20 */ | |
421 #ifdef _DEBUG_ | |
422 fprintf( stderr, "Zov=%e\n", zov ) ; | |
423 #endif | |
424 if( zov != 0. ) { /* coupled version ? */ | |
425 r1 = Ral ; /* Zral */ | |
426 r2 = zov / ( ratio * ratio ) ; /* Zov / (r*r) */ | |
427 } | |
428 else { /* uncoupled version */ | |
429 r1 = 0.0 ; | |
430 r2 = Rc ; /* Zrc */ | |
431 } | |
432 r3 = r183 ; | |
433 r4 = r204 = r1 + r2 +r3 ; | |
434 filter_state->gamma201 = r1 / r4 ; | |
435 filter_state->gamma202 = r2 / r4 ; | |
436 filter_state->ratio = ratio ; | |
437 | |
438 /* Adaptor 21 */ | |
439 r1 = 1. / ( fs2 * Cc ) ; /* Zcc */ | |
440 r2 = r204 ; | |
441 if( zov != 0. ) /* coupled version ? */ | |
442 r3 = 0.0 ; | |
443 else /* uncoupled version */ | |
444 r3 = fs2 * Lc ; /* Zlc */ | |
445 r4 = r214 = r1 + r2 + r3 ; | |
446 filter_state->gamma211 = r1 / r4 ; | |
447 filter_state->gamma212 = r2 / r4 ; | |
448 | |
449 /* Adaptor 22 */ | |
450 r1 = Kst_ratio * Kst_max / fs2 ; /* Zcst (initial value only) */ | |
451 r2 = r214 ; | |
452 r3 = r1 + r2 ; | |
453 filter_state->gamma221 = 2. * r1 / r3 ; | |
454 | |
455 #ifdef _DEBUG_ | |
456 fprintf ( stderr, "gamma71 =%f \n", filter_state->gamma71 ) ; | |
457 fprintf ( stderr, "gamma81 =%f gamma82 =%f\n", filter_state->gamma81 | |
458 , filter_state->gamma82 ) ; | |
459 fprintf ( stderr, "gamma91 =%f gamma92 =%f\n", filter_state->gamma91 | |
460 , filter_state->gamma92 ) ; | |
461 fprintf ( stderr, "gamma101=%f \n", filter_state->gamma101 ) ; | |
462 fprintf ( stderr, "gamma111=%f gamma112=%f\n", filter_state->gamma111 | |
463 , filter_state->gamma112 ) ; | |
464 fprintf ( stderr, "gamma121=%f \n", filter_state->gamma121 ) ; | |
465 fprintf ( stderr, "gamma131=%f \n", filter_state->gamma131 ) ; | |
466 fprintf ( stderr, "gamma141=%f \n", filter_state->gamma141 ) ; | |
467 fprintf ( stderr, "gamma151=%f \n", filter_state->gamma151 ) ; | |
468 fprintf ( stderr, "gamma161=%f \n", filter_state->gamma161 ) ; | |
469 fprintf ( stderr, "gamma171=%f gamma172=%f\n", filter_state->gamma171 | |
470 , filter_state->gamma172 ) ; | |
471 fprintf ( stderr, "gamma181=%f \n", filter_state->gamma181 ) ; | |
472 fprintf ( stderr, "gamma191=%f \n", filter_state->gamma191 ) ; | |
473 fprintf ( stderr, "gamma201=%f gamma202=%f\n", filter_state->gamma201 | |
474 , filter_state->gamma202 ) ; | |
475 fprintf ( stderr, "gamma211=%f gamma212=%f\n", filter_state->gamma211 | |
476 , filter_state->gamma212 ) ; | |
477 fprintf ( stderr, "gamma221=%f \n", filter_state->gamma221 ) ; | |
478 #endif | |
479 | |
480 /*** specify and initialise coefficient update procedure ***/ | |
481 filter_state->update_proc = update_earmiddle ; | |
482 ( void ) update_earmiddle_init( fs2, r214 ) ; | |
483 | |
484 /*** output scaling ***/ | |
485 filter_state->out_scale = output_scale ; | |
486 | |
487 /*** initialise filter states ***/ | |
488 filter_state->Nstates = N_OF_EARMIDDLE_STATES ; | |
489 filter_state->states = ( char * ) NewZeroedArray( StateType, filter_state->Nstates, | |
490 "wdf_ear.c for middle ear states\n" ) ; | |
491 | |
492 /*** return ***/ | |
493 return( filter_state ) ; | |
494 } | |
495 | |
496 | |
497 /*********************************** WDF procedures *************************************** | |
498 * name: function: | |
499 * | |
500 * DoEarWDF() WDF realization of the _UNCOUPLED_ version of the outer ear and | |
501 * middle ear networks. It is called by function ``ear_callback()'' | |
502 * in file ``ear.c'' once for a specified number of input points. | |
503 * It computes the stapes velocity for each input point and keeps | |
504 * track of the filter states. | |
505 * | |
506 * Note: The code for the realization of the _COUPLED_ ear version | |
507 * is located in file ``wdf_tl.c''. | |
508 * | |
509 * | |
510 * CloseEarWDF() Deletes all private data structures and arrays of the outer and | |
511 * middle ear filter upon completion of filtering. | |
512 * In the case of the _UNCOUPLED_ ear version, it is called by the | |
513 * function ``ear_callback()'' in file ``ear.c''. | |
514 * In the case of the _COUPLED_ ear version, it is called by the | |
515 * function ``tlf_bank_callbank()'' in file ``bank_tl.c''. | |
516 ******************************************************************************************/ | |
517 | |
518 /******************************* DoEarWDF() **************************************/ | |
519 | |
520 void DoEarWDF( ws, eartube_states, ms, tube_segments, inout_ptr, points ) | |
521 register WaveWDFstate *ws ; | |
522 register EartubeWDFstate **eartube_states ; | |
523 register EarmiddleWDFstate *ms ; | |
524 register int tube_segments ; | |
525 register DataType *inout_ptr ; | |
526 register int points ; | |
527 { | |
528 register EartubeWDFstate *ts ; | |
529 register StateType *st, in, out ; | |
530 register StateType a0, an_1, b1, b2, b3, b161, b202, b212, bn ; | |
531 register int tube_segment = -1 ; | |
532 #ifdef _IMPULSE_ | |
533 static int impulse = 10000 ; | |
534 #endif | |
535 | |
536 | |
537 /***** update stapedial muscle state *****/ | |
538 | |
539 ( void ) ms->update_proc( ms ) ; | |
540 | |
541 /***** for all points *****/ | |
542 | |
543 while( points-- > 0 ) { | |
544 | |
545 /*** input point ***/ | |
546 | |
547 in = ( StateType ) *inout_ptr ; | |
548 | |
549 #ifdef _IMPULSE_ | |
550 if( impulse != 0 ) { | |
551 in = ( StateType ) impulse ; | |
552 impulse = 0 ; | |
553 } | |
554 else | |
555 in = ( StateType ) 0 ; | |
556 #endif | |
557 | |
558 /*** computation in FORWARD direction for current input point ***/ | |
559 | |
560 /* freefield - external ear */ | |
561 | |
562 /* get states */ | |
563 st = ( StateType * ) ws->states ; | |
564 | |
565 /* Adaptor 0 */ | |
566 st[4] = ws->gamma01 * ( st[3] - in ) ; /* b00 */ | |
567 st[5] = st[4] + in + in ; /* b03 = -a11 */ | |
568 | |
569 /* Adaptor 2 */ | |
570 st[1] = -ws->gamma21 * st[0] ; /* b20 */ | |
571 st[2] = st[1] ; /* b23 = a12 */ | |
572 | |
573 /* Adaptor 1 */ | |
574 st[6] = st[5] - st[2] ; /* b13 = a32 */ | |
575 an_1 = st[6] ; | |
576 | |
577 /* concha and auditory canal */ | |
578 | |
579 while( ++tube_segment < tube_segments ) { | |
580 | |
581 /* get states */ | |
582 ts = *eartube_states++ ; | |
583 st = ( StateType * ) ts->states ; | |
584 | |
585 /* Adaptor 3 */ | |
586 st[3] = st[4] - an_1 ; /* b33 = a41 */ | |
587 | |
588 /* Adaptor 5 */ | |
589 st[0] = -ts->gamma51 * st[1] ; /* b50 */ | |
590 st[2] = st[0] + st[1] ; /* b53 = a42 */ | |
591 | |
592 /* Adaptor 4 */ | |
593 st[5] = st[3] - st[2] ; /* -a42+a41 */ | |
594 st[6] = ts->gamma41 * st[5] ; /* b40 */ | |
595 st[7] = st[6] + st[2] ; /* b43 = a61 */ | |
596 | |
597 /* Adaptor 6 */ | |
598 st[8] = st[9] - st[7] ; /* b63 = a32 */ | |
599 an_1 = st[8] ; | |
600 } | |
601 | |
602 /* middle ear */ | |
603 | |
604 /* get states */ | |
605 st = ( StateType * ) ms->states ; | |
606 | |
607 /* Adaptor 9 */ | |
608 st[31] = st[30] - st[29] ; /* b94 = a81 */ | |
609 | |
610 /* Adaptor 8 */ | |
611 st[32] = st[35] - st[31] ; /* a83-a81 */ | |
612 st[33] = -ms->gamma81 * st[32] - ms->gamma82 * st[35] ; /* b80 */ | |
613 st[34] = st[33] + st[35] ; /* b84 = a71 */ | |
614 | |
615 /* Adaptor 7 */ | |
616 st[36] = -st[34] - an_1 ; /* b73 = a102 */ | |
617 | |
618 /* Adaptor 13 */ | |
619 st[15] = -st[14] ; /* b133 = a122 */ | |
620 | |
621 /* Adaptor 12 */ | |
622 st[16] = st[15] + st[18] ; /* a122-a121 */ | |
623 st[17] = -ms->gamma121 * st[16] ; /* b120 */ | |
624 st[19] = st[17] + st[15] ; /* b123 = a112 */ | |
625 | |
626 /* Adaptor 14 */ | |
627 st[21] = -ms->gamma141 * st[20] ; /* b140 */ | |
628 st[22] = st[21] + st[20] ; /* b143 = a111 */ | |
629 | |
630 /* Adaptor 15 */ | |
631 st[23] = -st[24] ; /* b153 = a113 */ | |
632 | |
633 /* Adaptor 11 */ | |
634 st[25] = -st[22] - st[19] - st[23] ; /* b114 = a101 */ | |
635 | |
636 /* Adaptor 10 */ | |
637 st[26] = st[25] - st[36] ; /* -a102+a101 */ | |
638 st[27] = ms->gamma101 * st[26] ; /* b100 */ | |
639 st[28] = st[27] + st[36] ; /* b103 = a161 */ | |
640 | |
641 /* Adaptor 17 */ | |
642 st[10] = st[12] - st[11] ; /* b174 = a162 */ | |
643 | |
644 /* Adaptor 16 */ | |
645 st[13] = -st[28] - st[10] ; /* b163 = a181 */ | |
646 | |
647 /* Adaptor 19 */ | |
648 st[5] = -st[6] ; /* b193 = a182 */ | |
649 | |
650 /* Adaptor 18 */ | |
651 st[7] = st[13] - st[5] ; /* -a182+a181 */ | |
652 st[8] = ms->gamma181 * st[7] ; /* b180 */ | |
653 st[9] = st[8] + st[5] ; /* b183 = a203 */ | |
654 | |
655 /* Adaptor 20 */ | |
656 st[3] = -st[9] ; /* b204 = a212 */ | |
657 | |
658 /* Adaptor 21 */ | |
659 st[0] = st[2] - st[1] - st[3] ; /* b214 = a222 */ | |
660 | |
661 | |
662 /*** computation in BACKWARD direction for current input point ***/ | |
663 | |
664 /* middle ear */ | |
665 | |
666 /* Adaptor 22 */ | |
667 a0 = st[4] + st[0] ; /* a220 */ | |
668 st[4] = st[4] - ms->gamma221 * a0 ; /* b221 */ | |
669 b2 = -st[4] - a0 ; /* b222 = a214 */ | |
670 | |
671 /* Adaptor 21 */ | |
672 a0 = b2 - st[0] ; /* a210 */ | |
673 st[1] = st[1] - ms->gamma211 * a0 ; /* b211 */ | |
674 b212 = st[3] - ms->gamma212 * a0 ; /* b212 = a204 */ | |
675 st[2] = -st[1] - b212 - b2 ; /* b213 */ | |
676 | |
677 /* Adaptor 20 */ | |
678 a0 = b212 - st[3] ; /* a200 */ | |
679 b202 = - ms->gamma202 * a0 ; /* b202 */ | |
680 b3 = ms->gamma201 * a0 - b202 - b212 ; /* b203 = a183 */ | |
681 | |
682 /* Adaptor 18 */ | |
683 b2 = st[8] + b3 ; /* b182 = a193 */ | |
684 b1 = b2 - st[7] ; /* b181 = a163 */ | |
685 | |
686 /* Adaptor 19 */ | |
687 st[6] = st[6] + ms->gamma191 * ( st[5] - b2 ) ; /* b191 */ | |
688 | |
689 /* Adaptor 16 */ | |
690 b161 = st[28] + ms->gamma161 * ( st[13] - b1 ) ; /* b161 = a103 */ | |
691 b2 = -b161 - b1 ; /* b162 = a174 */ | |
692 | |
693 /* Adaptor 17 */ | |
694 a0 = b2 - st[10] ; /* a170 */ | |
695 st[11] = st[11] - ms->gamma171 * a0 ; /* b171 */ | |
696 st[12] = ms->gamma172 * a0 - b2 - st[11] ; /* b173 */ | |
697 | |
698 /* Adaptor 10 */ | |
699 st[37] = st[27] + b161 ; /* b102 = a73 */ | |
700 st[38] = st[37] - st[26] ; /* b101 = a114 */ | |
701 | |
702 /* Adaptor 11 */ | |
703 a0 = st[38] - st[25] ; /* a110 */ | |
704 b1 = st[22] - ms->gamma111 * a0 ; /* b111 = a143 */ | |
705 b2 = st[19] - ms->gamma112 * a0 ; /* b112 = a123 */ | |
706 b3 = -b1 -b2 - st[38] ; /* b113 = a153 */ | |
707 | |
708 /* Adaptor 15 */ | |
709 st[24] = st[24] + ms->gamma151 * ( st[23] - b3 ) ; /* b151 */ | |
710 | |
711 /* Adaptor 14 */ | |
712 st[20] = st[21] + b1 ; /* b142 */ | |
713 | |
714 /* Adaptor 12 */ | |
715 b2 = st[17] + b2 ; /* b122 = a133 */ | |
716 st[18] = b2 + st[16] ; /* b121 */ | |
717 | |
718 /* Adaptor 13 */ | |
719 st[14] = st[14] + ms->gamma131 * ( st[15] - b2 ) ; /* b131 */ | |
720 | |
721 /* Adaptor 7 */ | |
722 b1 = st[34] + ms->gamma71 * ( st[36] - st[37] ) ; /* b71 = a84 */ | |
723 st[39] = -b1 - st[37] ; /* b72 = a63 */ | |
724 | |
725 /* Adaptor 8 */ | |
726 st[35] = st[33] + b1 ; /* b83 */ | |
727 b1 = st[35] + st[32] ; /* b81 = a94 */ | |
728 | |
729 /* Adaptor 9 */ | |
730 a0 = b1 - st[31] ; /* a90 */ | |
731 st[29] = st[29] - ms->gamma91 * a0 ; /* b91 */ | |
732 st[30] = -st[29] + ms->gamma92 * a0 - b1 ; /* b93 */ | |
733 | |
734 bn = st[39] ; | |
735 | |
736 /* concha and auditory canal */ | |
737 | |
738 while( tube_segment-- > 0 ) { | |
739 | |
740 /* get states */ | |
741 ts = *--eartube_states ; | |
742 st = ( StateType * ) ts->states ; | |
743 | |
744 /* Adaptor 6 */ | |
745 b1 = st[7] - ts->gamma61 * ( bn - st[8] ) ; /* b61 = a43 */ | |
746 st[9] = -b1 - bn ; /* b62 */ | |
747 | |
748 /* Adaptor 4 */ | |
749 b2 = st[6] + b1 ; /* b42 = a53 */ | |
750 b1 = b2 - st[5] ; /* b41 = a33 */ | |
751 | |
752 /* Adaptor 5 */ | |
753 st[1] = st[0] + b2 ; /* b52 */ | |
754 | |
755 /* Adaptor 3 */ | |
756 st[4] = ts->gamma31 * ( st[3] - b1 ) - st[4] ; /* b31 */ | |
757 bn = -st[4] - b1 ; /* b32 = a63 */ | |
758 } | |
759 | |
760 /* freefield - external ear */ | |
761 | |
762 /* get states */ | |
763 st = ( StateType * ) ws->states ; | |
764 | |
765 /* Adaptor 1 */ | |
766 b1 = ws->gamma11 * ( st[6] - bn ) - st[5] ; /* b11 = -a03 */ | |
767 b2 = -b1 - bn ; /* b12 = a23 */ | |
768 | |
769 /* Adaptor 2 */ | |
770 st[0] = st[1] + b2 + st[0] ; /* b61 */ | |
771 | |
772 /* Adaptor 0 */ | |
773 st[3] = b1 - st[4] + st[3] ; /* -b01 + p */ | |
774 | |
775 /*** output ***/ | |
776 #ifdef _EARDRUM_ | |
777 st = ( StateType * ) ms->states ; | |
778 out = 0.5 * ( st[39] + an_1 ) * ms->out_scale ; | |
779 #else | |
780 out = -0.5 * b202 * ms->out_scale ; | |
781 #endif | |
782 | |
783 #ifdef _OVERFLOW_ | |
784 if( out > _MaxOutput_ || out < _MinOutput_ ) | |
785 fprintf( stderr, "Overflow error in Outer/Middle ear output=%e\n", ( double ) out ) ; | |
786 #endif | |
787 *inout_ptr++ = out ; | |
788 | |
789 } | |
790 return ; | |
791 } | |
792 | |
793 | |
794 /******************************* CloseEarWDF() *************************************/ | |
795 | |
796 void CloseEarWDF( wave_states, eartube_states, earmiddle_states, tube_segments ) | |
797 register WaveWDFstate *wave_states ; | |
798 register EartubeWDFstate **eartube_states ; | |
799 register EarmiddleWDFstate *earmiddle_states ; | |
800 register int tube_segments ; | |
801 { | |
802 Delete( earmiddle_states->states ) ; | |
803 Delete( earmiddle_states ) ; | |
804 | |
805 for( ; --tube_segments < 0 ; ) { | |
806 Delete( eartube_states[ tube_segments ]->states ) ; | |
807 Delete( eartube_states[ tube_segments ] ) ; | |
808 } | |
809 Delete( eartube_states ) ; | |
810 | |
811 Delete( wave_states->states ) ; | |
812 Delete( wave_states ) ; | |
813 | |
814 return ; | |
815 | |
816 } | |
817 | |
818 /************** low level functions **************/ | |
819 | |
820 static double den221 ; | |
821 static double Kst_old_ratio ; | |
822 | |
823 void update_earmiddle_init( rate, z ) | |
824 double rate, z ; | |
825 { | |
826 Kst_old_ratio = Kst_ratio ; | |
827 den221 = rate * z / Kst_max ; | |
828 return ; | |
829 } | |
830 | |
831 void update_earmiddle( ms ) | |
832 EarmiddleWDFstate *ms ; | |
833 { | |
834 if( Kst_ratio < Kst_min_ratio ) | |
835 Kst_ratio = Kst_min_ratio ; | |
836 | |
837 ms->gamma221 = 2. * Kst_ratio / ( Kst_ratio + den221 ) ; | |
838 ms->states[4] = ms->states[4] * Kst_ratio / Kst_old_ratio ; | |
839 | |
840 Kst_old_ratio = Kst_ratio ; | |
841 | |
842 return ; | |
843 } | |
844 |