Mercurial > hg > aim92
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 |