annotate tools/acf.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 FFT routines adapted from routines given in
tomwalters@0 3 Numerical Recipes.
tomwalters@0 4 The routine acf() uses an fft to compute the array of lagged products
tomwalters@0 5 which is the autocovariance function. An optional normalization (dividing
tomwalters@0 6 each coefficient by the zeroth coefficient) produces the autocorrelation
tomwalters@0 7 function, (and this is then scaled up to the range [0-1000]).
tomwalters@0 8
tomwalters@0 9 The output framewidth is the given maximum acf lag, which must not be
tomwalters@0 10 greater than the input framewidth.
tomwalters@0 11
tomwalters@0 12 Padding with zeroes is recommended to counter end-effects (See NR, p416).
tomwalters@0 13 It is also necessary since:
tomwalters@0 14 1) framesize + padding must be a power of two (sample points at given rate).
tomwalters@0 15 2) max possible acf lag = ( framesize + padding ) / 2
tomwalters@0 16
tomwalters@0 17 Each input frame is padded with zeroes so that it is at least twice the
tomwalters@0 18 required max acf lag, and is also a power of 2.
tomwalters@0 19 This is because the fft method is "radix-2", and because the output acf is
tomwalters@0 20 symmetrical so that just half the points are unique.
tomwalters@0 21 Therefore each input frame is padded with zeroes to the next power of 2
tomwalters@0 22 larger than either the input framewidth, or twice the required max acf lag,
tomwalters@0 23 (whichever is the larger).
tomwalters@0 24
tomwalters@0 25 If necessary, extra padding can be enforced using the padding option to
tomwalters@0 26 add extra zeroes, padding to a larger power of 2.
tomwalters@0 27 The amount of extra padding is "exponential", expanding the basic size to:
tomwalters@0 28 ( framesize + padding ) * 2**n
tomwalters@0 29 where the padding option is n.
tomwalters@0 30 (n=0 by default, so that no extra padding is added. When n=1 then padding is
tomwalters@0 31 added to double the size, and when n=2 the size is quadrupled, etc.).
tomwalters@0 32
tomwalters@0 33 Frames are selected from the input stream using the "frames" option,
tomwalters@0 34 which has syntax: [[-]frame=a[-b]]. Input frames are numbered 1,2,...
tomwalters@0 35 For example:
tomwalters@0 36 frame=a Select just the a'th frame.
tomwalters@0 37 frame=a-b Select frames from the a'th to b'th inclusive.
tomwalters@0 38 The strings "min" and "max" can be used as specifiers, meaning eg:
tomwalters@0 39 frame=min Select the first frame.
tomwalters@0 40 frame=max Select the last frame.
tomwalters@0 41 frame=a-max Select frames from the a'th to the last inclusive.
tomwalters@0 42 frame=min-b Select frames from the first to the b'th inclusive.
tomwalters@0 43 The default selects all frames, (ie frame=min-max).
tomwalters@0 44
tomwalters@0 45 Other options (set using <option>=on):
tomwalters@0 46 size Print the input and output frame sizes in sample points.
tomwalters@0 47 echo Echo buffered input without processing.
tomwalters@0 48 negative Write negative half of acf (ie. with zeroth lag on right).
tomwalters@0 49
tomwalters@0 50
tomwalters@0 51 Examples:
tomwalters@0 52
tomwalters@0 53 1. To print the input and output frame sizes in sample points, eg for a
tomwalters@0 54 subsequent plotting program, use the size option:
tomwalters@0 55
tomwalters@0 56 acf ... size=on
tomwalters@0 57
tomwalters@0 58 2. An acf of a waveform sampled at 10kHz, computed to a max lag of 12.8ms
tomwalters@0 59 within a frame of 12.8ms, plotting the 2nd frame in a sequence of frames
tomwalters@0 60 with frameshift 12.8ms.
tomwalters@0 61
tomwalters@0 62 acf samp=10kHz width=12.8ms frstep=12.8ms frame=2 lag=12.8ms file | x11plot
tomwalters@0 63
tomwalters@0 64 3. An animated plot of successive acf's of a waveform sampled at 10kHz,
tomwalters@0 65 each computed within a frame of 12.8ms, and shifted by 2 sample points.
tomwalters@0 66
tomwalters@0 67 acf samp=10kHz width=12.8ms frstep=2p lag=12.8ms file | x11play -n128
tomwalters@0 68
tomwalters@0 69 */
tomwalters@0 70
tomwalters@0 71 #include <stdio.h>
tomwalters@0 72 #include <math.h>
tomwalters@0 73 #include "options.h"
tomwalters@0 74 #include "units.h"
tomwalters@0 75 #include "strmatch.h"
tomwalters@0 76 #include "sigproc.h"
tomwalters@0 77
tomwalters@0 78 char applic[] = "autocorrelation function of contiguous frames.\n i/p and o/p data in binary shorts." ;
tomwalters@0 79
tomwalters@0 80 static char *helpstr, *debugstr, *sampstr, *startstr, *shiftstr, *widthstr, *sizestr ;
tomwalters@0 81 static char *padstr, *wstr, *lagstr, *scalestr, *normstr, *framestr, *echostr, *negstr ;
tomwalters@0 82
tomwalters@0 83 static Options option[] = {
tomwalters@0 84 { "help" , "off" , &helpstr , "help" , DEBUG },
tomwalters@0 85 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
tomwalters@0 86 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL },
tomwalters@0 87 { "start" , "0" , &startstr , "Start point in i/p file." , VAL },
tomwalters@0 88 { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL },
tomwalters@0 89 { "frstep" , "16ms" , &shiftstr , "Step between input frames." , VAL },
tomwalters@0 90 { "width" , "32ms" , &widthstr , "Width of input frames." , VAL },
tomwalters@0 91 { "lag" , "32ms" , &lagstr , "Maximum acf lag (output frame width)." , VAL },
tomwalters@0 92 { "padding" , "0" , &padstr , "Exponential frame padding" , SVAL },
tomwalters@0 93 { "window" , "on" , &wstr , "Hamming window" , SETFLAG },
tomwalters@0 94 { "normalize" , "off" , &normstr , "normalized acf" , SETFLAG },
tomwalters@0 95 { "scale" , "0.025" , &scalestr , "scale output" , SVAL },
tomwalters@0 96 { "size" , "off" , &sizestr , "print input/output frame size in samples" , SETFLAG },
tomwalters@0 97 { "echo" , "off" , &echostr , "echo buffered input without processing", SVAL },
tomwalters@0 98 { "negative" , "off" , &negstr , "write negative half of acf (zeroth lag on right)", SVAL },
tomwalters@0 99 ( char * ) 0 } ;
tomwalters@0 100
tomwalters@0 101
tomwalters@0 102 int samplerate ;
tomwalters@0 103 int width ;
tomwalters@0 104 int step ;
tomwalters@0 105 int zeroes ;
tomwalters@0 106 int maxlag ;
tomwalters@0 107 int dowindow ;
tomwalters@0 108 double scale ;
tomwalters@0 109 int normalize ;
tomwalters@0 110 int echo ;
tomwalters@0 111 int negative ;
tomwalters@0 112
tomwalters@0 113 float *vec, *window ;
tomwalters@0 114 short *obuf ;
tomwalters@0 115
tomwalters@0 116 main (argc, argv)
tomwalters@0 117 int argc;
tomwalters@0 118 char **argv;
tomwalters@0 119 {
tomwalters@0 120 FILE *fp ;
tomwalters@0 121 short *buf ;
tomwalters@0 122 int a, b ;
tomwalters@0 123
tomwalters@0 124 fp = openopts( option,argc,argv ) ;
tomwalters@0 125 if ( !isoff( helpstr ) )
tomwalters@0 126 helpopts( helpstr, argv[0], applic, option ) ;
tomwalters@0 127
tomwalters@0 128 samplerate = to_Hz( sampstr ) ;
tomwalters@0 129 dowindow = ison( wstr ) ;
tomwalters@0 130 normalize = ison( normstr ) ;
tomwalters@0 131 echo = ison( echostr ) ;
tomwalters@0 132 negative = ison( negstr ) ;
tomwalters@0 133
tomwalters@0 134 width = to_p( widthstr, samplerate ) ;
tomwalters@0 135 step = to_p( shiftstr, samplerate ) ;
tomwalters@0 136 maxlag = to_p( lagstr , samplerate ) ;
tomwalters@0 137
tomwalters@0 138 if ( ( maxlag << 1 ) < width )
tomwalters@0 139 zeroes = ( getpower( width ) << atoi( padstr ) ) - width ;
tomwalters@0 140 else if ( maxlag <= width )
tomwalters@0 141 zeroes = ( getpower( maxlag << 1 ) << atoi( padstr ) ) - width ;
tomwalters@0 142 else {
tomwalters@0 143 fprintf(stderr,"acf: required max lag [%dms] greater than framewidth [%dms]\n", maxlag*1000/samplerate, width*1000/samplerate);
tomwalters@0 144 exit( 1 ) ;
tomwalters@0 145 }
tomwalters@0 146
tomwalters@0 147 scale = ( 1./(double)(width+zeroes) ) * atof( scalestr ) ;
tomwalters@0 148
tomwalters@0 149 /* frame size printout */
tomwalters@0 150
tomwalters@0 151 if ( ison( sizestr ) ) {
tomwalters@0 152 fprintf(stderr,"acf sizes in sample points:\n" ) ;
tomwalters@0 153 fprintf(stderr," input frame size = %d (framewidth=%d + padding=%d)\n", width+zeroes, width, zeroes ) ;
tomwalters@0 154 fprintf(stderr," output frame size = %d \n", maxlag ) ;
tomwalters@0 155 exit( 0 ) ;
tomwalters@0 156 }
tomwalters@0 157
tomwalters@0 158 /* parse bounds on number of frames */
tomwalters@0 159
tomwalters@0 160 if ( selector( framestr, &a, &b ) == 0 ) {
tomwalters@0 161 fprintf(stderr,"acf: bad frame selector [%s]\n", framestr ) ;
tomwalters@0 162 exit( 1 ) ;
tomwalters@0 163 }
tomwalters@0 164
tomwalters@0 165 /* Allocate working space */
tomwalters@0 166
tomwalters@0 167 obuf = (short *)malloc( maxlag * sizeof(short) ) ;
tomwalters@0 168 vec = (float *)malloc( width+zeroes * sizeof(float) ) ;
tomwalters@0 169 if ( dowindow )
tomwalters@0 170 window = hamming( width ) ;
tomwalters@0 171
tomwalters@0 172 /* Compute acf for each frame of width shorts in the input stream */
tomwalters@0 173
tomwalters@0 174 if ( seekbytes( fp, (int)( to_p( startstr, samplerate ) * sizeof(short) ) ) == 0 ) {
tomwalters@0 175 fprintf(stderr,"improper seek\n") ;
tomwalters@0 176 exit( 1 ) ;
tomwalters@0 177 }
tomwalters@0 178
tomwalters@0 179 while ( ( buf = getframe( fp, a, width, step ) ) != (short *)0 && ( a<=b || b==0 ) ) {
tomwalters@0 180 if ( echo ) fwrite( buf, sizeof(short), width, stdout ) ;
tomwalters@0 181 else process( buf ) ;
tomwalters@0 182 a++ ;
tomwalters@0 183 }
tomwalters@0 184 if ( a<=b && b>0 )
tomwalters@0 185 fprintf(stderr,"warning: not enough frames for request\n");
tomwalters@0 186
tomwalters@0 187 fclose( fp ) ;
tomwalters@0 188 }
tomwalters@0 189
tomwalters@0 190
tomwalters@0 191 process( buf )
tomwalters@0 192 short *buf ;
tomwalters@0 193 {
tomwalters@0 194 short *bptr = buf ;
tomwalters@0 195 short *endptr = buf + width ;
tomwalters@0 196 short *optr = obuf ;
tomwalters@0 197 short *endlag = obuf + maxlag ;
tomwalters@0 198 float *wptr = window ;
tomwalters@0 199 float *vptr = vec ;
tomwalters@0 200 float *endvec = vec + width + zeroes ;
tomwalters@0 201
tomwalters@0 202 if ( dowindow )
tomwalters@0 203 while ( bptr < endptr )
tomwalters@0 204 *vptr++ = *bptr++ * *wptr++ ;
tomwalters@0 205 else
tomwalters@0 206 while ( bptr < endptr )
tomwalters@0 207 *vptr++ = *bptr++ ;
tomwalters@0 208
tomwalters@0 209 while ( vptr < endvec ) /* padding */
tomwalters@0 210 *vptr++ = 0 ;
tomwalters@0 211
tomwalters@0 212 acf( vec, width+zeroes ) ;
tomwalters@0 213
tomwalters@0 214 if ( normalize )
tomwalters@0 215 scale = 1000. / *vec ;
tomwalters@0 216
tomwalters@0 217 vptr = vec ;
tomwalters@0 218 while ( optr < endlag )
tomwalters@0 219 *optr++ = (short)( scale * *vptr++ ) ;
tomwalters@0 220
tomwalters@0 221 if ( !negative )
tomwalters@0 222 fwrite( obuf, sizeof(short), maxlag, stdout ) ;
tomwalters@0 223 else {
tomwalters@0 224 for ( optr = endlag-1 ; optr >= obuf ; optr-- ) /* write in reverse */
tomwalters@0 225 fwrite( optr, sizeof(short), 1, stdout ) ;
tomwalters@0 226 }
tomwalters@0 227 }
tomwalters@0 228
tomwalters@0 229