comparison wdf/meddis.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 meddis.c
42 ===========================================================
43
44 Implementation of Ray Meddis haircell model.
45
46 Author : Christian Giguere
47 First written : 10th September, 1991
48 Last edited : 07th March, 1994
49
50 References:
51 (1) C.Giguere and P.C.Woodland (1994). JASA 95(1): 331-342.
52 (2) R.Meddis et al. (1990). JASA 87(4): 1813-1816.
53 (3) R.Meddis (1988). JASA 83(3): 1056-1063.
54
55 Note - This is a complete re-write of the original file
56 "haircell.c" Release 3 (20th September 1988) from
57 J. Holdsworth and the Applied Psychology Unit.
58 ============================================================
59 */
60
61
62 /***** includes *****/
63
64 #include <math.h>
65 #include <stdio.h>
66 #include "stitch.h"
67 #include "source.h"
68 #include "calc.h"
69 #include "calc_tl.h"
70 #include "meddis.h"
71
72
73 /***** defines *****/
74
75 #if 0
76 #define _DEBUG_
77 #define _OVERFLOW_
78 #endif
79
80 #if 1 /* define numerical implementation */
81 #define _WDF_ /* Giguere and Woodland (1994) */
82 #else
83 #define _FORWARD_DIFFERENCE_ /* Meddis et al. (1990) */
84 #endif
85
86 #if 0
87 #define _CLAMPING_ /* clamping of reservoirs */
88 #endif
89
90 #define NUMBER_OF_COEFFS ( 12 )
91 #define NUMBER_OF_STATES ( 12 )
92
93
94 /* Feedback parameter */
95
96 #define InputGain_max ( 24.0 ) /* max coupling gain in dB */
97
98
99 /* Meddis et al. (1990) model parameters */
100
101 #define A_medium ( 10.0 ) /* medium-spontaneous rate fibre */
102 #define B_medium ( 3000.0 )
103 #define g_medium ( 1000.0 )
104
105 #define A_high ( 5.0 ) /* high-spontaneous rate fibre */
106 #define B_high ( 300.0 )
107 #define g_high ( 2000.0 )
108
109 #define y_value ( 5.05 ) /* replenishment rate */
110 #define l_value ( 2500 ) /* rate of loss from the cleft */
111 #define r_value ( 6580 ) /* rate of return from the cleft */
112 #define x_value ( 66.31 ) /* rate of release from w store */
113 #define m_value ( 1.0 ) /* max number of quanta */
114 #define h_value ( 50000. ) /* firing-rate factor */
115
116
117 /***** private data structures *****/
118
119 typedef struct _haircell_info HaircellInfo ;
120 typedef struct _haircell_bank HaircellBank ;
121
122 struct _haircell_info {
123 int number_of_states ;
124 double output_gain ;
125 StateType *states ;
126 } ;
127
128 struct _haircell_bank {
129 int channels ;
130 double *inputGain_ratio ;
131 double (*update_proc)() ; /* procedure to update cells input gain */
132 int number_of_coeffs ;
133 CoeffType *coeffs ;
134 HaircellInfo **cells ;
135 } ;
136
137
138 /***** external variables *****/
139
140 double *InputGain_ratio ;
141
142
143 /***** functions *****/
144
145 /*******************************************************************************
146 * name: function:
147 *
148 * NewHaircells() Set-up function for the implementation of a bank of inner
149 * haircells based on the model of Ray Meddis. It generates the
150 * multiplier coefficients for each haircell filter and
151 * initializes the filter states. It is called by function
152 * ``Meddis()'' in file ``model.c''. It returns a pointer to a
153 * structure containing all the relevant information for the
154 * computation of the haircell filters.
155 *
156 * The choice of the haircell type (medium or high-spontaneous
157 * rate fibre) is made at run time using options ``fibre_med''.
158 *
159 * The choice of the numerical implementation (Wave Digital
160 * Filtering or Forward Difference algorithm) is made at
161 * compile time using a macro substitution ``#define'' (see above).
162 *
163 * The choice of clamping the reservoirs' contents to non-
164 * negative values is made at compile time using a macro
165 * substitution ``#define'' (see above).
166 *
167 * DoHaircells() Realization of the bank of haircell filters. It computes the
168 * output for each haircell for a specified number of input
169 * points and keeps track of the filters' states. It returns
170 * the size of the output data in bytes (per point).
171 *
172 * CloseHaircells() Deletes all private data structures and arrays of the Haircell
173 * filters upon comletion of filtering.
174 ********************************************************************************/
175
176
177 /*************************** NewHaircells() *********************************/
178
179 Pointer NewHaircells( channels, samplerate, output_gain, coupling, fibreType )
180 int channels ;
181 double samplerate, output_gain ;
182 double coupling ;
183 char *fibreType ;
184 {
185 DeclareNew( HaircellBank *, bank ) ;
186 HaircellInfo *cell_info ;
187 CoeffType *cf ;
188 StateType *st ;
189 double ydt, ldt, rdt, xdt, gdt ;
190 double kdt_init, q_init, c_init, w_init, cell_scaling ;
191 double A_value, B_value, g_value ;
192 double r1, r2, r3, r4, r03 ;
193 double update_inputGain() ;
194 int channel ;
195
196 /*** scaling of input data ***/
197 cell_scaling = coupling ;
198
199 /*** allocate fibre-dependent haircell parameters ***/
200 if( strncmp( fibreType, "high", 3 ) == 0 ) {
201 A_value = A_high ;
202 B_value = B_high ;
203 g_value = g_high ;
204 }
205 else {
206 A_value = A_medium ;
207 B_value = B_medium ;
208 g_value = g_medium ;
209 }
210
211 #ifdef _DEBUG_
212 fprintf( stderr, "Meddis Haircell fibre type=%s\n", fibreType ) ;
213 fprintf( stderr, "A=%.2f B=%.2f g=%.2f\n", A_value, B_value, g_value ) ;
214 fprintf( stderr, "Input scaling factor=%.4f\n", cell_scaling ) ;
215 #endif
216
217
218 /*** scale model parameters for difference equations ***/
219 ydt = y_value / samplerate ;
220 ldt = l_value / samplerate ;
221 rdt = r_value / samplerate ;
222 xdt = x_value / samplerate ;
223 gdt = g_value / samplerate ;
224
225
226 /*** calculate initial values for infinite history of silence ***/
227 kdt_init = gdt * A_value / ( A_value + B_value ) ;
228 q_init = m_value / ( 1. + kdt_init / ydt * ( 1. - rdt / ( ldt + rdt ) ) ) ;
229 c_init = q_init * kdt_init / ( ldt + rdt ) ;
230 w_init = rdt / xdt * c_init ;
231
232
233 /*** allocate and store multiplier coefficients ***/
234 bank->number_of_coeffs = NUMBER_OF_COEFFS ;
235 cf = bank->coeffs = NewArray( CoeffType, bank->number_of_coeffs,
236 "haircell_tl.c for coefficients" ) ;
237 #ifdef _WDF_
238 output_gain = MEDDIS_SCALE * output_gain * h_value / ( 2. * r_value ) ;
239 cf[0] = m_value * y_value * output_gain ; /* M/Zy (normalized) */
240 cf[1] = A_value / cell_scaling ;
241 cf[2] = ( A_value + B_value ) / cell_scaling ;
242 cf[3] = g_value ;
243
244 /* Adaptor B0 */
245 r1 = y_value ; /* ( 1/Zy ) */
246 r2 = 2. * samplerate ; /* ( 1/Zcq ) */
247 r3 = r03 = r1 + r2 ;
248 cf[5] = r1 / r3 ; /* gamma01 */
249 cf[4] = r3 / cf[3] ; /* needed to update gamma11 */
250
251 /* Adaptor B1*/
252 r1 = kdt_init * samplerate ; /* ( 1/Zk ) initial value only */
253 r2 = r03 ;
254 r3 = r1 + r2 ;
255 cf[6] = 2. * r1 / r3 ; /* gamma11 updated at each sample */
256
257 /* Adaptor B2 */
258 r1 = l_value ; /* ( 1/Zl ) */
259 r2 = r_value ; /* ( 1/Zr ) */
260 r3 = 2. * samplerate ; /* ( 1/Zcc ) */
261 r4 = r1 + r2 + r3 ;
262 cf[7] = r1 / r4 ; /* gamma21 */
263 cf[8] = r2 / r4 ; /* gamma22 */
264
265 /* Adaptor B3 */
266 r1 = x_value ; /* ( 1/Zx ) */
267 r2 = 2. * samplerate ; /* ( 1/Zcw ) */
268 r3 = r1 + r2 ;
269 cf[9] = 0.5 * r1 / r3 ; /* 0.5 * gamma31 */
270
271 #else
272 output_gain = MEDDIS_SCALE * output_gain * h_value ;
273 cf[0] = m_value * output_gain ;
274 cf[1] = A_value / cell_scaling ;
275 cf[2] = ( A_value + B_value ) / cell_scaling ;
276 cf[3] = gdt ;
277 cf[4] = ydt ;
278 cf[5] = ldt ;
279 cf[6] = rdt ;
280 cf[7] = xdt ;
281 #endif
282
283
284 /*** loop through each haircell ***/
285 bank->channels = channels ;
286 bank->cells = NewArray( HaircellInfo *, bank->channels, "haircell.c for cell states" ) ;
287 bank->inputGain_ratio = InputGain_ratio = NewArray( double, bank->channels,
288 "haircell_tl.c for cells input gain ratio" ) ;
289 bank->update_proc = update_inputGain ;
290
291 for( channel = 0 ; channel < bank->channels ; channel++ ) {
292 bank->inputGain_ratio[ channel ] = 0.5 ; /* in absence of feedback, Gain = 1 */
293 cell_info = bank->cells[ channel ] = New( HaircellInfo * ) ;
294
295 /*** allocate and initialise states ***/
296 cell_info->number_of_states = NUMBER_OF_STATES ;
297 st = cell_info->states = NewZeroedArray( StateType, cell_info->number_of_states,
298 "haircell_tl.c for states" ) ;
299
300 #ifdef _WDF_
301 st[1] = x_value * w_init * output_gain ; /* Ixn (normalized) */
302 st[2] = 2. * q_init * samplerate * output_gain ; /* Ixn(t-T)-b02 (normalized) */
303 st[3] = -2. * c_init * samplerate * output_gain ; /* b23 (normalized) */
304 st[4] = -2. * w_init * samplerate * output_gain ; /* b33 (normalized) */
305 cell_info->output_gain = output_gain ; /* obsolete */
306
307 #else
308 st[0] = kdt_init ;
309 st[1] = q_init * output_gain ;
310 st[2] = c_init * output_gain ;
311 st[3] = w_init * output_gain ;
312 cell_info->output_gain = output_gain ; /* obsolete */
313 #endif
314
315 }
316
317 return( ( Pointer ) bank ) ;
318 }
319
320
321 /************************** DoHaircells() *********************************/
322
323 int DoHaircells( bank_ptr, bytes, output_ptr, end_output_ptr, input_ptr )
324 Pointer *bank_ptr ;
325 ByteCount *bytes ;
326 DataType *output_ptr, *end_output_ptr, *input_ptr ;
327 {
328 register HaircellBank *bank = ( HaircellBank * ) bank_ptr ;
329 register HaircellInfo *cell_info ;
330 register DataType *input, *output ;
331 register StateType *st ;
332 register StateType in, out ;
333 register CoeffType *cf ;
334 register double inputGain ;
335 register int channel = bank->channels ;
336 register int point, npoints = ( end_output_ptr - output_ptr ) / bank->channels ;
337 #ifdef _WDF_
338 register StateType an, a0 ;
339 #else
340 register StateType replenish, eject, loss, reuptake, reprocess ;
341 #endif
342
343 /*** for all channels ***/
344
345 #ifdef _DEBUG_
346 fprintf( stderr, "DoHaircells() = %d points X %d channels\n", npoints, bank->channels ) ;
347 #endif
348
349 cf = bank->coeffs ;
350
351 while( channel-- ) {
352
353 cell_info = bank->cells[ channel ] ;
354 st = cell_info->states ;
355 input = input_ptr + channel ;
356 output = output_ptr + channel ;
357 inputGain = bank->update_proc( bank->inputGain_ratio[ channel ] ) ;
358 cf[10] = cf[1] / inputGain ; /* (A/p) */
359 cf[11] = cf[2] / inputGain ; /* (A+B)/p */
360
361 /*** for each channel ***/
362
363 point = npoints ;
364 while( point-- ) {
365
366 #ifdef _WDF_
367 /*** compute compressive permeability function k ***/
368 in = ( StateType ) *input ; /* (BM vibration) */
369 if( in > -cf[10] )
370 st[0] = ( in + cf[10] ) / ( in + cf[11] ) ; /* kn(t) / g */
371 else
372 st[0] = 0. ;
373
374 /*** update gamma11 ***/
375 cf[6] = st[0] / ( st[0] + cf[4] ) ;
376 cf[6] += cf[6] ; /* gamma11 */
377
378 /*** compute wdf ***/
379
380 /* Adaptor B0 */
381 st[5] = cf[0] + st[1] + st[2] ; /* -b03=a12 (normalized) */
382
383 /* Adaptor B1 */
384 st[6] = cf[6] * st[5] ; /* -b11=2Ikn (normalized) */
385 st[7] = st[6] - st[5] ; /* b12=-a03 (normalized) */
386
387 /* Adaptor B0 */
388 st[2] = cf[0] + st[1] - st[7] + cf[5] * ( st[7] - st[5] ) ; /* Ixn(t-T)-b02 (normalized) */
389
390 /* Adaptor B2 */
391 an = st[6] - st[3] ; /* a24 (normalized) */
392 a0 = an - st[3] ; /* a20 (normalized) */
393 st[8] = cf[8] * a0 ; /* -b22=2Irn (normalized) */
394 st[3] = cf[7] * a0 + st[8] - an ; /* b23 (normalized) */
395
396 /* Adaptor B3 */
397 an = st[8] - st[4] ; /* a33 (normalized) */
398 st[1] = cf[9] * ( an - st[4] ) ; /* Ixn(t)=-0.5*b31 (normalized) */
399 st[4] = st[1] + st[1] - an ; /* b32 (normalized) */
400
401 #ifdef _CLAMPING_
402 /*** clamping of reservoirs to non-negative quantities ***/
403 /*** not available yet ***/
404 #endif
405
406 /*** output ***/
407 out = st[8] ;
408
409 #else
410
411 /*** compute change quantities ***/
412 replenish = cf[4] * ( cf[0] - st[1] ) ; /* y(M-q) */
413 eject = st[0] * st[1] ; /* kq */
414 loss = cf[5] * st[2] ; /* lc */
415 reuptake = cf[6] * st[2] ; /* rc */
416 reprocess = cf[7] * st[3] ; /* xw */
417
418 /*** compute compressive permeability function kn_1dt ***/
419 in = ( StateType ) *input ; /* (BM vibration) */
420 if( in > -cf[10] )
421 st[0] = cf[3] * ( in + cf[10] ) / ( in + cf[11] ) ; /* kn_1(t)dt */
422 else
423 st[0] = 0. ;
424
425 /*** update reservoir quantities ***/
426 st[1] += replenish - eject + reprocess ; /* q */
427 st[2] += eject - loss - reuptake ; /* c */
428 st[3] += reuptake - reprocess ; /* w */
429
430 #ifdef _CLAMPING_
431 /*** clamping of reservoirs to non-negative quantities ***/
432 if( st[1] < 0 )
433 st[1] = 0 ;
434 if( st[2] < 0 )
435 st[2] = 0 ;
436 #endif
437
438 /*** output ***/
439 out = st[2] ;
440
441 #endif
442
443 /*** output ***/
444 #ifdef _OVERFLOW_
445 if( out > _MaxOutput_ )
446 fprintf( stderr, "Overflow error in Meddis Haircell output\%e\n", ( double ) out ) ;
447 #endif
448
449 *output = ( DataType ) out ;
450
451 output += bank->channels ;
452 input += bank->channels ;
453 }
454
455 }
456
457 return( npoints ) ;
458 }
459
460
461 /************************** CloseHaircells() *********************************/
462
463 void CloseHaircells( bank_ptr )
464 Pointer bank_ptr ;
465 {
466 HaircellBank *bank = ( HaircellBank * ) bank_ptr ;
467 HaircellInfo *cell_info ;
468 int channel ;
469
470 for( channel = 0 ; channel < bank->channels ; channel++) {
471 Delete( bank->cells[ channel ]->states ) ;
472 Delete( bank->cells[ channel ] ) ;
473 }
474
475 Delete( bank->cells ) ;
476 Delete( bank->coeffs ) ;
477 Delete( bank->inputGain_ratio ) ;
478 Delete( bank ) ;
479
480 return ;
481 }
482
483
484 /********** low level functions ************/
485
486 double update_inputGain( ratio )
487 double ratio ;
488 {
489 return( pow( 10., ( ratio - 0.5 ) * InputGain_max / 20. ) ) ;
490 }
491