tomwalters@0
|
1 /*
|
tomwalters@0
|
2 smooth.c Low-pass filter by windowing in the time or frequency domain.
|
tomwalters@0
|
3 --------
|
tomwalters@0
|
4
|
tomwalters@0
|
5 In the time domain the input is convolved with a unit area Gaussian window.
|
tomwalters@0
|
6 In the frequency domain the spectrum is multiplied by a Gaussian mask which
|
tomwalters@0
|
7 zeroes higher frequency components. The transform between domains uses the FFT.
|
tomwalters@0
|
8
|
tomwalters@0
|
9 One parameter controls the amount of smoothing. This parameter controls the
|
tomwalters@0
|
10 size of the window.
|
tomwalters@0
|
11
|
tomwalters@0
|
12 Caveats for the frequency-domain approach are descibed in NR p436 (such as
|
tomwalters@0
|
13 the damped ringing effect which results when when sharp edges are smoothed).
|
tomwalters@0
|
14
|
tomwalters@0
|
15 */
|
tomwalters@0
|
16
|
tomwalters@0
|
17 #include <stdio.h>
|
tomwalters@0
|
18 #include <math.h>
|
tomwalters@0
|
19 #include "options.h"
|
tomwalters@0
|
20 #include "units.h"
|
tomwalters@0
|
21 #include "strmatch.h"
|
tomwalters@0
|
22 #include "sigproc.h"
|
tomwalters@0
|
23
|
tomwalters@0
|
24 char applic[] = "Data smoothing by convolution with Gaussian window." ;
|
tomwalters@0
|
25
|
tomwalters@0
|
26 static char *helpstr, *debugstr, *sampstr, *lenstr, *varstr, *domstr ;
|
tomwalters@0
|
27 static char *ranstr, *typestr, *sizestr ;
|
tomwalters@0
|
28
|
tomwalters@0
|
29 static Options option[] = {
|
tomwalters@0
|
30 { "help" , "off" , &helpstr , "help" , DEBUG },
|
tomwalters@0
|
31 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
|
tomwalters@0
|
32 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL },
|
tomwalters@0
|
33 { "length" , "max" , &lenstr , "Size of input." , VAL },
|
tomwalters@0
|
34 { "variance" , "20" , &varstr , "Variance of Gaussian window" , VAL },
|
tomwalters@0
|
35 { "range" , "4" , &ranstr , "Range in standard deviations about mean", VAL },
|
tomwalters@0
|
36 { "domain" , "time" , &domstr , "Convolve in time or frequency domain" , VAL },
|
tomwalters@0
|
37 { "type" , "short" , &typestr , "Data type input and output" , VAL },
|
tomwalters@0
|
38 { "SIZE" , "262144" , &sizestr , "buffer size (s, ms, samples)" , SVAL },
|
tomwalters@0
|
39 ( char * ) 0 } ;
|
tomwalters@0
|
40
|
tomwalters@0
|
41
|
tomwalters@0
|
42 int samplerate ;
|
tomwalters@0
|
43 int length ;
|
tomwalters@0
|
44
|
tomwalters@0
|
45 float *window ;
|
tomwalters@0
|
46 int points ;
|
tomwalters@0
|
47
|
tomwalters@0
|
48 short *buf1 ;
|
tomwalters@0
|
49 float *buf2 ;
|
tomwalters@0
|
50 float *out ;
|
tomwalters@0
|
51 FILE *fp ;
|
tomwalters@0
|
52
|
tomwalters@0
|
53
|
tomwalters@0
|
54
|
tomwalters@0
|
55 main (argc, argv)
|
tomwalters@0
|
56 int argc;
|
tomwalters@0
|
57 char **argv;
|
tomwalters@0
|
58 {
|
tomwalters@0
|
59 int maxlen, i ;
|
tomwalters@0
|
60
|
tomwalters@0
|
61 fp = openopts( option,argc,argv ) ;
|
tomwalters@0
|
62 if ( !isoff( helpstr ) )
|
tomwalters@0
|
63 helpopts( helpstr, argv[0], applic, option ) ;
|
tomwalters@0
|
64
|
tomwalters@0
|
65 samplerate = to_Hz( sampstr ) ;
|
tomwalters@0
|
66
|
tomwalters@0
|
67 if ( ismax( lenstr ) ) maxlen = to_p( sizestr, samplerate ) ;
|
tomwalters@0
|
68 else maxlen = to_p( lenstr, samplerate ) ;
|
tomwalters@0
|
69
|
tomwalters@0
|
70 out = (float *)malloc( maxlen * sizeof(float) ) ;
|
tomwalters@0
|
71 window = gauss_window( to_p( sqrt_units( varstr ), samplerate ), atof( ranstr ), &points ) ;
|
tomwalters@0
|
72 normalize_area( window, points ) ;
|
tomwalters@0
|
73
|
tomwalters@0
|
74 if ( isstr( typestr, "short" ) ) {
|
tomwalters@0
|
75 buf1 = (short *)malloc( maxlen * sizeof(short) ) ;
|
tomwalters@0
|
76 length = fread( buf1, sizeof(short), maxlen, fp ) ;
|
tomwalters@0
|
77 }
|
tomwalters@0
|
78 else if ( isstr( typestr, "float" ) ) {
|
tomwalters@0
|
79 buf2 = (float *)malloc( maxlen * sizeof(float) ) ;
|
tomwalters@0
|
80 length = fread( buf2, sizeof(float), maxlen, fp ) ;
|
tomwalters@0
|
81 }
|
tomwalters@0
|
82 else {
|
tomwalters@0
|
83 fprintf( stderr,"smooth: unknown data type [%s]\n", typestr ) ;
|
tomwalters@0
|
84 exit( 1 ) ;
|
tomwalters@0
|
85 }
|
tomwalters@0
|
86
|
tomwalters@0
|
87
|
tomwalters@0
|
88 if ( length < maxlen ) {
|
tomwalters@0
|
89 if ( length == 0 ) {
|
tomwalters@0
|
90 fprintf( stderr,"smooth: missing input data\n");
|
tomwalters@0
|
91 exit( 1 ) ;
|
tomwalters@0
|
92 }
|
tomwalters@0
|
93 if ( !ismax( lenstr ) )
|
tomwalters@0
|
94 fprintf( stderr,"smooth: warning: %d samples found\n", length ) ;
|
tomwalters@0
|
95 }
|
tomwalters@0
|
96 fclose( fp ) ;
|
tomwalters@0
|
97
|
tomwalters@0
|
98 if ( points <= 0 ) {
|
tomwalters@0
|
99 fprintf( stderr,"smooth: window size = %d\n", points ) ;
|
tomwalters@0
|
100 exit( 1 ) ;
|
tomwalters@0
|
101 }
|
tomwalters@0
|
102
|
tomwalters@0
|
103 if ( isstr( typestr, "short" ) ) {
|
tomwalters@0
|
104
|
tomwalters@0
|
105 if ( points == 1 ) /* no smoothing */
|
tomwalters@0
|
106 fwrite( buf1, sizeof(short), length, stdout ) ;
|
tomwalters@0
|
107
|
tomwalters@0
|
108 else if ( iststr( domstr, "time" ) )
|
tomwalters@0
|
109 convolve_time( buf1, length, window, points, out ) ;
|
tomwalters@0
|
110
|
tomwalters@0
|
111 else if ( iststr( domstr, "frequency" ) )
|
tomwalters@0
|
112 convolve_freq( buf1, length, window, points, out ) ;
|
tomwalters@0
|
113
|
tomwalters@0
|
114 else {
|
tomwalters@0
|
115 fprintf( stderr,"smooth: unknown domain [%s]\n", domstr ) ;
|
tomwalters@0
|
116 exit( 1 ) ;
|
tomwalters@0
|
117 }
|
tomwalters@0
|
118
|
tomwalters@0
|
119 ftos( out, buf1, length, 1. ) ;
|
tomwalters@0
|
120 fwrite( buf1, sizeof(short), length, stdout ) ;
|
tomwalters@0
|
121 }
|
tomwalters@0
|
122
|
tomwalters@0
|
123 else {
|
tomwalters@0
|
124
|
tomwalters@0
|
125 if ( points == 1 ) /* no smoothing */
|
tomwalters@0
|
126 fwrite( buf2, sizeof(float), length, stdout ) ;
|
tomwalters@0
|
127
|
tomwalters@0
|
128 else if ( iststr( domstr, "time" ) )
|
tomwalters@0
|
129 convolve_time2( buf2, length, window, points, out ) ;
|
tomwalters@0
|
130
|
tomwalters@0
|
131 else if ( iststr( domstr, "frequency" ) )
|
tomwalters@0
|
132 convolve_freq2( buf2, length, window, points, out ) ;
|
tomwalters@0
|
133
|
tomwalters@0
|
134 else {
|
tomwalters@0
|
135 fprintf( stderr,"smooth: unknown domain [%s]\n", domstr ) ;
|
tomwalters@0
|
136 exit( 1 ) ;
|
tomwalters@0
|
137 }
|
tomwalters@0
|
138
|
tomwalters@0
|
139 fwrite( out, sizeof(float), length, stdout ) ;
|
tomwalters@0
|
140 }
|
tomwalters@0
|
141
|
tomwalters@0
|
142
|
tomwalters@0
|
143 }
|
tomwalters@0
|
144
|
tomwalters@0
|
145
|
tomwalters@0
|
146 convolve_time2( y, n, x, m, z )
|
tomwalters@0
|
147 float *y ; /* input signal */
|
tomwalters@0
|
148 int n ; /* length of array y */
|
tomwalters@0
|
149 float *x ; /* convolution window or filter impulse response */
|
tomwalters@0
|
150 int m ; /* length of array x */
|
tomwalters@0
|
151 float *z ; /* output signal of length n (same as input) */
|
tomwalters@0
|
152 {
|
tomwalters@0
|
153 register int i, j, k, lim1, lim2 ;
|
tomwalters@0
|
154 register float sum ;
|
tomwalters@0
|
155
|
tomwalters@0
|
156 for ( i = 0 ; i < n ; i++ ) {
|
tomwalters@0
|
157
|
tomwalters@0
|
158 k = m - 1 ;
|
tomwalters@0
|
159 if ( ( lim1 = i - (m-1)/2 ) < 0 ) {
|
tomwalters@0
|
160 k += lim1 ;
|
tomwalters@0
|
161 lim1 = 0 ;
|
tomwalters@0
|
162 }
|
tomwalters@0
|
163 if ( ( lim2 = i + (m-1)/2 ) > n )
|
tomwalters@0
|
164 lim2 = n - 1 ;
|
tomwalters@0
|
165
|
tomwalters@0
|
166 sum = 0 ;
|
tomwalters@0
|
167 for ( j = lim1 ; j <= lim2 ; j++, --k )
|
tomwalters@0
|
168 sum += x[k] * y[j] ;
|
tomwalters@0
|
169
|
tomwalters@0
|
170 z[i] = sum ;
|
tomwalters@0
|
171 }
|
tomwalters@0
|
172 }
|
tomwalters@0
|
173
|
tomwalters@0
|
174
|
tomwalters@0
|
175 /*
|
tomwalters@0
|
176 Frequency-domain convolution.
|
tomwalters@0
|
177 */
|
tomwalters@0
|
178
|
tomwalters@0
|
179 convolve_freq2( y, n, x, m, z )
|
tomwalters@0
|
180 float *y ; /* input signal */
|
tomwalters@0
|
181 int n ; /* length of array y */
|
tomwalters@0
|
182 float *x ; /* convolution window or filter impulse response */
|
tomwalters@0
|
183 int m ; /* length of array x */
|
tomwalters@0
|
184 float *z ; /* output signal of length n (same as input) */
|
tomwalters@0
|
185 {
|
tomwalters@0
|
186 int i, j, n1 ;
|
tomwalters@0
|
187 float *data, *respns, *ans ;
|
tomwalters@0
|
188
|
tomwalters@0
|
189 n1 = getpower( n + m ) ; /* padded length of input signal */
|
tomwalters@0
|
190
|
tomwalters@0
|
191 data = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ;
|
tomwalters@0
|
192 respns = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ;
|
tomwalters@0
|
193 ans = (float *)malloc( ( n1 * 2 + 1 ) * sizeof(float) ) ;
|
tomwalters@0
|
194
|
tomwalters@0
|
195 /* copy and pad signal */
|
tomwalters@0
|
196
|
tomwalters@0
|
197 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
198 data[i] = y[i] ;
|
tomwalters@0
|
199 for ( ; i < n1 ; i++ )
|
tomwalters@0
|
200 data[i] = (float)0 ;
|
tomwalters@0
|
201
|
tomwalters@0
|
202 /* copy window into wrap-around order */
|
tomwalters@0
|
203
|
tomwalters@0
|
204 for ( i = m/2, j = 0 ; i < m ; i++, j++ )
|
tomwalters@0
|
205 respns[i] = x[j] ;
|
tomwalters@0
|
206 for ( i = 0 ; i < m/2 ; i++, j++ )
|
tomwalters@0
|
207 respns[i] = x[j] ;
|
tomwalters@0
|
208
|
tomwalters@0
|
209 /* Convolve and copy output */
|
tomwalters@0
|
210
|
tomwalters@0
|
211 convlv( data-1, n1, respns-1, m, 1, ans-1 ) ;
|
tomwalters@0
|
212
|
tomwalters@0
|
213 for ( i = 0 ; i < n ; i++ )
|
tomwalters@0
|
214 z[i] = ans[i] ;
|
tomwalters@0
|
215
|
tomwalters@0
|
216 free( data ) ;
|
tomwalters@0
|
217 free( respns ) ;
|
tomwalters@0
|
218 free( ans ) ;
|
tomwalters@0
|
219 }
|
tomwalters@0
|
220
|
tomwalters@0
|
221
|