Mercurial > hg > aim92
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/corti.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,453 @@ +/* + Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 + =========================================================================== + + Permission to use, copy, modify, and distribute this software without fee + is hereby granted for research purposes, provided that this copyright + notice appears in all copies and in all supporting documentation, and that + the software is not redistributed for any fee (except for a nominal shipping + charge). Anyone wanting to incorporate all or part of this software in a + commercial product must obtain a license from the Medical Research Council. + + The MRC makes no representations about the suitability of this + software for any purpose. It is provided "as is" without express or implied + warranty. + +*/ + +/* + corti.c + ======= + + attempt at model of organ of corti + + + Copyright (c), 1989 The Medical Research Council, Applied Psychology Unit. + + + Author : John Holdsworth + Written : 30th November, 1988. + + Edited : + + Christian Giguere, March 1994. + - Changed option "scale_at" into "gain_at". + - That option is now passed to newCorti() as a double instead of an integer + - In Corti(), this meant multiplying *optr by state->scale + - To locate changes, search for "CG" + +*/ +#include <stdio.h> +#include <math.h> + +#include "stitch.h" +#include "source.h" +#include "corti.h" +#include "calc.h" + +#if 0 +#define DEBUG +#endif + +#ifndef lint +static char *sccs_id = "@(#)corti.c 1.15 J. Holdsworth (MRC-APU) 5/31/91" ; +#endif + +/* calmB is the mB of the magnitude where the slope of temporal recovery is calculated */ +/* 5497 corresponds to a magnitude of 500 units */ + +static double calmB = 5497. ; + +struct _cell_state { +StoreType microphonic, rapid_limit, absolute_limit ; +ScalarType rapid_rise, fast_rise, rapid_decay, fast_decay ; +double compensate ; /* Changed to double from StoreType (mha:22/1/93) */ +} ; + +struct _corti_state { +struct _cell_state *cell_states ; +StoreType scale ; +ScalarType t_lat ; +unsigned cells, times ; +} ; + + +/* global variable for spectral tilt control to compensate for differences */ +/* between channels in terms of mean firing rate */ + +double compensate = 1. ; + + +char *newCorti( cells, samplerate, center_frequencies, bandwidth_function, t_rise, t_lat, t_rapid, t_fast, prop, absthresh, times, scale ) +int cells ; +double samplerate, *center_frequencies, (*bandwidth_function)(), t_rise, t_lat, t_rapid, t_fast, prop, absthresh ; +int times ; +double scale ; /* CG: 22/03/94 */ +{ + DeclareNew( struct _corti_state *, state ) ; + struct _cell_state *cell_ptr ; + double ratio, k_rise ; + double expected_rate, expected_reference ; + + /* parameters that are constant across cells */ + + state->t_lat = SCALAR( t_lat / ( samplerate * times ) ) ; + + state->cells = cells ; + state->times = times ; + state->scale = scale ; + + state->cell_states = NewArray( struct _cell_state, state->cells, "corti.c for cell states" ) ; + + for( cell_ptr = state->cell_states ; cell_ptr < state->cell_states + cells ; cell_ptr++ ) { + + /* corti states */ + + cell_ptr->microphonic = SCALAR( absthresh ) ; + cell_ptr->rapid_limit = SCALAR( absthresh ) ; + cell_ptr->absolute_limit = SCALAR( absthresh ) ; + + /* recovery time constants */ + + cell_ptr->rapid_decay = SCALAR( bandwidth_function( center_frequencies[cell_ptr-state->cell_states] ) * + t_rapid * calmB / ( calmB - absthresh ) / samplerate /* / ( 1. - prop ) */ ) ; + + cell_ptr->fast_decay = SCALAR( 1. / t_fast / samplerate ) ; + + /* adaptation time constants */ + + ratio = prop / ( 1. - prop ) / cell_ptr->rapid_decay * cell_ptr->fast_decay ; + + if( t_rise > 0 ) + k_rise = t_rise / ( samplerate * times ) ; + else + k_rise = 1. ; + + cell_ptr->rapid_rise = SCALAR( k_rise * 1. / ( 1. + ratio ) ) ; + cell_ptr->fast_rise = SCALAR( k_rise * ratio / ( 1. + ratio ) ) ; + + /* introduce variable amount of compensation w.r.t expected firing rate variation */ + + expected_rate = UNSCALE( cell_ptr->rapid_decay ) * ( calmB - absthresh ) ; + + if( cell_ptr == state->cell_states ) + expected_reference = expected_rate ; + + /* New formula for computing cell_ptr->compensate (mha: 20/1/93) */ + /* Parameters chosen to flatten pulse-train spectrum. */ + /* _cell_state member "compensate" changed to double. */ + /* The exponent used is 1.128*compensate so that the given */ + /* parameter (compensate_at) can be set as "on" (ie 1.0) for */ + /* optimal compensation (instead of a magic number) */ + /* The value for "compensate_at=off", (calmB - absthresh) was */ + /* chosen as similar to the original, and because the results */ + /* were appropriate for an un-compensated spectrum. */ + + if (compensate) + cell_ptr->compensate = pow(center_frequencies[cell_ptr - state->cell_states], 1.128*compensate) + 800. ; + else + cell_ptr->compensate = calmB - absthresh ; + + /* Originally, compensate used the SCALAR macro, and so it failed */ + /* for a floating-point version (defined in calc.h). */ + /* To fix this, the new compensate formula is scaled up using the */ + /* original integer version of the UNSCALE macro (see calc.h). */ + +#ifdef FLOAT + cell_ptr->compensate /= (float) ( 1l << 16l ) ; +#endif + +#ifdef DEBUG + (void) fprintf( stderr, "rapid_decay:%f fast_decay:%f ratio:%f k_rise:%f rapid_rise:%f fast_rise:%f compensation:%f\n", + UNSCALE(cell_ptr->rapid_decay), UNSCALE(cell_ptr->fast_decay), + ratio, k_rise, UNSCALE(cell_ptr->rapid_rise), UNSCALE(cell_ptr->fast_rise), + 1./UNSCALE(cell_ptr->compensate) ) ; +#endif + } +#ifdef DEBUG + (void) fprintf( stderr, "times:%d t_lat:%f\n", times, UNSCALE( state->t_lat ) ) ; +#endif + + return( (char *) state ) ; +} + +int Corti( state_ptr, bytes, out, end, in ) +char *state_ptr ; +ByteCount *bytes ; +DataType *out, *end, *in ; +{ + register struct _corti_state *state = (struct _corti_state *) state_ptr ; + register struct _cell_state *cell_ptr, *cell_end = state->cell_states + state->cells ; + register DataType *iptr, *optr, *eptr = end ; + register StoreType delta, old_last_mic ; + register int time ; + + while( out < eptr ) { + + for( time=0 ; time < state->times ; time++ ) { + + cell_ptr = state->cell_states ; + + iptr = in ; + optr = out ; + + /* raise threhsolds */ + + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) { + + if( time == 0 ) + *optr = 0 ; + + delta = *iptr++ - DESCALE( cell_ptr->microphonic ) ; + + if( delta > 0 ) { + + cell_ptr->microphonic += delta * cell_ptr->rapid_rise ; + cell_ptr->rapid_limit += delta * cell_ptr->fast_rise ; + + *optr += delta ; + } + + optr++ ; + } + + /* leak thresholds symetrically across channels */ + + old_last_mic = state->cell_states->microphonic ; + + for( cell_ptr = state->cell_states+1 ; cell_ptr < cell_end ; cell_ptr++ ) { + + delta = DESCALE( old_last_mic - cell_ptr->microphonic ) * state->t_lat ; + old_last_mic = cell_ptr->microphonic ; + + if( cell_ptr-1 != state->cell_states ) + (cell_ptr-1)->microphonic -= delta ; + + if( cell_ptr+1 != cell_end ) + (cell_ptr )->microphonic += delta ; + } + } + + /* decay potentails */ + + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) + cell_ptr->microphonic -= DESCALE( cell_ptr->microphonic - cell_ptr->rapid_limit ) * cell_ptr->rapid_decay ; + + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) + cell_ptr->rapid_limit -= DESCALE( cell_ptr->rapid_limit - cell_ptr->absolute_limit ) * cell_ptr->fast_decay ; + + /* generate output */ + + iptr = in ; + optr = out ; + + if( state->scale >= 0 ) /* CG: 22/3/94 */ + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) { + delta = SCALE( *iptr++ ) - cell_ptr->microphonic ; + if( delta > 0 ) + *optr++ = state->scale * delta / cell_ptr->compensate ; /* CG: 22/3/94 */ + else + *optr++ = 0 ; + } + else if( state->scale < 0 ) + switch( (int) state->scale ) { + + /* output internal states */ + + case -1 : + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) + *optr++ = DESCALE( cell_ptr->microphonic ) ; + + break ; + + case -2 : + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) + *optr++ = DESCALE( cell_ptr->rapid_limit ) ; + + break ; + + default : + for( cell_ptr = state->cell_states ; cell_ptr < cell_end ; cell_ptr++ ) + *optr++ = ( *iptr++ - DESCALE( cell_ptr->microphonic ) ) * -state->scale ; + + break ; + + } + /* else leave value as is */ + + + /* next frame */ + + in += state->cells ; + out += state->cells ; + } + + /* return amount processed */ + + return ( *bytes ) ; +} + +/* for compatability */ + +int OldCorti( state_ptr, cells, in, out ) +char *state_ptr ; +unsigned cells ; +DataType *in, *out ; +{ + ByteCount bytes = ToBytes( DataType, cells ) ; + + return ( ToPoints( DataType, Corti( state_ptr, &bytes, out, out+cells, in ) ) ) ; +} + +void closeCorti( state ) +struct _corti_state *state ; +{ + Delete( state->cell_states ) ; + Delete( state ) ; + + return ; +} + + +/* experimental corti simulation */ + + +struct _corti2_state { int *working, *falls, slope, scale ; short *forward, *backward ; } ; + +char *newCorti2( cells, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, t_slope, scale, forward, backward ) +int cells ; +double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, t_slope, scale ; +short *forward, *backward ; +{ + DeclareNew( struct _corti2_state *, state ) ; + int i ; + + state->working = NewArray( int, cells, "corti.c for works" ) ; + state->falls = NewZeroedArray( int, cells, "corti.c for falls" ) ; + + for( i=0 ; i < cells ; i++ ) + state->falls[i] = bandwidth_function( center_frequencies[i] ) * bandwidth_scalar / + samplerate * t_slope ; + + state->forward = forward ; + state->backward = backward ; + + state->scale = scale ; + + return( ( char * ) state ) ; +} + +int Corti2( state_ptr, cells, in, out ) +char *state_ptr ; +unsigned cells ; +short *in, *out ; +{ + struct _corti2_state *state ; + register int i, when ; + + state = ( struct _corti2_state * ) state_ptr ; + + for( i=0 ; i<cells ; i++ ) { + state->working[i] -= state->falls[i] ; + out[i] = in[i] - state->working[i] ; + if( out[i] > 0 ) + state->working[i] += out[i] ; + } + + when = 0 ; + + for( i=1 ; i<cells ; i++ ) + if( state->working[i] < state->working[ when ] + state->forward[ i - when ] ) { + state->working[i] = state->working[ when ] + state->forward[ i - when ] ; + out[i] = 0 ; + } + else + when = i ; + + when = cells-1 ; + + for( i=cells-2 ; i>=0 ; i-- ) + if( state->working[i] < state->working[ when ] + state->backward[ when - i ] ) { + state->working[i] = state->working[ when ] + state->backward[ when - i ] ; + out[i] = 0 ; + } + else + when = i ; + + for( i=0 ; i<cells ; i++ ) + if( state->scale != 0 ) + out[i] = out[i] * state->scale / state->falls[i] ; + else + out[i] = state->working[i] ; + + return ; +} + +void closeCorti2( state ) +struct _corti2_state *state ; +{ + stitch_free( ( char * ) state->working ) ; + stitch_free( ( char * ) state->falls ) ; + + Delete( state ) ; + + return ; +} + +#if 0 + +/* obsolete code stored here for now.. stitch entry points */ + + +struct _stx_state { Source source ; unsigned cells ; char *corti ; int (*model)() ; } ; + +static void stx_callback( state, bytes, buffer ) +struct _stx_state *state ; +ByteCount bytes ; +DataType *buffer ; +{ + int points = ToPoints( DataType, bytes ) ; + DataType *input = PullItems( state->source, points, DataType ) ; + int pointer ; + + for( pointer=0 ; pointer < points ; pointer += state->cells ) + (void) state->model( state->corti, state->cells, input+pointer, buffer+pointer ) ; + + return ; +} + +Source Stx( source, chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, t_rise, t_lat, t_rapid, absthresh, times, scale ) +Source source ; +int chans ; +double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, t_rise, t_lat, t_rapid, absthresh ; +int times, scale ; +{ + DeclareNew( struct _stx_state *, state ) ; + + state->source = source ; + state->cells = chans ; + + state->corti = newCorti( chans, samplerate, center_frequencies, bandwidth_function, t_rise, t_lat, t_rapid, absthresh, times, scale ) ; + state->model = OldCorti ; + + return ( stdAutoSource( ( Pointer ) state, stx_callback ) ) ; +} + +Source Stx2( source, chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, rapid_rises, scale ) +Source source ; +int chans ; +double samplerate, *center_frequencies, (*bandwidth_function)(), bandwidth_scalar, rapid_rises, scale ; +{ + DeclareNew( struct _stx_state *, state ) ; + short *forward = ( short * ) 0, *backward = ( short * ) 0 ; + + state->source = source ; + state->cells = chans ; + + state->corti = newCorti2( chans, samplerate, center_frequencies, bandwidth_function, bandwidth_scalar, rapid_rises, scale, forward, backward ) ; + state->model = Corti2 ; + + return ( stdAutoSource( ( Pointer ) state, stx_callback ) ) ; +} + +#endif