The simplest (and by no means ideal) low-pass filter is given by the
following *difference equation*:

where is the filter input amplitude at time (or sample) , and is the output amplitude at time . The

It is important when working with spectra to be able to convert time from sample-numbers, as in Eq. (1.1) above, to seconds. A more ``physical'' way of writing the filter equation is

To further our appreciation of this example, let's write a computer
subroutine to implement Eq. (1.1). In the computer, and
are data arrays and is an array index. Since sound files
are usually larger than what the computer can hold in memory all at
once, we must process the data in blocks of some reasonable
size. Therefore, the complete filtering operation consists of two
loops, one within the other. The outer loop fills the input array
and empties the output array , while the inner loop does the actual
filtering of the array to produce . Let denote the block
size (*i.e.*, the number of samples to be processed on each iteration of
the outer loop). In C, the inner loop of the subroutine might appear
as shown in Fig.1.3. The outer loop might read something like
``fill from the input file,'' ``call `simplp`,'' and
``write out .''

/* C function implementing the simplest lowpass: * * y(n) = x(n) + x(n-1) * */ double simplp (double *x, double *y, int M, double xm1) { int n; y[0] = x[0] + xm1; for (n=1; n < M ; n++) { y[n] = x[n] + x[n-1]; } return x[M-1]; } |

In this implementation, the first instance of is provided as
the procedure argument `xm1`. That way, both and can
have the same array bounds (
). For convenience, the
value of `xm1` appropriate for the *next* call to
`simplp` is returned as the procedure's value.

We may call `xm1` the filter's *state*. It is the current
``memory'' of the filter upon calling `simplp`. Since this
filter has only one sample of state, it is a *first order*
filter. When a filter is applied to successive blocks of a signal, it
is necessary to save the filter state after processing each block.
The filter state after processing block is then the starting state
for block .

Figure 1.4 illustrates a simple main program which calls `simplp`.
The length 10 input signal `x` is processed in two blocks of
length 5.

/* C main program for testing simplp */ main() { double x[10] = {1,2,3,4,5,6,7,8,9,10}; double y[10]; int i; int N=10; int M=N/2; /* block size */ double xm1 = 0; xm1 = simplp(x, y, M, xm1); xm1 = simplp(&x[M], &y[M], M, xm1); for (i=0;i<N;i++) { printf("x[%d]=%f\ty[%d]=%f\n",i,x[i],i,y[i]); } exit(0); } /* Output: * x[0]=1.000000 y[0]=1.000000 * x[1]=2.000000 y[1]=3.000000 * x[2]=3.000000 y[2]=5.000000 * x[3]=4.000000 y[3]=7.000000 * x[4]=5.000000 y[4]=9.000000 * x[5]=6.000000 y[5]=11.000000 * x[6]=7.000000 y[6]=13.000000 * x[7]=8.000000 y[7]=15.000000 * x[8]=9.000000 y[8]=17.000000 * x[9]=10.000000 y[9]=19.000000 */ |

You might suspect that since Eq. (1.1) is the simplest possible
low-pass filter, it is also somehow the worst possible low-pass
filter. How bad is it? In what sense is it bad? How do we even know it
is a low-pass at all? The answers to these and related questions will
become apparent when we find the *frequency response* of this
filter.

[How to cite this work] [Order a printed hardcopy]

Copyright ©

Center for Computer Research in Music and Acoustics (CCRMA), Stanford University

[Automatic-links disclaimer]