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