Mercurial > hg > aim92
view tools/racf.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 source
/* Autocorrelation function using recursive "leaky integrator" filter ie. for the m'th lag, the n'th recursive update is: y[n] = a.y[n-1] + (1-a).f[n].f[n-m] where decay constant a = exp(-Ts/T) and Ts is sample interval in seconds T is decay time constant in seconds The recursion computes the mean value of the product f[n].f[n-m] within an exponential window which weights past values. The window width parameter (eg. corresponding with the width of the fft analysis window) is the time constant parameter. The half life of the exponential window is given by -T.ln(0.5) = 0.693T ie. for a given time constant, T secs, the window decays to half of its current value in a period of 0.693T secs. So T can be set to accomodate an expected period. As a rough guide, in a period of 0.5T the window decays to about 0.6 (ie by 60%), so set T to twice the expected period of the waveform to get 60% of the window over this period. Eg. if the waveform has an expected period of t ms, then to set 60% of the window to this period, set 0.5T = t ms, ie. T = 2t ms. The routine generates the autocovariance function. An optional normalization (dividing each coefficient by the zeroth coefficient) produces the autocorrelation function, (and this is then scaled up to the range [0-1000]). The output framewidth is the given maximum acf lag. Frames are selected from the input stream using the "frames" option, which has syntax: [[-]frame=a[-b]]. Input frames are numbered 1,2,... For example: frame=a Select just the a'th frame. frame=a-b Select frames from the a'th to b'th inclusive. The strings "min" and "max" can be used as specifiers, meaning eg: frame=min Select the first frame. frame=max Select the last frame. frame=a-max Select frames from the a'th to the last inclusive. frame=min-b Select frames from the first to the b'th inclusive. The default selects all frames, (ie frame=min-max). Examples: 1. To print the input and output frame sizes in sample points, eg for a subsequent plotting program, use the size option: acf ... size=on 2. An acf of a waveform sampled at 10kHz, computed to a max lag of 12.8ms, plotting the 2nd frame in a sequence of frames with frameshift 12.8ms. acf samp=10kHz frstep=12.8ms frame=2 lag=12.8ms file | x11plot 3. An animated plot of successive acf's of a waveform sampled at 10kHz, shifted by 2 sample points. acf samp=10kHz frstep=2p lag=12.8ms file | x11play -n128 */ #include <stdio.h> #include <math.h> #include "options.h" #include "units.h" #include "strmatch.h" #include "sigproc.h" char applic[] = "autocorrelation function of contiguous frames.\n i/p and o/p data in binary shorts." ; static char *helpstr, *debugstr, *sampstr, *startstr, *shiftstr, *sizestr ; static char *lagstr, *tcstr, *scalestr, *normstr, *framestr, *echostr ; static char *negstr, *upstr, *slopestr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "samplerate", "20kHz" , &sampstr , "Samplerate " , VAL }, { "start" , "0" , &startstr , "Start point in i/p file." , VAL }, { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL }, { "frstep" , "1ms" , &shiftstr , "Step between output frames." , VAL }, { "lag" , "32ms" , &lagstr , "Maximum acf lag (output frame width)." , VAL }, { "update" , "1p" , &upstr , "Step between recursive updates." , VAL }, { "timeconst" , "3ms" , &tcstr , "Decay time constant" , VAL }, { "normalize" , "off" , &normstr , "Normalized acf" , SETFLAG }, { "scale" , "0.003" , &scalestr , "scale output" , SVAL }, { "sigmoid" , "off" , &slopestr , "Sigmoidal weighting slope parameter" , SVAL }, { "size" , "off" , &sizestr , "Print input/output frame size in samples" , SETFLAG }, { "echo" , "off" , &echostr , "echo buffered input without processing", SVAL }, { "negative" , "off" , &negstr , "write negative half of acf (zeroth lag on right)", SVAL }, ( char * ) 0 } ; int samplerate ; int framestep ; int updatestep ; int maxlag ; double scale ; int normalize ; int echo ; int negative ; double alpha ; /* decay constant */ float *vec ; short *obuf ; main (argc, argv) int argc; char **argv; { FILE *fp ; int a, b ; fp = openopts( option,argc,argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], applic, option ) ; samplerate = to_Hz( sampstr ) ; normalize = ison( normstr ) ; echo = ison( echostr ) ; negative = ison( negstr ) ; framestep = to_p( shiftstr, samplerate ) ; updatestep = to_p( upstr , samplerate ) ; maxlag = to_p( lagstr , samplerate ) ; scale = atof( scalestr ) ; alpha = exp( -(double)( 1. / ( samplerate * to_s( tcstr, samplerate ) ) ) ) ; if ( framestep % updatestep != 0 ) { fprintf(stderr,"frstep [%dp] must be an integer multiple of update [%dp] \n", framestep, updatestep ) ; exit( 1 ) ; } /* frame size printout */ if ( ison( sizestr ) ) { fprintf(stderr,"acf sizes in sample points:\n" ) ; fprintf(stderr," output frame size = %d \n", maxlag ) ; exit( 0 ) ; } /* parse bounds on number of frames */ if ( selector( framestr, &a, &b ) == 0 ) { fprintf(stderr,"acf: bad frame selector [%s]\n", framestr ) ; exit( 1 ) ; } /* Allocate working space */ obuf = (short *)malloc( maxlag * sizeof(short) ) ; vec = (float *)malloc( maxlag * sizeof(float) ) ; /* Compute acf for each frame of width shorts in the input stream */ if ( seekbytes( fp, (int)( to_p( startstr, samplerate ) * sizeof(short) ) ) == 0 ) { fprintf(stderr,"improper seek\n") ; exit( 1 ) ; } if ( isoff( slopestr ) ) process( fp, a, b ) ; /* conventional acf recursion */ else process2( fp, a, b, atof( slopestr) ) ; /* sigmoidally weighted recursion */ /* (recommend set sigmoid=.02) */ fclose( fp ) ; } process( fp, a, b ) FILE *fp ; int a, b ; { register short *buf, *bptr, *endptr ; register float *vptr ; register double beta ; register int update_count = 0 ; register int frame_count = 0 ; /* Initialize process with the first maxlag samples */ if ( ( buf = getframe( fp, 1, maxlag, updatestep ) ) != (short *)0 ) { for ( endptr = buf ; endptr < buf + maxlag ; endptr++ ) { bptr = endptr ; vptr = vec ; beta = ( 1-alpha ) * *bptr ; while ( bptr >= buf ) *vptr++ = alpha * *vptr + beta * *bptr-- ; } update_count = 1 ; frame_count = 1 ; if ( frame_count >= a ) { if ( echo ) fwrite( buf, sizeof(short), maxlag, stdout ) ; else writeframe() ; } } /* Continue process with successive buffers of maxlag samples */ while ( ( buf = getframe( fp, ++update_count, maxlag, updatestep ) ) != (short *)0 && ( frame_count<=b || b==0 ) ) { bptr = buf + maxlag - 1 ; vptr = vec ; beta = ( 1-alpha ) * *bptr ; while ( bptr >= buf ) /* recursive update */ *vptr++ = alpha * *vptr + beta * *bptr-- ; if ( update_count % framestep == 1 ) { if ( ++frame_count >= a && ( frame_count <= b || b == 0 ) ) { if ( echo ) fwrite( buf, sizeof(short), maxlag, stdout ) ; else writeframe() ; } } } if ( frame_count <= b && b > 0 ) fprintf(stderr,"warning: not enough frames for request\n"); } writeframe() { register float *vptr = vec ; register short *optr = obuf ; register short *endlag = obuf + maxlag ; if ( normalize ) scale = 1000. / *vec ; while ( optr < endlag ) *optr++ = (short)( scale * *vptr++ ) ; if ( !negative ) fwrite( obuf, sizeof(short), maxlag, stdout ) ; else { for ( optr = endlag-1 ; optr >= obuf ; optr-- ) fwrite( optr, sizeof(short), 1, stdout ) ; } } /*************************************************************************/ /* same as `process', but with added sigmoidal weighting */ process2( fp, a, b, slope ) FILE *fp ; int a, b ; float slope ; { register short *buf, *bptr, *endptr ; register float *vptr ; register double beta ; register int update_count = 0 ; register int frame_count = 0 ; double sigmoid() ; /* Initialize process with the first maxlag samples */ if ( ( buf = getframe( fp, 1, maxlag, updatestep ) ) != (short *)0 ) { for ( endptr = buf ; endptr < buf + maxlag ; endptr++ ) { bptr = endptr ; vptr = vec ; beta = ( 1-alpha ) * *bptr ; while ( bptr >= buf ) *vptr++ = alpha * *vptr + beta * sigmoid( fabs((double)*endptr) - fabs((double)*bptr ), slope ) * *bptr-- ; } update_count = 1 ; frame_count = 1 ; if ( frame_count >= a ) { if ( echo ) fwrite( buf, sizeof(short), maxlag, stdout ) ; else writeframe() ; } } /* Continue process with successive buffers of maxlag samples */ while ( ( buf = getframe( fp, ++update_count, maxlag, updatestep ) ) != (short *)0 && ( frame_count<=b || b==0 ) ) { endptr = buf + maxlag - 1 ; bptr = endptr ; vptr = vec ; beta = ( 1-alpha ) * *bptr ; while ( bptr >= buf ) /* recursive update */ *vptr++ = alpha * *vptr + beta * sigmoid( fabs((double)*endptr) - fabs((double)*bptr ), slope ) * *bptr-- ; if ( update_count % framestep == 1 ) { if ( ++frame_count >= a && ( frame_count <= b || b == 0 ) ) { if ( echo ) fwrite( buf, sizeof(short), maxlag, stdout ) ; else writeframe() ; } } } if ( frame_count <= b && b > 0 ) fprintf(stderr,"warning: not enough frames for request\n"); } double sigmoid( x, slope ) double x ; float slope ; { return (double)( 1. / ( exp( -(double)( 4.595 + slope * x ) ) + 1. ) ) ; }