Mercurial > hg > aim92
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 } |