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