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