diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/scale.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,271 @@
+/*
+  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 ) ;
+}
+
+