Mercurial > hg > aim92
view tools/scale.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
/* scale.c shift and scale a data stream by given constants or to ------- fit a given range (top - bottom). Shifting and scaling is done for all input x using the formula: y = ( x - shift ) * scale If only a shift term is given, then the default scale is 1.0 If only a scale factor is given, then the default shift is 0. If neither shift nor scale are given, then appropriate values are chosen so that the output fits the range specified by `top' and `bottom'. For an input which ranges between extreme values of `max' and `min', the shift and scale factors to give a required range between `top' and `bottom' are found by simultaneously solving: top = ( max - shift ) * scale bottom = ( min - shift ) * scale If top < bottom then the input is inverted in the resulting range. The input stream depends upon the `type' option. The output datatype is the same as that selected for input. With no filename arguments, data is expected on the stdin, and the scaled result is written on the stdout. Otherwise each given filename is processed in turn. When the `output' option is "off" output overwrites the respective input file. (The respective output for the stdin is the stdout). Otherwise all scaled input files are written to the given output file (which is the stdout by default). The `range' option sets the start and duration of the process. Its arguments are of the form: range=a-b (where start=a and duration=b-a+1) or: range=a (where start=a and duration=1 ) The arguments can be in time units (ms, s) or samples (no units), and both "min" (start of file) and "max" (end of file) are recognised. Samples in a file are numbered 0,1,2,...,max. Examples: 1. Invert the range of a given pulse train to obtain negative-going pulses. (Two ways): ptrain amp=512 | scale top=-512 bot=0 | x11plot ptrain amp=512 | scale scale=-1 | x11plot */ #include <stdio.h> #include <math.h> #include "options.h" #include "units.h" #include "strmatch.h" char applic[] = "waveform shifting and scaling: y = (x - shift) * scale" ; static char *helpstr, *debugstr, *sampstr, *rangestr, *outstr ; static char *topstr, *botstr, *scalestr, *typestr, *sizestr ; static char *shiftstr, *normstr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL }, { "range" , "0-max" , &rangestr , "start-finish limits in data" , VAL }, { "top" , "1000" , &topstr , "max of scaled data" , VAL }, { "bottom" , "-1000" , &botstr , "min of scaled data" , VAL }, { "shift" , "off" , &shiftstr , "shift term" , VAL }, { "scale" , "off" , &scalestr , "scale factor" , VAL }, { "normalize" , "off" , &normstr , "set zero mean and unit std dev", VAL }, { "type" , "short" , &typestr , "datatype" , VAL }, { "output" , "stdout" , &outstr , "output filename (off = overwrite input)" , VAL }, { "SIZE" , "262144p" , &sizestr , "buffer size (s, ms, or p)" , SVAL }, ( char * ) 0 } ; int samplerate ; int type ; /* datatype index */ int bytes ; int SIZE ; /* buffer size */ int FIT_TO_RANGE = 0 ; int NORMALIZE = 0 ; float shift, scale ; float *data ; FILE *ofp ; main (argc, argv) int argc; char **argv; { FILE *fp ; int i, j, a, b, n ; i = getopts( option, argc, argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], applic, option ) ; samplerate = to_Hz( sampstr ) ; SIZE = to_p( sizestr, samplerate ) ; if ( ( type = typeindex( typestr ) ) < 0 ) { fprintf( stderr, "scale: bad type [%s]\n", typestr ) ; exit( 1 ) ; } bytes = typebytes( type ) ; if ( range( rangestr, &a, &b, samplerate ) == 0 ) { fprintf(stderr,"scale: bad range [%s]\n", rangestr ) ; exit( 1 ) ; } if ( ison( normstr ) ) NORMALIZE = 1 ; else if ( isoff( shiftstr ) && isoff( scalestr ) ) FIT_TO_RANGE = 1 ; else if ( isoff( shiftstr ) ) { shift = 0 ; scale = atof( scalestr ) ; } else if ( isoff( scalestr ) ) { shift = atof( shiftstr ) ; scale = 1. ; } else { shift = atof( shiftstr ) ; scale = atof( scalestr ) ; } if ( ( data = (float *)malloc( SIZE * sizeof(float) ) ) == NULL ) { fprintf( stderr, "malloc out of space\n" ) ; exit( 1 ) ; } do { if ( i == 0 ) fp = stdin ; else if ( ( fp = fopen( argv[argc-i], "r" ) ) == (FILE *)0 ) { fprintf( stderr,"scale: can't open %s\n", argv[argc-i] ) ; exit( 1 ) ; } if ( seekstart( a, bytes, fp ) < a ) { fprintf( stderr,"scale: insufficient data in file\n" ) ; exit( 1 ) ; } for ( j = a, n = 0 ; ( j <= b || b == (-1) ) && n < SIZE && readitem( &data[n], type, 1, fp ) ; j++, n++ ) ; if ( n == SIZE ) fprintf( stderr, "scale warning: file %s exceeded buffer size\n", argv[argc-i] ) ; fclose( fp ) ; if ( NORMALIZE ) getnorm( data, n, &shift, &scale ) ; else if ( FIT_TO_RANGE ) getrange( data, n, atof( topstr ), atof( botstr ), &shift, &scale ) ; if ( isstr( outstr, "print" ) ) printf( "%8.3f %8.3f \n", shift, scale ) ; else { open_output( argc, argv , i ) ; for ( j = 0 ; j < n ; j++ ) { data[j] = ( data[j] - shift ) * scale ; writeitem( &data[j], type, 1, ofp ) ; } } } while ( --i > 0 ) ; fclose( ofp ) ; } /* Open ouput file pointer, ofp. Use the input filename (argv[argc-i]) if outstr is "off", otherwise use the given name outstr. */ open_output( argc, argv , i ) int argc ; char **argv ; int i ; { static int first = 1 ; if ( first ) { if ( isoff( outstr ) ) { if ( i == 0 ) ofp = stdout ; else if ( ( ofp = fopen( argv[argc-i], "w" ) ) == (FILE *)0 ) { fprintf( stderr,"scale: can't create %s\n", argv[argc-i] ) ; exit( 1 ) ; } } else if ( isstr( outstr, "stdout") ) ofp = stdout ; else if ( ( ofp = fopen( outstr, "w" ) ) == (FILE *)0 ) { fprintf( stderr,"scale: can't create %s\n", outstr ) ; exit( 1 ) ; } first = 0 ; } else { if ( isoff( outstr ) ) { fclose ( ofp ) ; if ( i == 0 ) ofp = stdout ; else if ( ( ofp = fopen( argv[argc-i], "w" ) ) == (FILE *)0 ) { fprintf( stderr,"scale: can't create %s\n", argv[argc-i] ) ; exit( 1 ) ; } } } } /* Return parameters `shift' and `scale' to normalize the data for zero mean and unit std dev: shift = mean scale = 1 / sqrt(variance) */ getnorm( data, n, shift, scale ) float *data ; int n ; float *shift, *scale ; { int i ; float sum = 0, sumsq = 0 ; for ( i = 0 ; i < n ; i++ ) { sum += data[i] ; sumsq += data[i] * data[i] ; } *shift = sum / n ; *scale = 1. / sqrt( sumsq / n - *shift * *shift ) ; } /* Return parameters `shift' and `scale' to fit the given float data into the amplitude range delimited by `top' and `bottom'. */ getrange( data, n, top, bottom, shift, scale ) float *data ; int n ; float top, bottom ; float *shift, *scale ; { float min = 1e+8, max = (-1e+8) ; int i ; for ( i = 0 ; i < n ; i++ ) { if ( data[i] > max ) max = data[i] ; if ( data[i] < min ) min = data[i] ; } *scale = ( top - bottom ) / ( max - min ) ; *shift = ( min * top - max * bottom ) / ( top - bottom ) ; }