diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/smooth.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,221 @@
+/*
+  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    ) ;
+}
+
+