view tools/stats.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
line wrap: on
line source
/*
  stats.c      calculate some statistics (min, max, mean etc.)
  -------

*/

#include <stdio.h>
#include <math.h>
#include "options.h"
#include "units.h"
#include "strmatch.h"

char applic[]     = "print statistics of input files" ;

static char *helpstr, *debugstr, *typestr, *statstr ;
static char *sampstr, *frstr,    *widstr,  *sizestr ;
static char *linestr, *precstr,  *fieldstr          ;

static Options option[] = {
    {   "help"      ,   "off"       ,  &helpstr     ,   "help"                          , DEBUG   },
    {   "debug"     ,   "off"       ,  &debugstr    ,   "debugging switch"              , DEBUG   },
    {   "samplerate",   "20kHz"     ,  &sampstr     ,   "samplerate "                   , VAL     },
    {   "frame"     ,   "1"         ,  &frstr       ,   "select frames inclusively"     , VAL     },
    {   "width"     ,   "max"       ,  &widstr      ,   "frame width"                   , VAL     },
    {   "type"      ,   "short"     ,  &typestr     ,   "data type"                     , VAL     },
    {   "stat"      ,   "mean"      ,  &statstr     ,   "statistic list (comma separated)"      , VAL     },
    {   "line"      ,   "off"       ,  &linestr     ,   "force ascii output"            , SETFLAG },
    {   "fieldwidth",   "10"        ,  &fieldstr    ,   "field width for ascii printing", SVAL    },
    {   "precision" ,   "3"         ,  &precstr     ,   "precision for ascii printing"  , SVAL    },
    {   "SIZE"      ,   "262144p"   ,  &sizestr     ,   "buffer size (s, ms, or p)"     , SVAL    },
   ( char * ) 0 } ;


typedef float (*PF)() ; /* pointer-to-function type returning float */

typedef struct {        /* a struct to hold both function name and pointer */
    char  *name ;       /* string name of function */
    PF     func ;       /* pointer to function     */
    char  *help ;       /* explanation of use      */
} Func ;


float   num(),      sum(),      sumabs(),   sumsq(),    mean()      ;
float   rms(),      variance(), stddev(),   min(),      max()       ;
float   absmax(),   absrange(), pc()                                            ;

float   call_by_name() ;

Func  statistic[] = {
    { "n"         ,     num         ,    "sample size (ie. frame width)"                        } ,
    { "sum"       ,     sum         ,    "area"                                                 } ,
    { "sa"        ,     sumabs      ,    "sum of absolute values"                               } ,
    { "ss"        ,     sumsq       ,    "sum of squares"                                       } ,
    { "mean"      ,     mean        ,    "sum/n"                                                } ,
    { "rms"       ,     rms         ,    "root mean square: square root of ss/n"                } ,
    { "variance"  ,     variance    ,    "computed with n-1 degrees of freedom"                 } ,
    { "stddev"    ,     stddev      ,    "standard deviation: square root of variance"          } ,
    { "min"       ,     min         ,    "minimum value"                                        } ,
    { "max"       ,     max         ,    "maximum value"                                        } ,
    { "absmax"    ,     absmax      ,    "maximum absolute value, ie. max( |max|, |min| )"      } ,
    { "range"     ,     absrange    ,    "max-min"                                              } ,
    { "pc_1of2"   ,     pc          ,    "percentage correct, ie. greater first of each pair"   } ,
   ( char * ) 0 } ;


int    samplerate ;
int    bytes      ;
int    type       ;     /* datatype index */
int    nstat      ;     /* number of statistics required */
int    width      ;
int    SIZE       ;
int    lineout    ;     /* flag for forcing ascii output */

float *buf ;            /* args to every stat function */
int    n   ;

main (argc, argv)
int    argc;
char **argv;
{
    FILE   *fp   ;
    char  **list ;
    float   y    ;
    int     i, j, k, a, b, helpstats() ;

    i = getopts( option, argc, argv ) ;
    if ( !isoff( helpstr ) )
	helpopts1( helpstr, argv[0], applic, option, helpstats ) ;

    if ( ( type = typeindex( typestr ) ) < 0 ) {
	fprintf( stderr, "stats: bad type [%s]\n", typestr ) ;
	exit( 1 ) ;
    }
    bytes = typebytes( type ) ;

    if ( selector( frstr, &a, &b ) == 0 ) {
	fprintf(stderr,"stats: bad frame selector [%s]\n", frstr ) ;
	exit( 1 ) ;
    }

    PRECISION  = atoi( precstr ) ;
    FIELDWIDTH = atoi( fieldstr ) ;
    lineout    = ison( linestr ) ;
    samplerate = to_Hz( sampstr, 0) ;
    SIZE       = to_p( sizestr, samplerate ) ;
    if ( ismax( widstr ) ) width = (-1) ;
    else                   width = to_p( widstr, samplerate ) ;

    nstat  = flistsize( statistic ) ;   /* max number of statistics */
    list   = (char **)malloc( nstat * sizeof( char *) ) ;
    if ( ( nstat  = tokens( statstr, list, nstat, ',' ) ) == 0 ) {
	fprintf(stderr,"stats: incorrect stat list\n" ) ;
	exit( 1 ) ;
    }

    do {

	if ( i == 0 ) fp = stdin ;
	else if ( ( fp = fopen( argv[argc-i], "r" ) ) == (FILE *)0 ) {
	    fprintf( stderr,"stats: can't open %s\n", argv[argc-i] ) ;
	    exit( 1 ) ;
	}

	if ( width > 0 ) buf = (float *)malloc( width * sizeof(float) ) ;
	else             buf = (float *)malloc( SIZE  * sizeof(float) ) ;

	if ( width > 0 && a > 1 )
	    if ( seekstart( (a-1)*width, bytes, fp ) < (a-1)*width )
		fprintf( stderr, "stats warning: insufficient input\n" ) ;

	for ( j = a ; ( j <= b || b == 0 ) && ( n = Readitem( buf, type, width, fp, SIZE ) ) > 0 ; j++ ) {

	    for ( k = 0 ; k < nstat ; k++ ) {

		y = call_by_name( list[k], statistic ) ;

		if ( lineout )
		    printf( "%*.*f  ", FIELDWIDTH, PRECISION, y ) ;
		else
		    writeitem( &y, type, 1, stdout ) ;
	    }
	}

	free( buf ) ;
	fclose( fp ) ;
	if ( lineout ) printf( "\n" ) ;

    } while ( --i > 0 ) ;

}


/*
Return the number of structs in the null-terminated array of Func structs.
*/

flistsize( flist )
Func *flist ;
{
    int  i ;

    for ( i = 0 ; flist[i].name != (char *)0 ; i++ )
	;
    return i ;
}


/*
Call a function given its string name. The function's address is found against
the matching name in the given `flist'.
The function returns an float.
Rather than return at the first matching name, search all the list for names
which match the (possibly abbreviated) string name. Print a warning if
ambiguity found.
*/

float call_by_name( str, flist )
char  *str   ;
Func  *flist ;
{
    int  i, j = (-1) ;

    for ( i=0 ; flist[i].name != (char *)0 ; i++ ) {
	if ( iststr( str, flist[i].name ) ) {
	    if ( j >= 0 )
		fprintf( stderr,"warning: ambiguous stat names (%s and %s)\n", flist[j].name, flist[i].name ) ;
	    j = i ;
	}
    }
    return ( (*flist[j].func)() ) ;
}


/*
Read items of given type up to max of SIZE items (when n=-1).
Return n or 0 if eof.
*/

Readitem( y, type, n, fp, SIZE )
float  *y    ;
int     type ;
int     n    ;
FILE   *fp   ;
int     SIZE ;
{
    if ( n == (-1) ) {
	for ( n = 0 ; n < SIZE && readitem( &y[n], type, 1, fp ) ; n++ )
	    ;
	if ( n == SIZE )
	    fprintf( stderr, "stats warning: buffer full\n" ) ;
    }
    else if ( readitem( y, type, n, fp ) == 0 ) return 0 ;

    return n ;
}


/*
Print help on request
*/

helpstats()
{
    int  i ;

    fprintf(stderr,"\nstatistics:       \n");

    for ( i = 0 ; statistic[i].name != (char *)0 ; i++ )
	fprintf(stderr,"            %-10s  %s\n", statistic[i].name, statistic[i].help ) ;

    exit( 1 ) ;
}


/*************************** functions ************************************/
/* The functions all take two args: char *buf; int n;                     */
/* These are declared externally.                                         */


float num()
{
    return n ;
}


float sum()
{
    int   i ;
    float sum = 0 ;

    for ( i = 0 ; i < n ; i++ )
	sum += buf[i] ;

    return ( sum ) ;
}


float sumabs()
{
    int   i ;
    float sum = 0 ;

    for ( i = 0 ; i < n ; i++ )
	sum += fabs( (double)buf[i] ) ;

    return ( sum ) ;
}


float sumsq()
{
    int   i ;
    float sumsq = 0 ;

    for ( i = 0 ; i < n ; i++ )
	sumsq += ( buf[i] * buf[i] ) ;

    return ( sumsq ) ;
}


float mean()
{
    int   i ;
    float sum = 0 ;

    for ( i = 0 ; i < n ; i++ )
	sum += buf[i] ;

    return ( sum / n ) ;
}


float rms()
{
    int   i ;
    float sumsq = 0 ;

    for ( i = 0 ; i < n ; i++ )
	sumsq += ( buf[i] * buf[i] ) ;

    return ( sqrt( sumsq / n ) ) ;
}


float variance()    /* computed with n-1 degrees of freedom */
{
    int   i ;
    float sum = 0, sumsq = 0 ;

    for ( i = 0 ; i < n ; i++ ) {
	sum   += buf[i]   ;
	sumsq += ( buf[i] * buf[i] ) ;
    }

    return ( ( sumsq - sum*sum/n ) / ( n - 1 ) ) ;  /* replace n-1 by n for n degrees of freedom */
}


float stddev()    /* computed with n-1 degrees of freedom */
{
    return ( sqrt( variance( buf, n ) ) ) ;
}


float min()
{
    int   i ;
    float min = 99999999999. ;

    for ( i = 0 ; i < n ; i++ )
	if ( buf[i] < min ) min = buf[i] ;
    return ( min ) ;
}


float max()
{
    int   i ;
    float max = ( -99999999999. ) ;

    for ( i = 0 ; i < n ; i++ )
	if ( buf[i] > max ) max = buf[i] ;

    return ( max ) ;
}


float absmax()
{
    int   i ;
    float min =    99999999999.   ;
    float max = ( -99999999999. ) ;

    for ( i = 0 ; i < n ; i++ ) {
	if ( buf[i] < min ) min = buf[i] ;
	if ( buf[i] > max ) max = buf[i] ;
    }

    if ( ( max = fabs( (double)max ) ) < ( min = fabs( (double)min ) ) )
	max = min ;

    return ( max ) ;
}


float absrange()
{
    int   i ;
    float min =    99999999999.   ;
    float max = ( -99999999999. ) ;

    for ( i = 0 ; i < n ; i++ ) {
	if ( buf[i] < min ) min = buf[i] ;
	if ( buf[i] > max ) max = buf[i] ;
    }

    return ( max - min ) ;
}


/*
The buf contains n/2 pairs of numbers. Calculate how many of each pair have
the first number greater than the last, and return this as a "percentage
correct".
*/

float pc()
{
    int   i ;
    float p = 0 ;

    for ( i = 0 ; i < n ; i+=2 )
	if ( buf[i] > buf[i+1] )
	    p++ ;

    return ( ( p / (n/2) ) * 100 ) ;
}