Mercurial > hg > aim92
comparison model/corti.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 */ | |
17 | |
18 /* | |
19 corti.c | |
20 ======= | |
21 | |
22 attempt at model of organ of corti | |
23 | |
24 | |
25 Copyright (c), 1989 The Medical Research Council, Applied Psychology Unit. | |
26 | |
27 | |
28 Author : John Holdsworth | |
29 Written : 30th November, 1988. | |
30 | |
31 Edited : | |
32 | |
33 Christian Giguere, March 1994. | |
34 - Changed option "scale_at" into "gain_at". | |
35 - That option is now passed to newCorti() as a double instead of an integer | |
36 - In Corti(), this meant multiplying *optr by state->scale | |
37 - To locate changes, search for "CG" | |
38 | |
39 */ | |
40 #include <stdio.h> | |
41 #include <math.h> | |
42 | |
43 #include "stitch.h" | |
44 #include "source.h" | |
45 #include "corti.h" | |
46 #include "calc.h" | |
47 | |
48 #if 0 | |
49 #define DEBUG | |
50 #endif | |
51 | |
52 #ifndef lint | |
53 static char *sccs_id = "@(#)corti.c 1.15 J. Holdsworth (MRC-APU) 5/31/91" ; | |
54 #endif | |
55 | |
56 /* calmB is the mB of the magnitude where the slope of temporal recovery is calculated */ | |
57 /* 5497 corresponds to a magnitude of 500 units */ | |
58 | |
59 static double calmB = 5497. ; | |
60 | |
61 struct _cell_state { | |
62 StoreType microphonic, rapid_limit, absolute_limit ; | |
63 ScalarType rapid_rise, fast_rise, rapid_decay, fast_decay ; | |
64 double compensate ; /* Changed to double from StoreType (mha:22/1/93) */ | |
65 } ; | |
66 | |
67 struct _corti_state { | |
68 struct _cell_state *cell_states ; | |
69 StoreType scale ; | |
70 ScalarType t_lat ; | |
71 unsigned cells, times ; | |
72 } ; | |
73 | |
74 | |
75 /* global variable for spectral tilt control to compensate for differences */ | |
76 /* between channels in terms of mean firing rate */ | |
77 | |
78 double compensate = 1. ; | |
79 | |
80 | |
81 char *newCorti( cells, samplerate, center_frequencies, bandwidth_function, t_rise, t_lat, t_rapid, t_fast, prop, absthresh, times, scale ) | |
82 int cells ; | |
83 double samplerate, *center_frequencies, (*bandwidth_function)(), t_rise, t_lat, t_rapid, t_fast, prop, absthresh ; | |
84 int times ; | |
85 double scale ; /* CG: 22/03/94 */ | |
86 { | |
87 DeclareNew( struct _corti_state *, state ) ; | |
88 struct _cell_state *cell_ptr ; | |
89 double ratio, k_rise ; | |
90 double expected_rate, expected_reference ; | |
91 | |
92 /* parameters that are constant across cells */ | |
93 | |
94 state->t_lat = SCALAR( t_lat / ( samplerate * times ) ) ; | |
95 | |
96 state->cells = cells ; | |
97 state->times = times ; | |
98 state->scale = scale ; | |
99 | |
100 state->cell_states = NewArray( struct _cell_state, state->cells, "corti.c for cell states" ) ; | |
101 | |
102 for( cell_ptr = state->cell_states ; cell_ptr < state->cell_states + cells ; cell_ptr++ ) { | |
103 | |
104 /* corti states */ | |
105 | |
106 cell_ptr->microphonic = SCALAR( absthresh ) ; | |
107 cell_ptr->rapid_limit = SCALAR( absthresh ) ; | |
108 cell_ptr->absolute_limit = SCALAR( absthresh ) ; | |
109 | |
110 /* recovery time constants */ | |
111 | |
112 cell_ptr->rapid_decay = SCALAR( bandwidth_function( center_frequencies[cell_ptr-state->cell_states] ) * | |
113 t_rapid * calmB / ( calmB - absthresh ) / samplerate /* / ( 1. - prop ) */ ) ; | |
114 | |
115 cell_ptr->fast_decay = SCALAR( 1. / t_fast / samplerate ) ; | |
116 | |
117 /* adaptation time constants */ | |
118 | |
119 ratio = prop / ( 1. - prop ) / cell_ptr->rapid_decay * cell_ptr->fast_decay ; | |
120 | |
121 if( t_rise > 0 ) | |
122 k_rise = t_rise / ( samplerate * times ) ; | |
123 else | |
124 k_rise = 1. ; | |
125 | |
126 cell_ptr->rapid_rise = SCALAR( k_rise * 1. / ( 1. + ratio ) ) ; | |
127 cell_ptr->fast_rise = SCALAR( k_rise * ratio / ( 1. + ratio ) ) ; | |
128 | |
129 /* introduce variable amount of compensation w.r.t expected firing rate variation */ | |
130 | |
131 expected_rate = UNSCALE( cell_ptr->rapid_decay ) * ( calmB - absthresh ) ; | |
132 | |
133 if( cell_ptr == state->cell_states ) | |
134 expected_reference = expected_rate ; | |
135 | |
136 /* New formula for computing cell_ptr->compensate (mha: 20/1/93) */ | |
137 /* Parameters chosen to flatten pulse-train spectrum. */ | |
138 /* _cell_state member "compensate" changed to double. */ | |
139 /* The exponent used is 1.128*compensate so that the given */ | |
140 /* parameter (compensate_at) can be set as "on" (ie 1.0) for */ | |
141 /* optimal compensation (instead of a magic number) */ | |
142 /* The value for "compensate_at=off", (calmB - absthresh) was */ | |
143 /* chosen as similar to the original, and because the results */ | |
144 /* were appropriate for an un-compensated spectrum. */ | |
145 | |
146 if (compensate) | |
147 cell_ptr->compensate = pow(center_frequencies[cell_ptr - state->cell_states], 1.128*compensate) + 800. ; | |
148 else | |
149 cell_ptr->compensate = calmB - absthresh ; | |
150 | |
151 /* Originally, compensate used the SCALAR macro, and so it failed */ | |
152 /* for a floating-point version (defined in calc.h). */ | |
153 /* To fix this, the new compensate formula is scaled up using the */ | |
154 /* original integer version of the UNSCALE macro (see calc.h). */ | |
155 | |
156 #ifdef FLOAT | |
157 cell_ptr->compensate /= (float) ( 1l << 16l ) ; | |
158 #endif | |
159 | |
160 #ifdef DEBUG | |
161 (void) fprintf( stderr, "rapid_decay:%f fast_decay:%f ratio:%f k_rise:%f rapid_rise:%f fast_rise:%f compensation:%f\n", | |
162 UNSCALE(cell_ptr->rapid_decay), UNSCALE(cell_ptr->fast_decay), | |
163 ratio, k_rise, UNSCALE(cell_ptr->rapid_rise), UNSCALE(cell_ptr->fast_rise), | |
164 1./UNSCALE(cell_ptr->compensate) ) ; | |
165 #endif | |
166 } | |
167 #ifdef DEBUG | |
168 (void) fprintf( stderr, "times:%d t_lat:%f\n", times, UNSCALE( state->t_lat ) ) ; | |
169 #endif | |
170 | |
171 return( (char *) state ) ; | |
172 } | |
173 | |
174 int Corti( state_ptr, bytes, out, end, in ) | |
175 char *state_ptr ; | |
176 ByteCount *bytes ; | |
177 DataType *out, *end, *in ; | |
178 { | |
179 register struct _corti_state *state = (struct _corti_state *) state_ptr ; | |
180 register struct _cell_state *cell_ptr, *cell_end = state->cell_states + state->cells ; | |
181 register DataType *iptr, *optr, *eptr = end ; | |
182 register StoreType delta, old_last_mic ; | |
183 register int time ; | |
184 | |
185 while( out < eptr ) { | |
186 | |
187 for( time=0 ; time < state->times ; time++ ) { | |
188 | |
189 cell_ptr = state->cell_states ; | |
190 | |
191 iptr = in ; | |
192 optr = out ; | |
193 | |
194 /* raise threhsolds */ | |
195 | |
196 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) { | |
197 | |
198 if( time == 0 ) | |
199 *optr = 0 ; | |
200 | |
201 delta = *iptr++ - DESCALE( cell_ptr->microphonic ) ; | |
202 | |
203 if( delta > 0 ) { | |
204 | |
205 cell_ptr->microphonic += delta * cell_ptr->rapid_rise ; | |
206 cell_ptr->rapid_limit += delta * cell_ptr->fast_rise ; | |
207 | |
208 *optr += delta ; | |
209 } | |
210 | |
211 optr++ ; | |
212 } | |
213 | |
214 /* leak thresholds symetrically across channels */ | |
215 | |
216 old_last_mic = state->cell_states->microphonic ; | |
217 | |
218 for( cell_ptr = state->cell_states+1 ; cell_ptr < cell_end ; cell_ptr++ ) { | |
219 | |
220 delta = DESCALE( old_last_mic - cell_ptr->microphonic ) * state->t_lat ; | |
221 old_last_mic = cell_ptr->microphonic ; | |
222 | |
223 if( cell_ptr-1 != state->cell_states ) | |
224 (cell_ptr-1)->microphonic -= delta ; | |
225 | |
226 if( cell_ptr+1 != cell_end ) | |
227 (cell_ptr )->microphonic += delta ; | |
228 } | |
229 } | |
230 | |
231 /* decay potentails */ | |
232 | |
233 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) | |
234 cell_ptr->microphonic -= DESCALE( cell_ptr->microphonic - cell_ptr->rapid_limit ) * cell_ptr->rapid_decay ; | |
235 | |
236 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) | |
237 cell_ptr->rapid_limit -= DESCALE( cell_ptr->rapid_limit - cell_ptr->absolute_limit ) * cell_ptr->fast_decay ; | |
238 | |
239 /* generate output */ | |
240 | |
241 iptr = in ; | |
242 optr = out ; | |
243 | |
244 if( state->scale >= 0 ) /* CG: 22/3/94 */ | |
245 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) { | |
246 delta = SCALE( *iptr++ ) - cell_ptr->microphonic ; | |
247 if( delta > 0 ) | |
248 *optr++ = state->scale * delta / cell_ptr->compensate ; /* CG: 22/3/94 */ | |
249 else | |
250 *optr++ = 0 ; | |
251 } | |
252 else if( state->scale < 0 ) | |
253 switch( (int) state->scale ) { | |
254 | |
255 /* output internal states */ | |
256 | |
257 case -1 : | |
258 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) | |
259 *optr++ = DESCALE( cell_ptr->microphonic ) ; | |
260 | |
261 break ; | |
262 | |
263 case -2 : | |
264 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) | |
265 *optr++ = DESCALE( cell_ptr->rapid_limit ) ; | |
266 | |
267 break ; | |
268 | |
269 default : | |
270 for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) | |
271 *optr++ = ( *iptr++ - DESCALE( cell_ptr->microphonic ) ) * -state->scale ; | |
272 | |
273 break ; | |
274 | |
275 } | |
276 /* else leave value as is */ | |
277 | |
278 | |
279 /* next frame */ | |
280 | |
281 in += state->cells ; | |
282 out += state->cells ; | |
283 } | |
284 | |
285 /* return amount processed */ | |
286 | |
287 return ( *bytes ) ; | |
288 } | |
289 | |
290 /* for compatability */ | |
291 | |
292 int OldCorti( state_ptr, cells, in, out ) | |
293 char *state_ptr ; | |
294 unsigned cells ; | |
295 DataType *in, *out ; | |
296 { | |
297 ByteCount bytes = ToBytes( DataType, cells ) ; | |
298 | |
299 return ( ToPoints( DataType, Corti( state_ptr, &bytes, out, out+cells, in ) ) ) ; | |
300 } | |
301 | |
302 void closeCorti( state ) | |
303 struct _corti_state *state ; | |
304 { | |
305 Delete( state->cell_states ) ; | |
306 Delete( state ) ; | |
307 | |
308 return ; | |
309 } | |
310 | |
311 | |
312 /* experimental corti simulation */ | |
313 | |
314 | |
315 struct _corti2_state { int *working, *falls, slope, scale ; short *forward, *backward ; } ; | |
316 | |
317 char *newCorti2( cells, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, t_slope, scale, forward, backward ) | |
318 int cells ; | |
319 double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, t_slope, scale ; | |
320 short *forward, *backward ; | |
321 { | |
322 DeclareNew( struct _corti2_state *, state ) ; | |
323 int i ; | |
324 | |
325 state->working = NewArray( int, cells, "corti.c for works" ) ; | |
326 state->falls = NewZeroedArray( int, cells, "corti.c for falls" ) ; | |
327 | |
328 for( i=0 ; i < cells ; i++ ) | |
329 state->falls[i] = bandwidth_function( center_frequencies[i] ) * bandwidth_scalar / | |
330 samplerate * t_slope ; | |
331 | |
332 state->forward = forward ; | |
333 state->backward = backward ; | |
334 | |
335 state->scale = scale ; | |
336 | |
337 return( ( char * ) state ) ; | |
338 } | |
339 | |
340 int Corti2( state_ptr, cells, in, out ) | |
341 char *state_ptr ; | |
342 unsigned cells ; | |
343 short *in, *out ; | |
344 { | |
345 struct _corti2_state *state ; | |
346 register int i, when ; | |
347 | |
348 state = ( struct _corti2_state * ) state_ptr ; | |
349 | |
350 for( i=0 ; i<cells ; i++ ) { | |
351 state->working[i] -= state->falls[i] ; | |
352 out[i] = in[i] - state->working[i] ; | |
353 if( out[i] > 0 ) | |
354 state->working[i] += out[i] ; | |
355 } | |
356 | |
357 when = 0 ; | |
358 | |
359 for( i=1 ; i<cells ; i++ ) | |
360 if( state->working[i] < state->working[ when ] + state->forward[ i - when ] ) { | |
361 state->working[i] = state->working[ when ] + state->forward[ i - when ] ; | |
362 out[i] = 0 ; | |
363 } | |
364 else | |
365 when = i ; | |
366 | |
367 when = cells-1 ; | |
368 | |
369 for( i=cells-2 ; i>=0 ; i-- ) | |
370 if( state->working[i] < state->working[ when ] + state->backward[ when - i ] ) { | |
371 state->working[i] = state->working[ when ] + state->backward[ when - i ] ; | |
372 out[i] = 0 ; | |
373 } | |
374 else | |
375 when = i ; | |
376 | |
377 for( i=0 ; i<cells ; i++ ) | |
378 if( state->scale != 0 ) | |
379 out[i] = out[i] * state->scale / state->falls[i] ; | |
380 else | |
381 out[i] = state->working[i] ; | |
382 | |
383 return ; | |
384 } | |
385 | |
386 void closeCorti2( state ) | |
387 struct _corti2_state *state ; | |
388 { | |
389 stitch_free( ( char * ) state->working ) ; | |
390 stitch_free( ( char * ) state->falls ) ; | |
391 | |
392 Delete( state ) ; | |
393 | |
394 return ; | |
395 } | |
396 | |
397 #if 0 | |
398 | |
399 /* obsolete code stored here for now.. stitch entry points */ | |
400 | |
401 | |
402 struct _stx_state { Source source ; unsigned cells ; char *corti ; int (*model)() ; } ; | |
403 | |
404 static void stx_callback( state, bytes, buffer ) | |
405 struct _stx_state *state ; | |
406 ByteCount bytes ; | |
407 DataType *buffer ; | |
408 { | |
409 int points = ToPoints( DataType, bytes ) ; | |
410 DataType *input = PullItems( state->source, points, DataType ) ; | |
411 int pointer ; | |
412 | |
413 for( pointer=0 ; pointer < points ; pointer += state->cells ) | |
414 (void) state->model( state->corti, state->cells, input+pointer, buffer+pointer ) ; | |
415 | |
416 return ; | |
417 } | |
418 | |
419 Source Stx( source, chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, t_rise, t_lat, t_rapid, absthresh, times, scale ) | |
420 Source source ; | |
421 int chans ; | |
422 double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, t_rise, t_lat, t_rapid, absthresh ; | |
423 int times, scale ; | |
424 { | |
425 DeclareNew( struct _stx_state *, state ) ; | |
426 | |
427 state->source = source ; | |
428 state->cells = chans ; | |
429 | |
430 state->corti = newCorti( chans, samplerate, center_frequencies, bandwidth_function, t_rise, t_lat, t_rapid, absthresh, times, scale ) ; | |
431 state->model = OldCorti ; | |
432 | |
433 return ( stdAutoSource( ( Pointer ) state, stx_callback ) ) ; | |
434 } | |
435 | |
436 Source Stx2( source, chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, rapid_rises, scale ) | |
437 Source source ; | |
438 int chans ; | |
439 double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, rapid_rises, scale ; | |
440 { | |
441 DeclareNew( struct _stx_state *, state ) ; | |
442 short *forward = ( short * ) 0, *backward = ( short * ) 0 ; | |
443 | |
444 state->source = source ; | |
445 state->cells = chans ; | |
446 | |
447 state->corti = newCorti2( chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, rapid_rises, scale, forward, backward ) ; | |
448 state->model = Corti2 ; | |
449 | |
450 return ( stdAutoSource( ( Pointer ) state, stx_callback ) ) ; | |
451 } | |
452 | |
453 #endif |