tomwalters@0
|
1 /*
|
tomwalters@0
|
2 filt1.c 1st order LP filter using an exponential smoother
|
tomwalters@0
|
3 (recursive "leaky integrator" filter)
|
tomwalters@0
|
4
|
tomwalters@0
|
5 The n'th recursive update is:
|
tomwalters@0
|
6
|
tomwalters@0
|
7 a) y[n] = a.y[n-1] + x[n] recursive sum
|
tomwalters@0
|
8 b) y[n] = a.y[n-1] + (1-a).x[n] recursive mean
|
tomwalters@0
|
9
|
tomwalters@0
|
10 where decay constant a = exp(-Ts/T)
|
tomwalters@0
|
11 and Ts is sample interval in seconds
|
tomwalters@0
|
12 T is decay time-constant in seconds
|
tomwalters@0
|
13
|
tomwalters@0
|
14 The 1st order LP filter is an exponential window which decays into the past.
|
tomwalters@0
|
15 With decay constant a=1 there is infinite memory because it does not decay.
|
tomwalters@0
|
16 The result is either a steadily accumulating sum or mean.
|
tomwalters@0
|
17 (A zero mean is assumed).
|
tomwalters@0
|
18 With 0 < a < 1 there is a finite decaying memory.
|
tomwalters@0
|
19 The smaller `a', the smaller the memory (it decays faster).
|
tomwalters@0
|
20 With a = 0 the filter output is identical with its input.
|
tomwalters@0
|
21
|
tomwalters@0
|
22 The window width parameter is the time-constant parameter.
|
tomwalters@0
|
23 The half life of the exponential window is given by -T.ln(0.5) = 0.693T
|
tomwalters@0
|
24 ie. for a given time constant, T secs, the window decays to half of its
|
tomwalters@0
|
25 current value in a period of 0.693T secs.
|
tomwalters@0
|
26 (Thus T can be set to accomodate an expected period).
|
tomwalters@0
|
27
|
tomwalters@0
|
28 When the time-constant parameter is given with time units (s or ms) then
|
tomwalters@0
|
29 it is converted to a decay constant using a = exp(-Ts/T).
|
tomwalters@0
|
30 Otherwise it is taken to be the decay constant directly.
|
tomwalters@0
|
31
|
tomwalters@0
|
32 */
|
tomwalters@0
|
33
|
tomwalters@0
|
34 #include <stdio.h>
|
tomwalters@0
|
35 #include <math.h>
|
tomwalters@0
|
36 #include "options.h"
|
tomwalters@0
|
37 #include "units.h"
|
tomwalters@0
|
38 #include "strmatch.h"
|
tomwalters@0
|
39
|
tomwalters@0
|
40 char applic[] = "1st order low-pass filter using exponential smoother." ;
|
tomwalters@0
|
41
|
tomwalters@0
|
42 static char *helpstr, *debugstr, *sampstr, *tcstr, *destr ;
|
tomwalters@0
|
43
|
tomwalters@0
|
44 static Options option[] = {
|
tomwalters@0
|
45 { "help" , "off" , &helpstr , "help" , DEBUG },
|
tomwalters@0
|
46 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
|
tomwalters@0
|
47 { "samplerate", "20kHz" , &sampstr , "Samplerate " , VAL },
|
tomwalters@0
|
48 { "tc" , "3ms" , &tcstr , "Decay time constant" , VAL },
|
tomwalters@0
|
49 { "de" , "mean" , &destr , "Difference equation" , VAL },
|
tomwalters@0
|
50 ( char * ) 0 } ;
|
tomwalters@0
|
51
|
tomwalters@0
|
52
|
tomwalters@0
|
53 int samplerate ;
|
tomwalters@0
|
54 double a ; /* decay constant */
|
tomwalters@0
|
55
|
tomwalters@0
|
56
|
tomwalters@0
|
57 main (argc, argv)
|
tomwalters@0
|
58 int argc;
|
tomwalters@0
|
59 char **argv;
|
tomwalters@0
|
60 {
|
tomwalters@0
|
61 FILE *fp ;
|
tomwalters@0
|
62 short x, y ;
|
tomwalters@0
|
63 int morehelp() ;
|
tomwalters@0
|
64
|
tomwalters@0
|
65 fp = openopts( option,argc,argv ) ;
|
tomwalters@0
|
66 if ( !isoff( helpstr ) )
|
tomwalters@0
|
67 helpopts1( helpstr, argv[0], applic, option, morehelp ) ;
|
tomwalters@0
|
68
|
tomwalters@0
|
69 samplerate = to_Hz( sampstr ) ;
|
tomwalters@0
|
70
|
tomwalters@0
|
71 if ( Units( tcstr ) )
|
tomwalters@0
|
72 a = exp( -(double)( 1. / ( samplerate * to_s( tcstr, samplerate ) ) ) ) ;
|
tomwalters@0
|
73 else
|
tomwalters@0
|
74 a = (double)atof( tcstr ) ;
|
tomwalters@0
|
75
|
tomwalters@0
|
76 y = 0 ; /* initialization */
|
tomwalters@0
|
77
|
tomwalters@0
|
78 if ( iststr( destr, "mean" ) )
|
tomwalters@0
|
79 while ( fread( &x, sizeof(short), 1, fp ) ) {
|
tomwalters@0
|
80 y = a * y + ( 1 - a ) * x ;
|
tomwalters@0
|
81 fwrite( &y, sizeof(short), 1, stdout ) ;
|
tomwalters@0
|
82 }
|
tomwalters@0
|
83
|
tomwalters@0
|
84 else if ( iststr( destr, "sum" ) )
|
tomwalters@0
|
85 while ( fread( &x, sizeof(short), 1, fp ) ) {
|
tomwalters@0
|
86 y = a * y + x ;
|
tomwalters@0
|
87 fwrite( &y, sizeof(short), 1, stdout ) ;
|
tomwalters@0
|
88 }
|
tomwalters@0
|
89
|
tomwalters@0
|
90 else {
|
tomwalters@0
|
91 fprintf( stderr,"unknown de [%s]\n", destr ) ;
|
tomwalters@0
|
92 exit( 1 ) ;
|
tomwalters@0
|
93 }
|
tomwalters@0
|
94
|
tomwalters@0
|
95 fclose( fp );
|
tomwalters@0
|
96 }
|
tomwalters@0
|
97
|
tomwalters@0
|
98
|
tomwalters@0
|
99 /* Return 1 if the str has appended units. Otherwise return 0. */
|
tomwalters@0
|
100
|
tomwalters@0
|
101 Units(str)
|
tomwalters@0
|
102 char *str ;
|
tomwalters@0
|
103 {
|
tomwalters@0
|
104 char *eptr = str + strlen( str ) ;
|
tomwalters@0
|
105
|
tomwalters@0
|
106 if( isdigit( *--eptr ) ) return 0 ; /* last char is digit, so no units */
|
tomwalters@0
|
107 else return 1 ;
|
tomwalters@0
|
108 }
|
tomwalters@0
|
109
|
tomwalters@0
|
110
|
tomwalters@0
|
111
|
tomwalters@0
|
112 morehelp()
|
tomwalters@0
|
113 {
|
tomwalters@0
|
114 fprintf(stderr,"\nde: \n");
|
tomwalters@0
|
115 fprintf(stderr," sum y[n] = a.y[n-1] + x[n] \n");
|
tomwalters@0
|
116 fprintf(stderr," mean y[n] = a.y[n-1] + (1-a).x[n] (unity steady-state gain)\n");
|
tomwalters@0
|
117 exit( 1 ) ;
|
tomwalters@0
|
118 }
|