annotate 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
rev   line source
tomwalters@0 1 /*
tomwalters@0 2 Autocorrelation function using recursive "leaky integrator" filter
tomwalters@0 3 ie. for the m'th lag, the n'th recursive update is:
tomwalters@0 4
tomwalters@0 5 y[n] = a.y[n-1] + (1-a).f[n].f[n-m]
tomwalters@0 6
tomwalters@0 7 where decay constant a = exp(-Ts/T)
tomwalters@0 8 and Ts is sample interval in seconds
tomwalters@0 9 T is decay time constant in seconds
tomwalters@0 10
tomwalters@0 11 The recursion computes the mean value of the product f[n].f[n-m]
tomwalters@0 12 within an exponential window which weights past values.
tomwalters@0 13 The window width parameter (eg. corresponding with the width of the
tomwalters@0 14 fft analysis window) is the time constant parameter.
tomwalters@0 15 The half life of the exponential window is given by -T.ln(0.5) = 0.693T
tomwalters@0 16 ie. for a given time constant, T secs, the window decays to half of its
tomwalters@0 17 current value in a period of 0.693T secs.
tomwalters@0 18 So T can be set to accomodate an expected period.
tomwalters@0 19 As a rough guide, in a period of 0.5T the window decays to about 0.6
tomwalters@0 20 (ie by 60%), so set T to twice the expected period of the waveform to
tomwalters@0 21 get 60% of the window over this period.
tomwalters@0 22 Eg. if the waveform has an expected period of t ms, then to set 60% of
tomwalters@0 23 the window to this period, set 0.5T = t ms, ie. T = 2t ms.
tomwalters@0 24
tomwalters@0 25 The routine generates the autocovariance function.
tomwalters@0 26 An optional normalization (dividing each coefficient by the zeroth
tomwalters@0 27 coefficient) produces the autocorrelation function,
tomwalters@0 28 (and this is then scaled up to the range [0-1000]).
tomwalters@0 29
tomwalters@0 30 The output framewidth is the given maximum acf lag.
tomwalters@0 31
tomwalters@0 32 Frames are selected from the input stream using the "frames" option,
tomwalters@0 33 which has syntax: [[-]frame=a[-b]]. Input frames are numbered 1,2,...
tomwalters@0 34 For example:
tomwalters@0 35 frame=a Select just the a'th frame.
tomwalters@0 36 frame=a-b Select frames from the a'th to b'th inclusive.
tomwalters@0 37 The strings "min" and "max" can be used as specifiers, meaning eg:
tomwalters@0 38 frame=min Select the first frame.
tomwalters@0 39 frame=max Select the last frame.
tomwalters@0 40 frame=a-max Select frames from the a'th to the last inclusive.
tomwalters@0 41 frame=min-b Select frames from the first to the b'th inclusive.
tomwalters@0 42 The default selects all frames, (ie frame=min-max).
tomwalters@0 43
tomwalters@0 44
tomwalters@0 45 Examples:
tomwalters@0 46
tomwalters@0 47 1. To print the input and output frame sizes in sample points, eg for a
tomwalters@0 48 subsequent plotting program, use the size option:
tomwalters@0 49
tomwalters@0 50 acf ... size=on
tomwalters@0 51
tomwalters@0 52 2. An acf of a waveform sampled at 10kHz, computed to a max lag of 12.8ms,
tomwalters@0 53 plotting the 2nd frame in a sequence of frames with frameshift 12.8ms.
tomwalters@0 54
tomwalters@0 55 acf samp=10kHz frstep=12.8ms frame=2 lag=12.8ms file | x11plot
tomwalters@0 56
tomwalters@0 57 3. An animated plot of successive acf's of a waveform sampled at 10kHz,
tomwalters@0 58 shifted by 2 sample points.
tomwalters@0 59
tomwalters@0 60 acf samp=10kHz frstep=2p lag=12.8ms file | x11play -n128
tomwalters@0 61
tomwalters@0 62 */
tomwalters@0 63
tomwalters@0 64 #include <stdio.h>
tomwalters@0 65 #include <math.h>
tomwalters@0 66 #include "options.h"
tomwalters@0 67 #include "units.h"
tomwalters@0 68 #include "strmatch.h"
tomwalters@0 69 #include "sigproc.h"
tomwalters@0 70
tomwalters@0 71 char applic[] = "autocorrelation function of contiguous frames.\n i/p and o/p data in binary shorts." ;
tomwalters@0 72
tomwalters@0 73 static char *helpstr, *debugstr, *sampstr, *startstr, *shiftstr, *sizestr ;
tomwalters@0 74 static char *lagstr, *tcstr, *scalestr, *normstr, *framestr, *echostr ;
tomwalters@0 75 static char *negstr, *upstr, *slopestr ;
tomwalters@0 76
tomwalters@0 77 static Options option[] = {
tomwalters@0 78 { "help" , "off" , &helpstr , "help" , DEBUG },
tomwalters@0 79 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
tomwalters@0 80 { "samplerate", "20kHz" , &sampstr , "Samplerate " , VAL },
tomwalters@0 81 { "start" , "0" , &startstr , "Start point in i/p file." , VAL },
tomwalters@0 82 { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL },
tomwalters@0 83 { "frstep" , "1ms" , &shiftstr , "Step between output frames." , VAL },
tomwalters@0 84 { "lag" , "32ms" , &lagstr , "Maximum acf lag (output frame width)." , VAL },
tomwalters@0 85 { "update" , "1p" , &upstr , "Step between recursive updates." , VAL },
tomwalters@0 86 { "timeconst" , "3ms" , &tcstr , "Decay time constant" , VAL },
tomwalters@0 87 { "normalize" , "off" , &normstr , "Normalized acf" , SETFLAG },
tomwalters@0 88 { "scale" , "0.003" , &scalestr , "scale output" , SVAL },
tomwalters@0 89 { "sigmoid" , "off" , &slopestr , "Sigmoidal weighting slope parameter" , SVAL },
tomwalters@0 90 { "size" , "off" , &sizestr , "Print input/output frame size in samples" , SETFLAG },
tomwalters@0 91 { "echo" , "off" , &echostr , "echo buffered input without processing", SVAL },
tomwalters@0 92 { "negative" , "off" , &negstr , "write negative half of acf (zeroth lag on right)", SVAL },
tomwalters@0 93 ( char * ) 0 } ;
tomwalters@0 94
tomwalters@0 95
tomwalters@0 96 int samplerate ;
tomwalters@0 97 int framestep ;
tomwalters@0 98 int updatestep ;
tomwalters@0 99 int maxlag ;
tomwalters@0 100 double scale ;
tomwalters@0 101 int normalize ;
tomwalters@0 102 int echo ;
tomwalters@0 103 int negative ;
tomwalters@0 104 double alpha ; /* decay constant */
tomwalters@0 105
tomwalters@0 106 float *vec ;
tomwalters@0 107 short *obuf ;
tomwalters@0 108
tomwalters@0 109 main (argc, argv)
tomwalters@0 110 int argc;
tomwalters@0 111 char **argv;
tomwalters@0 112 {
tomwalters@0 113 FILE *fp ;
tomwalters@0 114 int a, b ;
tomwalters@0 115
tomwalters@0 116 fp = openopts( option,argc,argv ) ;
tomwalters@0 117 if ( !isoff( helpstr ) )
tomwalters@0 118 helpopts( helpstr, argv[0], applic, option ) ;
tomwalters@0 119
tomwalters@0 120 samplerate = to_Hz( sampstr ) ;
tomwalters@0 121 normalize = ison( normstr ) ;
tomwalters@0 122 echo = ison( echostr ) ;
tomwalters@0 123 negative = ison( negstr ) ;
tomwalters@0 124
tomwalters@0 125 framestep = to_p( shiftstr, samplerate ) ;
tomwalters@0 126 updatestep = to_p( upstr , samplerate ) ;
tomwalters@0 127 maxlag = to_p( lagstr , samplerate ) ;
tomwalters@0 128
tomwalters@0 129 scale = atof( scalestr ) ;
tomwalters@0 130
tomwalters@0 131 alpha = exp( -(double)( 1. / ( samplerate * to_s( tcstr, samplerate ) ) ) ) ;
tomwalters@0 132
tomwalters@0 133 if ( framestep % updatestep != 0 ) {
tomwalters@0 134 fprintf(stderr,"frstep [%dp] must be an integer multiple of update [%dp] \n", framestep, updatestep ) ;
tomwalters@0 135 exit( 1 ) ;
tomwalters@0 136 }
tomwalters@0 137
tomwalters@0 138 /* frame size printout */
tomwalters@0 139
tomwalters@0 140 if ( ison( sizestr ) ) {
tomwalters@0 141 fprintf(stderr,"acf sizes in sample points:\n" ) ;
tomwalters@0 142 fprintf(stderr," output frame size = %d \n", maxlag ) ;
tomwalters@0 143 exit( 0 ) ;
tomwalters@0 144 }
tomwalters@0 145
tomwalters@0 146 /* parse bounds on number of frames */
tomwalters@0 147
tomwalters@0 148 if ( selector( framestr, &a, &b ) == 0 ) {
tomwalters@0 149 fprintf(stderr,"acf: bad frame selector [%s]\n", framestr ) ;
tomwalters@0 150 exit( 1 ) ;
tomwalters@0 151 }
tomwalters@0 152
tomwalters@0 153 /* Allocate working space */
tomwalters@0 154
tomwalters@0 155 obuf = (short *)malloc( maxlag * sizeof(short) ) ;
tomwalters@0 156 vec = (float *)malloc( maxlag * sizeof(float) ) ;
tomwalters@0 157
tomwalters@0 158 /* Compute acf for each frame of width shorts in the input stream */
tomwalters@0 159
tomwalters@0 160 if ( seekbytes( fp, (int)( to_p( startstr, samplerate ) * sizeof(short) ) ) == 0 ) {
tomwalters@0 161 fprintf(stderr,"improper seek\n") ;
tomwalters@0 162 exit( 1 ) ;
tomwalters@0 163 }
tomwalters@0 164
tomwalters@0 165 if ( isoff( slopestr ) )
tomwalters@0 166 process( fp, a, b ) ; /* conventional acf recursion */
tomwalters@0 167 else
tomwalters@0 168 process2( fp, a, b, atof( slopestr) ) ; /* sigmoidally weighted recursion */
tomwalters@0 169 /* (recommend set sigmoid=.02) */
tomwalters@0 170
tomwalters@0 171 fclose( fp ) ;
tomwalters@0 172 }
tomwalters@0 173
tomwalters@0 174
tomwalters@0 175 process( fp, a, b )
tomwalters@0 176 FILE *fp ;
tomwalters@0 177 int a, b ;
tomwalters@0 178 {
tomwalters@0 179 register short *buf, *bptr, *endptr ;
tomwalters@0 180 register float *vptr ;
tomwalters@0 181 register double beta ;
tomwalters@0 182 register int update_count = 0 ;
tomwalters@0 183 register int frame_count = 0 ;
tomwalters@0 184
tomwalters@0 185 /* Initialize process with the first maxlag samples */
tomwalters@0 186
tomwalters@0 187 if ( ( buf = getframe( fp, 1, maxlag, updatestep ) ) != (short *)0 ) {
tomwalters@0 188 for ( endptr = buf ; endptr < buf + maxlag ; endptr++ ) {
tomwalters@0 189 bptr = endptr ;
tomwalters@0 190 vptr = vec ;
tomwalters@0 191 beta = ( 1-alpha ) * *bptr ;
tomwalters@0 192 while ( bptr >= buf )
tomwalters@0 193 *vptr++ = alpha * *vptr + beta * *bptr-- ;
tomwalters@0 194 }
tomwalters@0 195
tomwalters@0 196 update_count = 1 ;
tomwalters@0 197 frame_count = 1 ;
tomwalters@0 198
tomwalters@0 199 if ( frame_count >= a ) {
tomwalters@0 200 if ( echo )
tomwalters@0 201 fwrite( buf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 202 else
tomwalters@0 203 writeframe() ;
tomwalters@0 204 }
tomwalters@0 205 }
tomwalters@0 206
tomwalters@0 207 /* Continue process with successive buffers of maxlag samples */
tomwalters@0 208
tomwalters@0 209 while ( ( buf = getframe( fp, ++update_count, maxlag, updatestep ) ) != (short *)0 && ( frame_count<=b || b==0 ) ) {
tomwalters@0 210 bptr = buf + maxlag - 1 ;
tomwalters@0 211 vptr = vec ;
tomwalters@0 212 beta = ( 1-alpha ) * *bptr ;
tomwalters@0 213
tomwalters@0 214 while ( bptr >= buf ) /* recursive update */
tomwalters@0 215 *vptr++ = alpha * *vptr + beta * *bptr-- ;
tomwalters@0 216
tomwalters@0 217 if ( update_count % framestep == 1 ) {
tomwalters@0 218 if ( ++frame_count >= a && ( frame_count <= b || b == 0 ) ) {
tomwalters@0 219 if ( echo )
tomwalters@0 220 fwrite( buf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 221 else
tomwalters@0 222 writeframe() ;
tomwalters@0 223 }
tomwalters@0 224 }
tomwalters@0 225 }
tomwalters@0 226 if ( frame_count <= b && b > 0 )
tomwalters@0 227 fprintf(stderr,"warning: not enough frames for request\n");
tomwalters@0 228 }
tomwalters@0 229
tomwalters@0 230
tomwalters@0 231 writeframe()
tomwalters@0 232 {
tomwalters@0 233 register float *vptr = vec ;
tomwalters@0 234 register short *optr = obuf ;
tomwalters@0 235 register short *endlag = obuf + maxlag ;
tomwalters@0 236
tomwalters@0 237 if ( normalize )
tomwalters@0 238 scale = 1000. / *vec ;
tomwalters@0 239
tomwalters@0 240 while ( optr < endlag )
tomwalters@0 241 *optr++ = (short)( scale * *vptr++ ) ;
tomwalters@0 242
tomwalters@0 243 if ( !negative )
tomwalters@0 244 fwrite( obuf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 245 else {
tomwalters@0 246 for ( optr = endlag-1 ; optr >= obuf ; optr-- )
tomwalters@0 247 fwrite( optr, sizeof(short), 1, stdout ) ;
tomwalters@0 248 }
tomwalters@0 249 }
tomwalters@0 250
tomwalters@0 251
tomwalters@0 252 /*************************************************************************/
tomwalters@0 253 /*
tomwalters@0 254 same as `process', but with added sigmoidal weighting
tomwalters@0 255 */
tomwalters@0 256
tomwalters@0 257 process2( fp, a, b, slope )
tomwalters@0 258 FILE *fp ;
tomwalters@0 259 int a, b ;
tomwalters@0 260 float slope ;
tomwalters@0 261 {
tomwalters@0 262 register short *buf, *bptr, *endptr ;
tomwalters@0 263 register float *vptr ;
tomwalters@0 264 register double beta ;
tomwalters@0 265 register int update_count = 0 ;
tomwalters@0 266 register int frame_count = 0 ;
tomwalters@0 267 double sigmoid() ;
tomwalters@0 268
tomwalters@0 269 /* Initialize process with the first maxlag samples */
tomwalters@0 270
tomwalters@0 271 if ( ( buf = getframe( fp, 1, maxlag, updatestep ) ) != (short *)0 ) {
tomwalters@0 272 for ( endptr = buf ; endptr < buf + maxlag ; endptr++ ) {
tomwalters@0 273 bptr = endptr ;
tomwalters@0 274 vptr = vec ;
tomwalters@0 275 beta = ( 1-alpha ) * *bptr ;
tomwalters@0 276 while ( bptr >= buf )
tomwalters@0 277 *vptr++ = alpha * *vptr + beta * sigmoid( fabs((double)*endptr) - fabs((double)*bptr ), slope ) * *bptr-- ;
tomwalters@0 278 }
tomwalters@0 279
tomwalters@0 280 update_count = 1 ;
tomwalters@0 281 frame_count = 1 ;
tomwalters@0 282
tomwalters@0 283 if ( frame_count >= a ) {
tomwalters@0 284 if ( echo )
tomwalters@0 285 fwrite( buf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 286 else
tomwalters@0 287 writeframe() ;
tomwalters@0 288 }
tomwalters@0 289 }
tomwalters@0 290
tomwalters@0 291 /* Continue process with successive buffers of maxlag samples */
tomwalters@0 292
tomwalters@0 293 while ( ( buf = getframe( fp, ++update_count, maxlag, updatestep ) ) != (short *)0 && ( frame_count<=b || b==0 ) ) {
tomwalters@0 294 endptr = buf + maxlag - 1 ;
tomwalters@0 295 bptr = endptr ;
tomwalters@0 296 vptr = vec ;
tomwalters@0 297 beta = ( 1-alpha ) * *bptr ;
tomwalters@0 298
tomwalters@0 299 while ( bptr >= buf ) /* recursive update */
tomwalters@0 300 *vptr++ = alpha * *vptr + beta * sigmoid( fabs((double)*endptr) - fabs((double)*bptr ), slope ) * *bptr-- ;
tomwalters@0 301
tomwalters@0 302 if ( update_count % framestep == 1 ) {
tomwalters@0 303 if ( ++frame_count >= a && ( frame_count <= b || b == 0 ) ) {
tomwalters@0 304 if ( echo )
tomwalters@0 305 fwrite( buf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 306 else
tomwalters@0 307 writeframe() ;
tomwalters@0 308 }
tomwalters@0 309 }
tomwalters@0 310 }
tomwalters@0 311 if ( frame_count <= b && b > 0 )
tomwalters@0 312 fprintf(stderr,"warning: not enough frames for request\n");
tomwalters@0 313 }
tomwalters@0 314
tomwalters@0 315
tomwalters@0 316 double sigmoid( x, slope )
tomwalters@0 317 double x ;
tomwalters@0 318 float slope ;
tomwalters@0 319 {
tomwalters@0 320 return (double)( 1. / ( exp( -(double)( 4.595 + slope * x ) ) + 1. ) ) ;
tomwalters@0 321 }