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
|