annotate 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
rev   line source
tomwalters@0 1 /*
tomwalters@0 2 scale.c shift and scale a data stream by given constants or to
tomwalters@0 3 ------- fit a given range (top - bottom).
tomwalters@0 4
tomwalters@0 5 Shifting and scaling is done for all input x using the formula:
tomwalters@0 6 y = ( x - shift ) * scale
tomwalters@0 7
tomwalters@0 8 If only a shift term is given, then the default scale is 1.0
tomwalters@0 9 If only a scale factor is given, then the default shift is 0.
tomwalters@0 10
tomwalters@0 11 If neither shift nor scale are given, then appropriate values are
tomwalters@0 12 chosen so that the output fits the range specified by `top' and `bottom'.
tomwalters@0 13 For an input which ranges between extreme values of `max' and `min', the
tomwalters@0 14 shift and scale factors to give a required range between `top' and `bottom'
tomwalters@0 15 are found by simultaneously solving:
tomwalters@0 16 top = ( max - shift ) * scale
tomwalters@0 17 bottom = ( min - shift ) * scale
tomwalters@0 18
tomwalters@0 19 If top < bottom then the input is inverted in the resulting range.
tomwalters@0 20
tomwalters@0 21 The input stream depends upon the `type' option. The output datatype is
tomwalters@0 22 the same as that selected for input.
tomwalters@0 23 With no filename arguments, data is expected on the stdin, and the
tomwalters@0 24 scaled result is written on the stdout. Otherwise each given filename is
tomwalters@0 25 processed in turn. When the `output' option is "off" output overwrites the
tomwalters@0 26 respective input file. (The respective output for the stdin is the stdout).
tomwalters@0 27 Otherwise all scaled input files are written to the given output file
tomwalters@0 28 (which is the stdout by default).
tomwalters@0 29
tomwalters@0 30 The `range' option sets the start and duration of the process.
tomwalters@0 31 Its arguments are of the form: range=a-b (where start=a and duration=b-a+1)
tomwalters@0 32 or: range=a (where start=a and duration=1 )
tomwalters@0 33 The arguments can be in time units (ms, s) or samples (no units), and both
tomwalters@0 34 "min" (start of file) and "max" (end of file) are recognised.
tomwalters@0 35 Samples in a file are numbered 0,1,2,...,max.
tomwalters@0 36
tomwalters@0 37 Examples:
tomwalters@0 38
tomwalters@0 39 1. Invert the range of a given pulse train to obtain negative-going pulses.
tomwalters@0 40 (Two ways):
tomwalters@0 41
tomwalters@0 42 ptrain amp=512 | scale top=-512 bot=0 | x11plot
tomwalters@0 43 ptrain amp=512 | scale scale=-1 | x11plot
tomwalters@0 44
tomwalters@0 45 */
tomwalters@0 46
tomwalters@0 47
tomwalters@0 48 #include <stdio.h>
tomwalters@0 49 #include <math.h>
tomwalters@0 50 #include "options.h"
tomwalters@0 51 #include "units.h"
tomwalters@0 52 #include "strmatch.h"
tomwalters@0 53
tomwalters@0 54 char applic[] = "waveform shifting and scaling: y = (x - shift) * scale" ;
tomwalters@0 55
tomwalters@0 56 static char *helpstr, *debugstr, *sampstr, *rangestr, *outstr ;
tomwalters@0 57 static char *topstr, *botstr, *scalestr, *typestr, *sizestr ;
tomwalters@0 58 static char *shiftstr, *normstr ;
tomwalters@0 59
tomwalters@0 60 static Options option[] = {
tomwalters@0 61 { "help" , "off" , &helpstr , "help" , DEBUG },
tomwalters@0 62 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
tomwalters@0 63 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL },
tomwalters@0 64 { "range" , "0-max" , &rangestr , "start-finish limits in data" , VAL },
tomwalters@0 65 { "top" , "1000" , &topstr , "max of scaled data" , VAL },
tomwalters@0 66 { "bottom" , "-1000" , &botstr , "min of scaled data" , VAL },
tomwalters@0 67 { "shift" , "off" , &shiftstr , "shift term" , VAL },
tomwalters@0 68 { "scale" , "off" , &scalestr , "scale factor" , VAL },
tomwalters@0 69 { "normalize" , "off" , &normstr , "set zero mean and unit std dev", VAL },
tomwalters@0 70 { "type" , "short" , &typestr , "datatype" , VAL },
tomwalters@0 71 { "output" , "stdout" , &outstr , "output filename (off = overwrite input)" , VAL },
tomwalters@0 72 { "SIZE" , "262144p" , &sizestr , "buffer size (s, ms, or p)" , SVAL },
tomwalters@0 73 ( char * ) 0 } ;
tomwalters@0 74
tomwalters@0 75
tomwalters@0 76 int samplerate ;
tomwalters@0 77 int type ; /* datatype index */
tomwalters@0 78 int bytes ;
tomwalters@0 79 int SIZE ; /* buffer size */
tomwalters@0 80
tomwalters@0 81 int FIT_TO_RANGE = 0 ;
tomwalters@0 82 int NORMALIZE = 0 ;
tomwalters@0 83
tomwalters@0 84 float shift, scale ;
tomwalters@0 85
tomwalters@0 86 float *data ;
tomwalters@0 87
tomwalters@0 88 FILE *ofp ;
tomwalters@0 89
tomwalters@0 90 main (argc, argv)
tomwalters@0 91 int argc;
tomwalters@0 92 char **argv;
tomwalters@0 93 {
tomwalters@0 94 FILE *fp ;
tomwalters@0 95 int i, j, a, b, n ;
tomwalters@0 96
tomwalters@0 97 i = getopts( option, argc, argv ) ;
tomwalters@0 98 if ( !isoff( helpstr ) )
tomwalters@0 99 helpopts( helpstr, argv[0], applic, option ) ;
tomwalters@0 100
tomwalters@0 101 samplerate = to_Hz( sampstr ) ;
tomwalters@0 102 SIZE = to_p( sizestr, samplerate ) ;
tomwalters@0 103
tomwalters@0 104 if ( ( type = typeindex( typestr ) ) < 0 ) {
tomwalters@0 105 fprintf( stderr, "scale: bad type [%s]\n", typestr ) ;
tomwalters@0 106 exit( 1 ) ;
tomwalters@0 107 }
tomwalters@0 108 bytes = typebytes( type ) ;
tomwalters@0 109
tomwalters@0 110 if ( range( rangestr, &a, &b, samplerate ) == 0 ) {
tomwalters@0 111 fprintf(stderr,"scale: bad range [%s]\n", rangestr ) ;
tomwalters@0 112 exit( 1 ) ;
tomwalters@0 113 }
tomwalters@0 114
tomwalters@0 115
tomwalters@0 116 if ( ison( normstr ) ) NORMALIZE = 1 ;
tomwalters@0 117 else if ( isoff( shiftstr ) && isoff( scalestr ) ) FIT_TO_RANGE = 1 ;
tomwalters@0 118 else if ( isoff( shiftstr ) ) {
tomwalters@0 119 shift = 0 ;
tomwalters@0 120 scale = atof( scalestr ) ;
tomwalters@0 121 }
tomwalters@0 122 else if ( isoff( scalestr ) ) {
tomwalters@0 123 shift = atof( shiftstr ) ;
tomwalters@0 124 scale = 1. ;
tomwalters@0 125 }
tomwalters@0 126 else {
tomwalters@0 127 shift = atof( shiftstr ) ;
tomwalters@0 128 scale = atof( scalestr ) ;
tomwalters@0 129 }
tomwalters@0 130
tomwalters@0 131 if ( ( data = (float *)malloc( SIZE * sizeof(float) ) ) == NULL ) {
tomwalters@0 132 fprintf( stderr, "malloc out of space\n" ) ;
tomwalters@0 133 exit( 1 ) ;
tomwalters@0 134 }
tomwalters@0 135
tomwalters@0 136
tomwalters@0 137 do {
tomwalters@0 138
tomwalters@0 139 if ( i == 0 ) fp = stdin ;
tomwalters@0 140 else if ( ( fp = fopen( argv[argc-i], "r" ) ) == (FILE *)0 ) {
tomwalters@0 141 fprintf( stderr,"scale: can't open %s\n", argv[argc-i] ) ;
tomwalters@0 142 exit( 1 ) ;
tomwalters@0 143 }
tomwalters@0 144
tomwalters@0 145 if ( seekstart( a, bytes, fp ) < a ) {
tomwalters@0 146 fprintf( stderr,"scale: insufficient data in file\n" ) ;
tomwalters@0 147 exit( 1 ) ;
tomwalters@0 148 }
tomwalters@0 149
tomwalters@0 150 for ( j = a, n = 0 ; ( j <= b || b == (-1) ) && n < SIZE && readitem( &data[n], type, 1, fp ) ; j++, n++ )
tomwalters@0 151 ;
tomwalters@0 152 if ( n == SIZE )
tomwalters@0 153 fprintf( stderr, "scale warning: file %s exceeded buffer size\n", argv[argc-i] ) ;
tomwalters@0 154
tomwalters@0 155 fclose( fp ) ;
tomwalters@0 156
tomwalters@0 157
tomwalters@0 158 if ( NORMALIZE )
tomwalters@0 159 getnorm( data, n, &shift, &scale ) ;
tomwalters@0 160 else if ( FIT_TO_RANGE )
tomwalters@0 161 getrange( data, n, atof( topstr ), atof( botstr ), &shift, &scale ) ;
tomwalters@0 162
tomwalters@0 163
tomwalters@0 164 if ( isstr( outstr, "print" ) )
tomwalters@0 165 printf( "%8.3f %8.3f \n", shift, scale ) ;
tomwalters@0 166 else {
tomwalters@0 167 open_output( argc, argv , i ) ;
tomwalters@0 168 for ( j = 0 ; j < n ; j++ ) {
tomwalters@0 169 data[j] = ( data[j] - shift ) * scale ;
tomwalters@0 170 writeitem( &data[j], type, 1, ofp ) ;
tomwalters@0 171 }
tomwalters@0 172 }
tomwalters@0 173
tomwalters@0 174 } while ( --i > 0 ) ;
tomwalters@0 175
tomwalters@0 176 fclose( ofp ) ;
tomwalters@0 177 }
tomwalters@0 178
tomwalters@0 179
tomwalters@0 180 /*
tomwalters@0 181 Open ouput file pointer, ofp.
tomwalters@0 182 Use the input filename (argv[argc-i]) if outstr is "off", otherwise use
tomwalters@0 183 the given name outstr.
tomwalters@0 184 */
tomwalters@0 185
tomwalters@0 186 open_output( argc, argv , i )
tomwalters@0 187 int argc ;
tomwalters@0 188 char **argv ;
tomwalters@0 189 int i ;
tomwalters@0 190 {
tomwalters@0 191 static int first = 1 ;
tomwalters@0 192
tomwalters@0 193 if ( first ) {
tomwalters@0 194
tomwalters@0 195 if ( isoff( outstr ) ) {
tomwalters@0 196 if ( i == 0 ) ofp = stdout ;
tomwalters@0 197 else if ( ( ofp = fopen( argv[argc-i], "w" ) ) == (FILE *)0 ) {
tomwalters@0 198 fprintf( stderr,"scale: can't create %s\n", argv[argc-i] ) ;
tomwalters@0 199 exit( 1 ) ;
tomwalters@0 200 }
tomwalters@0 201 }
tomwalters@0 202 else if ( isstr( outstr, "stdout") ) ofp = stdout ;
tomwalters@0 203 else if ( ( ofp = fopen( outstr, "w" ) ) == (FILE *)0 ) {
tomwalters@0 204 fprintf( stderr,"scale: can't create %s\n", outstr ) ;
tomwalters@0 205 exit( 1 ) ;
tomwalters@0 206 }
tomwalters@0 207 first = 0 ;
tomwalters@0 208 }
tomwalters@0 209
tomwalters@0 210 else {
tomwalters@0 211 if ( isoff( outstr ) ) {
tomwalters@0 212 fclose ( ofp ) ;
tomwalters@0 213 if ( i == 0 ) ofp = stdout ;
tomwalters@0 214 else if ( ( ofp = fopen( argv[argc-i], "w" ) ) == (FILE *)0 ) {
tomwalters@0 215 fprintf( stderr,"scale: can't create %s\n", argv[argc-i] ) ;
tomwalters@0 216 exit( 1 ) ;
tomwalters@0 217 }
tomwalters@0 218 }
tomwalters@0 219 }
tomwalters@0 220 }
tomwalters@0 221
tomwalters@0 222
tomwalters@0 223 /*
tomwalters@0 224 Return parameters `shift' and `scale' to normalize the data for zero mean
tomwalters@0 225 and unit std dev:
tomwalters@0 226 shift = mean
tomwalters@0 227 scale = 1 / sqrt(variance)
tomwalters@0 228 */
tomwalters@0 229
tomwalters@0 230 getnorm( data, n, shift, scale )
tomwalters@0 231 float *data ;
tomwalters@0 232 int n ;
tomwalters@0 233 float *shift, *scale ;
tomwalters@0 234 {
tomwalters@0 235 int i ;
tomwalters@0 236 float sum = 0, sumsq = 0 ;
tomwalters@0 237
tomwalters@0 238 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 239 sum += data[i] ;
tomwalters@0 240 sumsq += data[i] * data[i] ;
tomwalters@0 241 }
tomwalters@0 242
tomwalters@0 243 *shift = sum / n ;
tomwalters@0 244 *scale = 1. / sqrt( sumsq / n - *shift * *shift ) ;
tomwalters@0 245 }
tomwalters@0 246
tomwalters@0 247
tomwalters@0 248 /*
tomwalters@0 249 Return parameters `shift' and `scale' to fit the given float data into the
tomwalters@0 250 amplitude range delimited by `top' and `bottom'.
tomwalters@0 251 */
tomwalters@0 252
tomwalters@0 253 getrange( data, n, top, bottom, shift, scale )
tomwalters@0 254 float *data ;
tomwalters@0 255 int n ;
tomwalters@0 256 float top, bottom ;
tomwalters@0 257 float *shift, *scale ;
tomwalters@0 258 {
tomwalters@0 259 float min = 1e+8, max = (-1e+8) ;
tomwalters@0 260 int i ;
tomwalters@0 261
tomwalters@0 262 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 263 if ( data[i] > max ) max = data[i] ;
tomwalters@0 264 if ( data[i] < min ) min = data[i] ;
tomwalters@0 265 }
tomwalters@0 266
tomwalters@0 267 *scale = ( top - bottom ) / ( max - min ) ;
tomwalters@0 268 *shift = ( min * top - max * bottom ) / ( top - bottom ) ;
tomwalters@0 269 }
tomwalters@0 270
tomwalters@0 271