Mercurial > hg > aim92
view tools/smooth.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 |
line wrap: on
line source
/* smooth.c Low-pass filter by windowing in the time or frequency domain. -------- In the time domain the input is convolved with a unit area Gaussian window. In the frequency domain the spectrum is multiplied by a Gaussian mask which zeroes higher frequency components. The transform between domains uses the FFT. One parameter controls the amount of smoothing. This parameter controls the size of the window. Caveats for the frequency-domain approach are descibed in NR p436 (such as the damped ringing effect which results when when sharp edges are smoothed). */ #include <stdio.h> #include <math.h> #include "options.h" #include "units.h" #include "strmatch.h" #include "sigproc.h" char applic[] = "Data smoothing by convolution with Gaussian window." ; static char *helpstr, *debugstr, *sampstr, *lenstr, *varstr, *domstr ; static char *ranstr, *typestr, *sizestr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL }, { "length" , "max" , &lenstr , "Size of input." , VAL }, { "variance" , "20" , &varstr , "Variance of Gaussian window" , VAL }, { "range" , "4" , &ranstr , "Range in standard deviations about mean", VAL }, { "domain" , "time" , &domstr , "Convolve in time or frequency domain" , VAL }, { "type" , "short" , &typestr , "Data type input and output" , VAL }, { "SIZE" , "262144" , &sizestr , "buffer size (s, ms, samples)" , SVAL }, ( char * ) 0 } ; int samplerate ; int length ; float *window ; int points ; short *buf1 ; float *buf2 ; float *out ; FILE *fp ; main (argc, argv) int argc; char **argv; { int maxlen, i ; fp = openopts( option,argc,argv ) ; if ( !isoff( helpstr ) ) helpopts( helpstr, argv[0], applic, option ) ; samplerate = to_Hz( sampstr ) ; if ( ismax( lenstr ) ) maxlen = to_p( sizestr, samplerate ) ; else maxlen = to_p( lenstr, samplerate ) ; out = (float *)malloc( maxlen * sizeof(float) ) ; window = gauss_window( to_p( sqrt_units( varstr ), samplerate ), atof( ranstr ), &points ) ; normalize_area( window, points ) ; if ( isstr( typestr, "short" ) ) { buf1 = (short *)malloc( maxlen * sizeof(short) ) ; length = fread( buf1, sizeof(short), maxlen, fp ) ; } else if ( isstr( typestr, "float" ) ) { buf2 = (float *)malloc( maxlen * sizeof(float) ) ; length = fread( buf2, sizeof(float), maxlen, fp ) ; } else { fprintf( stderr,"smooth: unknown data type [%s]\n", typestr ) ; exit( 1 ) ; } if ( length < maxlen ) { if ( length == 0 ) { fprintf( stderr,"smooth: missing input data\n"); exit( 1 ) ; } if ( !ismax( lenstr ) ) fprintf( stderr,"smooth: warning: %d samples found\n", length ) ; } fclose( fp ) ; if ( points <= 0 ) { fprintf( stderr,"smooth: window size = %d\n", points ) ; exit( 1 ) ; } if ( isstr( typestr, "short" ) ) { if ( points == 1 ) /* no smoothing */ fwrite( buf1, sizeof(short), length, stdout ) ; else if ( iststr( domstr, "time" ) ) convolve_time( buf1, length, window, points, out ) ; else if ( iststr( domstr, "frequency" ) ) convolve_freq( buf1, length, window, points, out ) ; else { fprintf( stderr,"smooth: unknown domain [%s]\n", domstr ) ; exit( 1 ) ; } ftos( out, buf1, length, 1. ) ; fwrite( buf1, sizeof(short), length, stdout ) ; } else { if ( points == 1 ) /* no smoothing */ fwrite( buf2, sizeof(float), length, stdout ) ; else if ( iststr( domstr, "time" ) ) convolve_time2( buf2, length, window, points, out ) ; else if ( iststr( domstr, "frequency" ) ) convolve_freq2( buf2, length, window, points, out ) ; else { fprintf( stderr,"smooth: unknown domain [%s]\n", domstr ) ; exit( 1 ) ; } fwrite( out, sizeof(float), length, stdout ) ; } } convolve_time2( y, n, x, m, z ) float *y ; /* input signal */ int n ; /* length of array y */ float *x ; /* convolution window or filter impulse response */ int m ; /* length of array x */ float *z ; /* output signal of length n (same as input) */ { register int i, j, k, lim1, lim2 ; register float sum ; for ( i = 0 ; i < n ; i++ ) { k = m - 1 ; if ( ( lim1 = i - (m-1)/2 ) < 0 ) { k += lim1 ; lim1 = 0 ; } if ( ( lim2 = i + (m-1)/2 ) > n ) lim2 = n - 1 ; sum = 0 ; for ( j = lim1 ; j <= lim2 ; j++, --k ) sum += x[k] * y[j] ; z[i] = sum ; } } /* Frequency-domain convolution. */ convolve_freq2( y, n, x, m, z ) float *y ; /* input signal */ int n ; /* length of array y */ float *x ; /* convolution window or filter impulse response */ int m ; /* length of array x */ float *z ; /* output signal of length n (same as input) */ { int i, j, n1 ; float *data, *respns, *ans ; n1 = getpower( n + m ) ; /* padded length of input signal */ data = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ; respns = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ; ans = (float *)malloc( ( n1 * 2 + 1 ) * sizeof(float) ) ; /* copy and pad signal */ for ( i = 0 ; i < n ; i++ ) data[i] = y[i] ; for ( ; i < n1 ; i++ ) data[i] = (float)0 ; /* copy window into wrap-around order */ for ( i = m/2, j = 0 ; i < m ; i++, j++ ) respns[i] = x[j] ; for ( i = 0 ; i < m/2 ; i++, j++ ) respns[i] = x[j] ; /* Convolve and copy output */ convlv( data-1, n1, respns-1, m, 1, ans-1 ) ; for ( i = 0 ; i < n ; i++ ) z[i] = ans[i] ; free( data ) ; free( respns ) ; free( ans ) ; }