Mercurial > hg > aim92
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 |