annotate wdf/wdf_tl.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
rev   line source
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