tomwalters@0
|
1 /*
|
tomwalters@0
|
2 stats.c calculate some statistics (min, max, mean etc.)
|
tomwalters@0
|
3 -------
|
tomwalters@0
|
4
|
tomwalters@0
|
5 */
|
tomwalters@0
|
6
|
tomwalters@0
|
7 #include <stdio.h>
|
tomwalters@0
|
8 #include <math.h>
|
tomwalters@0
|
9 #include "options.h"
|
tomwalters@0
|
10 #include "units.h"
|
tomwalters@0
|
11 #include "strmatch.h"
|
tomwalters@0
|
12
|
tomwalters@0
|
13 char applic[] = "print statistics of input files" ;
|
tomwalters@0
|
14
|
tomwalters@0
|
15 static char *helpstr, *debugstr, *typestr, *statstr ;
|
tomwalters@0
|
16 static char *sampstr, *frstr, *widstr, *sizestr ;
|
tomwalters@0
|
17 static char *linestr, *precstr, *fieldstr ;
|
tomwalters@0
|
18
|
tomwalters@0
|
19 static Options option[] = {
|
tomwalters@0
|
20 { "help" , "off" , &helpstr , "help" , DEBUG },
|
tomwalters@0
|
21 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
|
tomwalters@0
|
22 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL },
|
tomwalters@0
|
23 { "frame" , "1" , &frstr , "select frames inclusively" , VAL },
|
tomwalters@0
|
24 { "width" , "max" , &widstr , "frame width" , VAL },
|
tomwalters@0
|
25 { "type" , "short" , &typestr , "data type" , VAL },
|
tomwalters@0
|
26 { "stat" , "mean" , &statstr , "statistic list (comma separated)" , VAL },
|
tomwalters@0
|
27 { "line" , "off" , &linestr , "force ascii output" , SETFLAG },
|
tomwalters@0
|
28 { "fieldwidth", "10" , &fieldstr , "field width for ascii printing", SVAL },
|
tomwalters@0
|
29 { "precision" , "3" , &precstr , "precision for ascii printing" , SVAL },
|
tomwalters@0
|
30 { "SIZE" , "262144p" , &sizestr , "buffer size (s, ms, or p)" , SVAL },
|
tomwalters@0
|
31 ( char * ) 0 } ;
|
tomwalters@0
|
32
|
tomwalters@0
|
33
|
tomwalters@0
|
34 typedef float (*PF)() ; /* pointer-to-function type returning float */
|
tomwalters@0
|
35
|
tomwalters@0
|
36 typedef struct { /* a struct to hold both function name and pointer */
|
tomwalters@0
|
37 char *name ; /* string name of function */
|
tomwalters@0
|
38 PF func ; /* pointer to function */
|
tomwalters@0
|
39 char *help ; /* explanation of use */
|
tomwalters@0
|
40 } Func ;
|
tomwalters@0
|
41
|
tomwalters@0
|
42
|
tomwalters@0
|
43 float num(), sum(), sumabs(), sumsq(), mean() ;
|
tomwalters@0
|
44 float rms(), variance(), stddev(), min(), max() ;
|
tomwalters@0
|
45 float absmax(), absrange(), pc() ;
|
tomwalters@0
|
46
|
tomwalters@0
|
47 float call_by_name() ;
|
tomwalters@0
|
48
|
tomwalters@0
|
49 Func statistic[] = {
|
tomwalters@0
|
50 { "n" , num , "sample size (ie. frame width)" } ,
|
tomwalters@0
|
51 { "sum" , sum , "area" } ,
|
tomwalters@0
|
52 { "sa" , sumabs , "sum of absolute values" } ,
|
tomwalters@0
|
53 { "ss" , sumsq , "sum of squares" } ,
|
tomwalters@0
|
54 { "mean" , mean , "sum/n" } ,
|
tomwalters@0
|
55 { "rms" , rms , "root mean square: square root of ss/n" } ,
|
tomwalters@0
|
56 { "variance" , variance , "computed with n-1 degrees of freedom" } ,
|
tomwalters@0
|
57 { "stddev" , stddev , "standard deviation: square root of variance" } ,
|
tomwalters@0
|
58 { "min" , min , "minimum value" } ,
|
tomwalters@0
|
59 { "max" , max , "maximum value" } ,
|
tomwalters@0
|
60 { "absmax" , absmax , "maximum absolute value, ie. max( |max|, |min| )" } ,
|
tomwalters@0
|
61 { "range" , absrange , "max-min" } ,
|
tomwalters@0
|
62 { "pc_1of2" , pc , "percentage correct, ie. greater first of each pair" } ,
|
tomwalters@0
|
63 ( char * ) 0 } ;
|
tomwalters@0
|
64
|
tomwalters@0
|
65
|
tomwalters@0
|
66 int samplerate ;
|
tomwalters@0
|
67 int bytes ;
|
tomwalters@0
|
68 int type ; /* datatype index */
|
tomwalters@0
|
69 int nstat ; /* number of statistics required */
|
tomwalters@0
|
70 int width ;
|
tomwalters@0
|
71 int SIZE ;
|
tomwalters@0
|
72 int lineout ; /* flag for forcing ascii output */
|
tomwalters@0
|
73
|
tomwalters@0
|
74 float *buf ; /* args to every stat function */
|
tomwalters@0
|
75 int n ;
|
tomwalters@0
|
76
|
tomwalters@0
|
77 main (argc, argv)
|
tomwalters@0
|
78 int argc;
|
tomwalters@0
|
79 char **argv;
|
tomwalters@0
|
80 {
|
tomwalters@0
|
81 FILE *fp ;
|
tomwalters@0
|
82 char **list ;
|
tomwalters@0
|
83 float y ;
|
tomwalters@0
|
84 int i, j, k, a, b, helpstats() ;
|
tomwalters@0
|
85
|
tomwalters@0
|
86 i = getopts( option, argc, argv ) ;
|
tomwalters@0
|
87 if ( !isoff( helpstr ) )
|
tomwalters@0
|
88 helpopts1( helpstr, argv[0], applic, option, helpstats ) ;
|
tomwalters@0
|
89
|
tomwalters@0
|
90 if ( ( type = typeindex( typestr ) ) < 0 ) {
|
tomwalters@0
|
91 fprintf( stderr, "stats: bad type [%s]\n", typestr ) ;
|
tomwalters@0
|
92 exit( 1 ) ;
|
tomwalters@0
|
93 }
|
tomwalters@0
|
94 bytes = typebytes( type ) ;
|
tomwalters@0
|
95
|
tomwalters@0
|
96 if ( selector( frstr, &a, &b ) == 0 ) {
|
tomwalters@0
|
97 fprintf(stderr,"stats: bad frame selector [%s]\n", frstr ) ;
|
tomwalters@0
|
98 exit( 1 ) ;
|
tomwalters@0
|
99 }
|
tomwalters@0
|
100
|
tomwalters@0
|
101 PRECISION = atoi( precstr ) ;
|
tomwalters@0
|
102 FIELDWIDTH = atoi( fieldstr ) ;
|
tomwalters@0
|
103 lineout = ison( linestr ) ;
|
tomwalters@0
|
104 samplerate = to_Hz( sampstr, 0) ;
|
tomwalters@0
|
105 SIZE = to_p( sizestr, samplerate ) ;
|
tomwalters@0
|
106 if ( ismax( widstr ) ) width = (-1) ;
|
tomwalters@0
|
107 else width = to_p( widstr, samplerate ) ;
|
tomwalters@0
|
108
|
tomwalters@0
|
109 nstat = flistsize( statistic ) ; /* max number of statistics */
|
tomwalters@0
|
110 list = (char **)malloc( nstat * sizeof( char *) ) ;
|
tomwalters@0
|
111 if ( ( nstat = tokens( statstr, list, nstat, ',' ) ) == 0 ) {
|
tomwalters@0
|
112 fprintf(stderr,"stats: incorrect stat list\n" ) ;
|
tomwalters@0
|
113 exit( 1 ) ;
|
tomwalters@0
|
114 }
|
tomwalters@0
|
115
|
tomwalters@0
|
116 do {
|
tomwalters@0
|
117
|
tomwalters@0
|
118 if ( i == 0 ) fp = stdin ;
|
tomwalters@0
|
119 else if ( ( fp = fopen( argv[argc-i], "r" ) ) == (FILE *)0 ) {
|
tomwalters@0
|
120 fprintf( stderr,"stats: can't open %s\n", argv[argc-i] ) ;
|
tomwalters@0
|
121 exit( 1 ) ;
|
tomwalters@0
|
122 }
|
tomwalters@0
|
123
|
tomwalters@0
|
124 if ( width > 0 ) buf = (float *)malloc( width * sizeof(float) ) ;
|
tomwalters@0
|
125 else buf = (float *)malloc( SIZE * sizeof(float) ) ;
|
tomwalters@0
|
126
|
tomwalters@0
|
127 if ( width > 0 && a > 1 )
|
tomwalters@0
|
128 if ( seekstart( (a-1)*width, bytes, fp ) < (a-1)*width )
|
tomwalters@0
|
129 fprintf( stderr, "stats warning: insufficient input\n" ) ;
|
tomwalters@0
|
130
|
tomwalters@0
|
131 for ( j = a ; ( j <= b || b == 0 ) && ( n = Readitem( buf, type, width, fp, SIZE ) ) > 0 ; j++ ) {
|
tomwalters@0
|
132
|
tomwalters@0
|
133 for ( k = 0 ; k < nstat ; k++ ) {
|
tomwalters@0
|
134
|
tomwalters@0
|
135 y = call_by_name( list[k], statistic ) ;
|
tomwalters@0
|
136
|
tomwalters@0
|
137 if ( lineout )
|
tomwalters@0
|
138 printf( "%*.*f ", FIELDWIDTH, PRECISION, y ) ;
|
tomwalters@0
|
139 else
|
tomwalters@0
|
140 writeitem( &y, type, 1, stdout ) ;
|
tomwalters@0
|
141 }
|
tomwalters@0
|
142 }
|
tomwalters@0
|
143
|
tomwalters@0
|
144 free( buf ) ;
|
tomwalters@0
|
145 fclose( fp ) ;
|
tomwalters@0
|
146 if ( lineout ) printf( "\n" ) ;
|
tomwalters@0
|
147
|
tomwalters@0
|
148 } while ( --i > 0 ) ;
|
tomwalters@0
|
149
|
tomwalters@0
|
150 }
|
tomwalters@0
|
151
|
tomwalters@0
|
152
|
tomwalters@0
|
153 /*
|
tomwalters@0
|
154 Return the number of structs in the null-terminated array of Func structs.
|
tomwalters@0
|
155 */
|
tomwalters@0
|
156
|
tomwalters@0
|
157 flistsize( flist )
|
tomwalters@0
|
158 Func *flist ;
|
tomwalters@0
|
159 {
|
tomwalters@0
|
160 int i ;
|
tomwalters@0
|
161
|
tomwalters@0
|
162 for ( i = 0 ; flist[i].name != (char *)0 ; i++ )
|
tomwalters@0
|
163 ;
|
tomwalters@0
|
164 return i ;
|
tomwalters@0
|
165 }
|
tomwalters@0
|
166
|
tomwalters@0
|
167
|
tomwalters@0
|
168 /*
|
tomwalters@0
|
169 Call a function given its string name. The function's address is found against
|
tomwalters@0
|
170 the matching name in the given `flist'.
|
tomwalters@0
|
171 The function returns an float.
|
tomwalters@0
|
172 Rather than return at the first matching name, search all the list for names
|
tomwalters@0
|
173 which match the (possibly abbreviated) string name. Print a warning if
|
tomwalters@0
|
174 ambiguity found.
|
tomwalters@0
|
175 */
|
tomwalters@0
|
176
|
tomwalters@0
|
177 float call_by_name( str, flist )
|
tomwalters@0
|
178 char *str ;
|
tomwalters@0
|
179 Func *flist ;
|
tomwalters@0
|
180 {
|
tomwalters@0
|
181 int i, j = (-1) ;
|
tomwalters@0
|
182
|
tomwalters@0
|
183 for ( i=0 ; flist[i].name != (char *)0 ; i++ ) {
|
tomwalters@0
|
184 if ( iststr( str, flist[i].name ) ) {
|
tomwalters@0
|
185 if ( j >= 0 )
|
tomwalters@0
|
186 fprintf( stderr,"warning: ambiguous stat names (%s and %s)\n", flist[j].name, flist[i].name ) ;
|
tomwalters@0
|
187 j = i ;
|
tomwalters@0
|
188 }
|
tomwalters@0
|
189 }
|
tomwalters@0
|
190 return ( (*flist[j].func)() ) ;
|
tomwalters@0
|
191 }
|
tomwalters@0
|
192
|
tomwalters@0
|
193
|
tomwalters@0
|
194 /*
|
tomwalters@0
|
195 Read items of given type up to max of SIZE items (when n=-1).
|
tomwalters@0
|
196 Return n or 0 if eof.
|
tomwalters@0
|
197 */
|
tomwalters@0
|
198
|
tomwalters@0
|
199 Readitem( y, type, n, fp, SIZE )
|
tomwalters@0
|
200 float *y ;
|
tomwalters@0
|
201 int type ;
|
tomwalters@0
|
202 int n ;
|
tomwalters@0
|
203 FILE *fp ;
|
tomwalters@0
|
204 int SIZE ;
|
tomwalters@0
|
205 {
|
tomwalters@0
|
206 if ( n == (-1) ) {
|
tomwalters@0
|
207 for ( n = 0 ; n < SIZE && readitem( &y[n], type, 1, fp ) ; n++ )
|
tomwalters@0
|
208 ;
|
tomwalters@0
|
209 if ( n == SIZE )
|
tomwalters@0
|
210 fprintf( stderr, "stats warning: buffer full\n" ) ;
|
tomwalters@0
|
211 }
|
tomwalters@0
|
212 else if ( readitem( y, type, n, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
213
|
tomwalters@0
|
214 return n ;
|
tomwalters@0
|
215 }
|
tomwalters@0
|
216
|
tomwalters@0
|
217
|
tomwalters@0
|
218 /*
|
tomwalters@0
|
219 Print help on request
|
tomwalters@0
|
220 */
|
tomwalters@0
|
221
|
tomwalters@0
|
222 helpstats()
|
tomwalters@0
|
223 {
|
tomwalters@0
|
224 int i ;
|
tomwalters@0
|
225
|
tomwalters@0
|
226 fprintf(stderr,"\nstatistics: \n");
|
tomwalters@0
|
227
|
tomwalters@0
|
228 for ( i = 0 ; statistic[i].name != (char *)0 ; i++ )
|
tomwalters@0
|
229 fprintf(stderr," %-10s %s\n", statistic[i].name, statistic[i].help ) ;
|
tomwalters@0
|
230
|
tomwalters@0
|
231 exit( 1 ) ;
|
tomwalters@0
|
232 }
|
tomwalters@0
|
233
|
tomwalters@0
|
234
|
tomwalters@0
|
235 /*************************** functions ************************************/
|
tomwalters@0
|
236 /* The functions all take two args: char *buf; int n; */
|
tomwalters@0
|
237 /* These are declared externally. */
|
tomwalters@0
|
238
|
tomwalters@0
|
239
|
tomwalters@0
|
240 float num()
|
tomwalters@0
|
241 {
|
tomwalters@0
|
242 return n ;
|
tomwalters@0
|
243 }
|
tomwalters@0
|
244
|
tomwalters@0
|
245
|
tomwalters@0
|
246 float sum()
|
tomwalters@0
|
247 {
|
tomwalters@0
|
248 int i ;
|
tomwalters@0
|
249 float sum = 0 ;
|
tomwalters@0
|
250
|
tomwalters@0
|
251 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
252 sum += buf[i] ;
|
tomwalters@0
|
253
|
tomwalters@0
|
254 return ( sum ) ;
|
tomwalters@0
|
255 }
|
tomwalters@0
|
256
|
tomwalters@0
|
257
|
tomwalters@0
|
258 float sumabs()
|
tomwalters@0
|
259 {
|
tomwalters@0
|
260 int i ;
|
tomwalters@0
|
261 float sum = 0 ;
|
tomwalters@0
|
262
|
tomwalters@0
|
263 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
264 sum += fabs( (double)buf[i] ) ;
|
tomwalters@0
|
265
|
tomwalters@0
|
266 return ( sum ) ;
|
tomwalters@0
|
267 }
|
tomwalters@0
|
268
|
tomwalters@0
|
269
|
tomwalters@0
|
270 float sumsq()
|
tomwalters@0
|
271 {
|
tomwalters@0
|
272 int i ;
|
tomwalters@0
|
273 float sumsq = 0 ;
|
tomwalters@0
|
274
|
tomwalters@0
|
275 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
276 sumsq += ( buf[i] * buf[i] ) ;
|
tomwalters@0
|
277
|
tomwalters@0
|
278 return ( sumsq ) ;
|
tomwalters@0
|
279 }
|
tomwalters@0
|
280
|
tomwalters@0
|
281
|
tomwalters@0
|
282 float mean()
|
tomwalters@0
|
283 {
|
tomwalters@0
|
284 int i ;
|
tomwalters@0
|
285 float sum = 0 ;
|
tomwalters@0
|
286
|
tomwalters@0
|
287 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
288 sum += buf[i] ;
|
tomwalters@0
|
289
|
tomwalters@0
|
290 return ( sum / n ) ;
|
tomwalters@0
|
291 }
|
tomwalters@0
|
292
|
tomwalters@0
|
293
|
tomwalters@0
|
294 float rms()
|
tomwalters@0
|
295 {
|
tomwalters@0
|
296 int i ;
|
tomwalters@0
|
297 float sumsq = 0 ;
|
tomwalters@0
|
298
|
tomwalters@0
|
299 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
300 sumsq += ( buf[i] * buf[i] ) ;
|
tomwalters@0
|
301
|
tomwalters@0
|
302 return ( sqrt( sumsq / n ) ) ;
|
tomwalters@0
|
303 }
|
tomwalters@0
|
304
|
tomwalters@0
|
305
|
tomwalters@0
|
306 float variance() /* computed with n-1 degrees of freedom */
|
tomwalters@0
|
307 {
|
tomwalters@0
|
308 int i ;
|
tomwalters@0
|
309 float sum = 0, sumsq = 0 ;
|
tomwalters@0
|
310
|
tomwalters@0
|
311 for ( i = 0 ; i < n ; i++ ) {
|
tomwalters@0
|
312 sum += buf[i] ;
|
tomwalters@0
|
313 sumsq += ( buf[i] * buf[i] ) ;
|
tomwalters@0
|
314 }
|
tomwalters@0
|
315
|
tomwalters@0
|
316 return ( ( sumsq - sum*sum/n ) / ( n - 1 ) ) ; /* replace n-1 by n for n degrees of freedom */
|
tomwalters@0
|
317 }
|
tomwalters@0
|
318
|
tomwalters@0
|
319
|
tomwalters@0
|
320 float stddev() /* computed with n-1 degrees of freedom */
|
tomwalters@0
|
321 {
|
tomwalters@0
|
322 return ( sqrt( variance( buf, n ) ) ) ;
|
tomwalters@0
|
323 }
|
tomwalters@0
|
324
|
tomwalters@0
|
325
|
tomwalters@0
|
326 float min()
|
tomwalters@0
|
327 {
|
tomwalters@0
|
328 int i ;
|
tomwalters@0
|
329 float min = 99999999999. ;
|
tomwalters@0
|
330
|
tomwalters@0
|
331 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
332 if ( buf[i] < min ) min = buf[i] ;
|
tomwalters@0
|
333 return ( min ) ;
|
tomwalters@0
|
334 }
|
tomwalters@0
|
335
|
tomwalters@0
|
336
|
tomwalters@0
|
337 float max()
|
tomwalters@0
|
338 {
|
tomwalters@0
|
339 int i ;
|
tomwalters@0
|
340 float max = ( -99999999999. ) ;
|
tomwalters@0
|
341
|
tomwalters@0
|
342 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
343 if ( buf[i] > max ) max = buf[i] ;
|
tomwalters@0
|
344
|
tomwalters@0
|
345 return ( max ) ;
|
tomwalters@0
|
346 }
|
tomwalters@0
|
347
|
tomwalters@0
|
348
|
tomwalters@0
|
349 float absmax()
|
tomwalters@0
|
350 {
|
tomwalters@0
|
351 int i ;
|
tomwalters@0
|
352 float min = 99999999999. ;
|
tomwalters@0
|
353 float max = ( -99999999999. ) ;
|
tomwalters@0
|
354
|
tomwalters@0
|
355 for ( i = 0 ; i < n ; i++ ) {
|
tomwalters@0
|
356 if ( buf[i] < min ) min = buf[i] ;
|
tomwalters@0
|
357 if ( buf[i] > max ) max = buf[i] ;
|
tomwalters@0
|
358 }
|
tomwalters@0
|
359
|
tomwalters@0
|
360 if ( ( max = fabs( (double)max ) ) < ( min = fabs( (double)min ) ) )
|
tomwalters@0
|
361 max = min ;
|
tomwalters@0
|
362
|
tomwalters@0
|
363 return ( max ) ;
|
tomwalters@0
|
364 }
|
tomwalters@0
|
365
|
tomwalters@0
|
366
|
tomwalters@0
|
367 float absrange()
|
tomwalters@0
|
368 {
|
tomwalters@0
|
369 int i ;
|
tomwalters@0
|
370 float min = 99999999999. ;
|
tomwalters@0
|
371 float max = ( -99999999999. ) ;
|
tomwalters@0
|
372
|
tomwalters@0
|
373 for ( i = 0 ; i < n ; i++ ) {
|
tomwalters@0
|
374 if ( buf[i] < min ) min = buf[i] ;
|
tomwalters@0
|
375 if ( buf[i] > max ) max = buf[i] ;
|
tomwalters@0
|
376 }
|
tomwalters@0
|
377
|
tomwalters@0
|
378 return ( max - min ) ;
|
tomwalters@0
|
379 }
|
tomwalters@0
|
380
|
tomwalters@0
|
381
|
tomwalters@0
|
382 /*
|
tomwalters@0
|
383 The buf contains n/2 pairs of numbers. Calculate how many of each pair have
|
tomwalters@0
|
384 the first number greater than the last, and return this as a "percentage
|
tomwalters@0
|
385 correct".
|
tomwalters@0
|
386 */
|
tomwalters@0
|
387
|
tomwalters@0
|
388 float pc()
|
tomwalters@0
|
389 {
|
tomwalters@0
|
390 int i ;
|
tomwalters@0
|
391 float p = 0 ;
|
tomwalters@0
|
392
|
tomwalters@0
|
393 for ( i = 0 ; i < n ; i+=2 )
|
tomwalters@0
|
394 if ( buf[i] > buf[i+1] )
|
tomwalters@0
|
395 p++ ;
|
tomwalters@0
|
396
|
tomwalters@0
|
397 return ( ( p / (n/2) ) * 100 ) ;
|
tomwalters@0
|
398 }
|
tomwalters@0
|
399
|
tomwalters@0
|
400
|
tomwalters@0
|
401
|