diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wdf/meddis.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,491 @@
+/*
+    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.
+ 
+    THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
+    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
+    A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 
+    DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*  
+    Acknowledgment:
+    ==============
+
+    The source code provided in this file was originally developed by 
+    Christian Giguere as part of a Ph.D degree at the Department of
+    Engineering of the University of Cambridge from April 1990 to
+    November 1993. The code was subsequently adapted under a grant
+    from the Hearing Research Trust for full compatibility with 
+    AIM Release 6.15.
+
+    Christian Giguere 25/03/94
+
+*/
+
+/*
+    ===========================================================
+    meddis.c
+    ===========================================================
+
+    Implementation of Ray Meddis haircell model.
+
+    Author        : Christian Giguere
+    First written : 10th September, 1991
+    Last edited   : 07th March, 1994
+
+    References:
+    (1) C.Giguere and P.C.Woodland (1994). JASA 95(1): 331-342.
+    (2) R.Meddis et al. (1990). JASA 87(4): 1813-1816.
+    (3) R.Meddis (1988). JASA 83(3): 1056-1063.
+
+    Note - This is a complete re-write of the original file 
+	   "haircell.c" Release 3 (20th September 1988) from  
+	   J. Holdsworth and the Applied Psychology Unit. 
+    ============================================================
+*/
+
+
+/***** includes *****/
+
+#include <math.h>
+#include <stdio.h>
+#include "stitch.h"
+#include "source.h"
+#include "calc.h"
+#include "calc_tl.h"
+#include "meddis.h"
+
+
+/***** defines *****/
+
+#if 0
+#define   _DEBUG_
+#define   _OVERFLOW_
+#endif
+
+#if 1                                                /* define numerical implementation */
+#define   _WDF_                                      /* Giguere and Woodland (1994) */
+#else
+#define   _FORWARD_DIFFERENCE_                       /* Meddis et al. (1990) */
+#endif
+
+#if 0  
+#define   _CLAMPING_                                 /* clamping of reservoirs */
+#endif
+ 
+#define   NUMBER_OF_COEFFS     (           12 )
+#define   NUMBER_OF_STATES     (           12 )
+
+
+/* Feedback parameter */
+
+#define   InputGain_max        (         24.0 )      /* max coupling gain in dB */
+
+
+/* Meddis et al. (1990) model parameters */
+
+#define   A_medium             (         10.0 )      /* medium-spontaneous rate fibre  */
+#define   B_medium             (       3000.0 )
+#define   g_medium             (       1000.0 )
+
+#define   A_high               (          5.0 )      /* high-spontaneous rate fibre */
+#define   B_high               (        300.0 )
+#define   g_high               (       2000.0 )
+
+#define   y_value              (         5.05 )      /* replenishment rate */
+#define   l_value              (         2500 )      /* rate of loss from the cleft */
+#define   r_value              (         6580 )      /* rate of return from the cleft */
+#define   x_value              (        66.31 )      /* rate of release from w store */ 
+#define   m_value              (          1.0 )      /* max number of quanta */
+#define   h_value              (       50000. )      /* firing-rate factor */
+
+
+/***** private data structures *****/
+
+typedef struct _haircell_info HaircellInfo ;
+typedef struct _haircell_bank HaircellBank ;
+
+struct _haircell_info {
+  int        number_of_states ;  
+  double     output_gain ;
+  StateType  *states ;
+  } ;
+
+struct _haircell_bank {
+  int           channels ;
+  double        *inputGain_ratio ;
+  double        (*update_proc)() ;                  /* procedure to update cells input gain */
+  int           number_of_coeffs ;
+  CoeffType     *coeffs ;
+  HaircellInfo  **cells ;
+  } ;
+
+
+/***** external variables *****/
+
+double *InputGain_ratio ;
+
+
+/***** functions *****/
+
+/*******************************************************************************
+* name:                 function:
+*
+* NewHaircells()        Set-up function for the implementation of a bank of inner
+*                       haircells based on the model of Ray Meddis. It generates the 
+*                       multiplier coefficients for each haircell filter and 
+*                       initializes the filter states. It is called by function 
+*                       ``Meddis()'' in file ``model.c''. It returns a pointer to a 
+*                       structure containing all the relevant information for the 
+*                       computation of the haircell filters. 
+*
+*                       The choice of the haircell type (medium or high-spontaneous
+*                       rate fibre) is made at run time using options ``fibre_med''.
+*
+*                       The choice of the numerical implementation (Wave Digital 
+*                       Filtering or Forward Difference algorithm) is made at 
+*                       compile time using a macro substitution ``#define'' (see above).
+*
+*                       The choice of clamping the reservoirs' contents to non-
+*                       negative values is made at compile time using a macro
+*                       substitution ``#define'' (see above).
+*
+* DoHaircells()         Realization of the bank of haircell filters. It computes the
+*                       output for each haircell for a specified number of input 
+*                       points and keeps track of the filters' states. It returns
+*                       the size of the output data in bytes (per point).
+*
+* CloseHaircells()      Deletes all private data structures and arrays of the Haircell 
+*                       filters upon comletion of filtering.
+********************************************************************************/
+
+
+/*************************** NewHaircells() *********************************/
+
+Pointer NewHaircells( channels, samplerate, output_gain, coupling, fibreType )
+    int    channels ;
+    double samplerate, output_gain ;
+    double coupling ;
+    char   *fibreType ;
+{
+    DeclareNew( HaircellBank *, bank ) ;
+    HaircellInfo  *cell_info ;
+    CoeffType     *cf ;
+    StateType     *st ;  
+    double        ydt, ldt, rdt, xdt, gdt ; 
+    double        kdt_init, q_init, c_init, w_init, cell_scaling ; 
+    double        A_value, B_value, g_value ;
+    double        r1, r2, r3, r4, r03 ;
+    double        update_inputGain() ;
+    int           channel ;
+
+   /*** scaling of input data ***/
+    cell_scaling = coupling ;
+
+   /*** allocate fibre-dependent haircell parameters ***/
+    if( strncmp( fibreType, "high", 3 ) == 0 ) {
+	A_value = A_high ;
+	B_value = B_high ;
+	g_value = g_high ;
+    }
+     else {
+	A_value = A_medium ;
+	B_value = B_medium ;
+	g_value = g_medium ;
+    }
+
+#ifdef _DEBUG_
+    fprintf( stderr, "Meddis Haircell fibre type=%s\n", fibreType ) ;
+    fprintf( stderr, "A=%.2f B=%.2f g=%.2f\n", A_value, B_value, g_value ) ;
+    fprintf( stderr, "Input scaling factor=%.4f\n", cell_scaling ) ;
+#endif
+
+
+   /*** scale model parameters for difference equations ***/ 
+    ydt = y_value / samplerate ;
+    ldt = l_value / samplerate ;
+    rdt = r_value / samplerate ;
+    xdt = x_value / samplerate ;
+    gdt = g_value / samplerate ;
+
+
+   /*** calculate initial values for infinite history of silence ***/
+    kdt_init = gdt * A_value / ( A_value + B_value ) ;
+    q_init   = m_value / ( 1. + kdt_init / ydt * ( 1. - rdt / ( ldt + rdt ) ) ) ;
+    c_init   = q_init * kdt_init / ( ldt + rdt ) ;
+    w_init   = rdt / xdt * c_init ;    
+
+
+   /*** allocate and store multiplier coefficients ***/
+    bank->number_of_coeffs = NUMBER_OF_COEFFS ;  
+    cf = bank->coeffs = NewArray( CoeffType, bank->number_of_coeffs, 
+				  "haircell_tl.c for coefficients" ) ;
+#ifdef _WDF_
+    output_gain = MEDDIS_SCALE * output_gain * h_value / ( 2. * r_value ) ;
+    cf[0] = m_value * y_value * output_gain ;                     /* M/Zy (normalized) */
+    cf[1] = A_value / cell_scaling ;
+    cf[2] = ( A_value + B_value ) / cell_scaling ; 
+    cf[3] = g_value ;
+
+    /* Adaptor B0 */ 
+    r1 = y_value ;                                                /* ( 1/Zy ) */
+    r2 = 2. * samplerate ;                                        /* ( 1/Zcq ) */
+    r3 = r03 = r1 + r2 ;
+    cf[5] = r1 / r3 ;                                             /* gamma01 */
+    cf[4] = r3 / cf[3] ;                                          /* needed to update gamma11 */
+
+    /* Adaptor B1*/ 
+    r1 = kdt_init * samplerate ;                                  /* ( 1/Zk ) initial value only */
+    r2 = r03 ;
+    r3 = r1 + r2 ;
+    cf[6] = 2. * r1 / r3 ;                                        /* gamma11 updated at each sample */
+
+    /* Adaptor B2 */ 
+    r1 = l_value ;                                                /* ( 1/Zl ) */
+    r2 = r_value ;                                                /* ( 1/Zr ) */
+    r3 = 2. * samplerate ;                                        /* ( 1/Zcc ) */
+    r4 = r1 + r2 + r3 ;
+    cf[7] = r1 / r4 ;                                             /* gamma21 */
+    cf[8] = r2 / r4 ;                                             /* gamma22 */
+
+    /* Adaptor B3 */
+    r1 = x_value ;                                                /* ( 1/Zx ) */
+    r2 = 2. * samplerate ;                                        /* ( 1/Zcw ) */
+    r3 = r1 + r2 ;
+    cf[9] = 0.5 * r1 / r3 ;                                       /* 0.5 * gamma31 */
+
+#else
+    output_gain = MEDDIS_SCALE * output_gain * h_value ;
+    cf[0] = m_value * output_gain ;
+    cf[1] = A_value / cell_scaling ;
+    cf[2] = ( A_value + B_value ) / cell_scaling ;
+    cf[3] = gdt ;
+    cf[4] = ydt ;
+    cf[5] = ldt ;
+    cf[6] = rdt ;
+    cf[7] = xdt ;
+#endif
+
+
+   /*** loop through each haircell ***/
+    bank->channels = channels ;
+    bank->cells = NewArray( HaircellInfo *, bank->channels, "haircell.c for cell states" ) ;
+    bank->inputGain_ratio = InputGain_ratio = NewArray( double, bank->channels, 
+							"haircell_tl.c for cells input gain ratio" ) ;
+    bank->update_proc = update_inputGain ;
+
+    for( channel = 0 ; channel < bank->channels ; channel++ ) {
+	 bank->inputGain_ratio[ channel ] = 0.5 ;            /* in absence of feedback, Gain = 1 */
+	 cell_info = bank->cells[ channel ] = New( HaircellInfo * ) ;
+
+	/*** allocate and initialise states ***/
+	 cell_info->number_of_states = NUMBER_OF_STATES ;
+	 st = cell_info->states = NewZeroedArray( StateType, cell_info->number_of_states, 
+						  "haircell_tl.c for states" ) ;
+
+#ifdef _WDF_
+	st[1] =  x_value * w_init * output_gain ;               /* Ixn (normalized) */
+	st[2] =  2. * q_init * samplerate * output_gain ;       /* Ixn(t-T)-b02 (normalized) */
+	st[3] = -2. * c_init * samplerate * output_gain ;       /* b23 (normalized) */
+	st[4] = -2. * w_init * samplerate * output_gain ;       /* b33 (normalized) */
+	cell_info->output_gain = output_gain ;                  /* obsolete */
+
+#else
+	st[0] = kdt_init ;
+	st[1] = q_init * output_gain ;
+	st[2] = c_init * output_gain ;
+	st[3] = w_init * output_gain ;
+	cell_info->output_gain = output_gain ;                  /* obsolete */
+#endif
+
+    }
+
+    return( ( Pointer ) bank ) ;
+}
+
+
+/************************** DoHaircells() *********************************/
+
+int DoHaircells( bank_ptr, bytes, output_ptr, end_output_ptr, input_ptr ) 
+    Pointer    *bank_ptr ;
+    ByteCount  *bytes ;
+    DataType   *output_ptr, *end_output_ptr, *input_ptr ;
+{
+    register HaircellBank *bank = ( HaircellBank * ) bank_ptr ;
+    register HaircellInfo *cell_info ;
+    register DataType     *input, *output ;
+    register StateType    *st ;
+    register StateType    in, out ;
+    register CoeffType    *cf ;
+    register double       inputGain ;
+    register int          channel = bank->channels ;
+    register int          point, npoints = ( end_output_ptr - output_ptr ) / bank->channels ;
+#ifdef _WDF_
+    register StateType    an, a0 ;
+#else
+    register StateType    replenish, eject, loss, reuptake, reprocess ;
+#endif
+
+    /*** for all channels ***/
+
+#ifdef _DEBUG_
+     fprintf( stderr, "DoHaircells() = %d points X %d channels\n", npoints, bank->channels ) ;
+#endif
+
+     cf = bank->coeffs ;
+
+     while( channel-- ) {
+
+	cell_info = bank->cells[ channel ] ;
+	st = cell_info->states ;
+	input = input_ptr + channel ;                
+	output = output_ptr + channel ;
+	inputGain = bank->update_proc( bank->inputGain_ratio[ channel ] ) ; 
+	cf[10] = cf[1] / inputGain ;                                    /* (A/p) */
+	cf[11] = cf[2] / inputGain ;                                    /* (A+B)/p */
+
+       /*** for each channel ***/
+
+	point = npoints ;  
+	while( point-- ) { 
+
+#ifdef _WDF_
+	  /*** compute compressive permeability function k ***/
+	   in = ( StateType ) *input ;                                  /* (BM vibration) */
+	   if( in > -cf[10] )
+	      st[0] = ( in + cf[10] ) / ( in + cf[11] ) ;               /* kn(t) / g */ 
+	   else
+	      st[0] = 0. ;
+
+	  /*** update gamma11 ***/
+	   cf[6] = st[0] / ( st[0] + cf[4] ) ;
+	   cf[6] += cf[6] ;                                             /* gamma11 */
+
+	  /*** compute wdf ***/
+
+	  /* Adaptor  B0 */
+	  st[5] = cf[0] + st[1] + st[2] ;                               /* -b03=a12 (normalized) */
+
+	  /* Adaptor B1 */
+	  st[6] = cf[6] * st[5] ;                                       /* -b11=2Ikn (normalized) */
+	  st[7] = st[6] - st[5] ;                                       /* b12=-a03 (normalized) */
+
+	  /* Adaptor B0 */
+	  st[2] = cf[0] + st[1] - st[7] + cf[5] * ( st[7] - st[5] ) ;   /* Ixn(t-T)-b02 (normalized) */
+
+	  /* Adaptor B2 */
+	  an = st[6] - st[3] ;                                          /* a24 (normalized) */ 
+	  a0 = an - st[3] ;                                             /* a20 (normalized) */
+	  st[8] = cf[8] * a0 ;                                          /* -b22=2Irn (normalized) */
+	  st[3] = cf[7] * a0 + st[8] - an ;                             /* b23 (normalized) */
+
+	  /* Adaptor B3 */
+	  an = st[8] - st[4] ;                                          /* a33 (normalized) */ 
+	  st[1] = cf[9] * ( an - st[4] ) ;                              /* Ixn(t)=-0.5*b31 (normalized) */
+	  st[4] = st[1] + st[1] - an ;                                  /* b32 (normalized) */
+
+#ifdef _CLAMPING_
+	  /*** clamping of reservoirs to non-negative quantities ***/
+	  /*** not available yet ***/
+#endif     
+
+	  /*** output ***/
+	   out = st[8] ;
+
+#else
+
+	  /*** compute change quantities ***/
+	   replenish = cf[4] * ( cf[0] - st[1] ) ;                     /* y(M-q) */
+	   eject     = st[0] * st[1] ;                                 /* kq */
+	   loss      = cf[5] * st[2] ;                                 /* lc */ 
+	   reuptake  = cf[6] * st[2] ;                                 /* rc */
+	   reprocess = cf[7] * st[3] ;                                 /* xw */
+
+	  /*** compute compressive permeability function kn_1dt ***/
+	   in = ( StateType ) *input ;                                 /* (BM vibration) */
+	   if( in > -cf[10] )
+	      st[0] = cf[3] * ( in + cf[10] ) / ( in + cf[11] ) ;      /* kn_1(t)dt */ 
+	   else
+	      st[0] = 0. ;
+
+	  /*** update reservoir quantities ***/
+	   st[1] += replenish - eject + reprocess ;                    /* q */
+	   st[2] += eject - loss - reuptake ;                          /* c */
+	   st[3] += reuptake - reprocess ;                             /* w */
+ 
+#ifdef _CLAMPING_
+	  /*** clamping of reservoirs to non-negative quantities ***/
+	   if( st[1] < 0 )
+	      st[1] = 0 ;
+	   if( st[2] < 0 )
+	      st[2] = 0 ;
+#endif
+
+	  /*** output ***/
+	   out = st[2] ; 
+
+#endif
+
+	  /*** output ***/
+#ifdef _OVERFLOW_  
+	   if( out > _MaxOutput_ ) 
+	      fprintf( stderr, "Overflow error in Meddis Haircell output\%e\n", ( double ) out ) ;
+#endif
+
+	   *output = ( DataType ) out ;
+
+	   output += bank->channels ;
+	   input  += bank->channels ;
+	}
+
+    }
+
+    return( npoints ) ;
+ }
+
+
+/************************** CloseHaircells() *********************************/
+
+void CloseHaircells( bank_ptr )
+    Pointer bank_ptr ;
+{
+    HaircellBank *bank = ( HaircellBank * ) bank_ptr ;
+    HaircellInfo *cell_info ;
+    int          channel ;
+
+    for( channel = 0 ; channel < bank->channels ; channel++) {
+       Delete( bank->cells[ channel ]->states ) ;
+       Delete( bank->cells[ channel ] ) ;
+    }
+    
+    Delete( bank->cells ) ;
+    Delete( bank->coeffs ) ;
+    Delete( bank->inputGain_ratio ) ; 
+    Delete( bank ) ;
+
+    return ;
+}
+
+
+/********** low level functions ************/
+
+double update_inputGain( ratio ) 
+  double ratio ;
+{
+  return( pow( 10., ( ratio - 0.5 ) * InputGain_max / 20. ) ) ; 
+}
+