Consider an FIR filter with impulse response h and input x, where the output is given by
.
We now examine a number of ways to implement this filter.
If x is finite, and we can interpret it as an infinite signal that is zero outside the specified range, then we can compute y using Matlab's conv() function. That is, if x is a vector containing the N values of the input, h is a vector containing the M + 1 values of the impulse response, then
y = conv(x, h);
yields a vector containing M + N values of the output. This strategy, of course, only works for finite input data.
The following Java class implements an FIR filter.
1 class FIR {
2 private int length;
3 private double[] delayLine;
4 private double[] impulseResponse;
5 private int count = 0;
6 FIR(double[] coefs) {
7 length = coefs.length;
8 impulseResponse = coefs;
9 delayLine = new double[length];
10 }
11 double getOutputSample(double inputSample) {
12 delayLine[count] = inputSample;
13 double result = 0.0;
14 int index = count;
15 for (int i=0; i<length; i++) {
16 result += impulseResponse[i] * delayLine[index--];
17 if (index < 0) index = length-1;
18 }
19 if (++count >= length) count = 0;
20 return result;
21 }
22 }
A class is Java (and in any object oriented language) has both data members and methods. The methods are procedures that operate on the data members, and may or may not take arguments are return values. In this case, there are two procedures, "FIR" and "getOutputSample". The first, lines 6-10, is a constructor, which is a procedure that is called to create an FIR filter. It takes one argument, an array of double-precision floating-point numbers that specify the impulse response of the filter. The second, lines 11-22, takes a new input sample value as an argument and returns a new output sample. It also updates the delay line using a strategy called circular buffering. That is, the count member is used to keep track of where each new input sample should go. It gets incremented (line 19) each time the getOutputSample() method is called. When it exceeds the length of the buffer, it gets reset to zero. Thus, at all times, it contains the M + 1 most recently received input data samples. The most recent one is at index count in the buffer. The second most recent is at count - 1, or if that is negative, at length - 1. Line 17 makes sure that the variable index remains within the confines of the buffer as we iterate through the loop.
The following section of code is the assembly language for a programmable DSP, which is a specialized microprocessor designed to implement signal processing functions efficiently in embedded systems (such as cellular telephones, digital cordless telephones, digital audio systems, etc.). This particular code is for the Motorola DSP56000 family of processors.
1 fir movep x:input,x:(r0)
2 clr a x:(r0)-,x0 y:(r4)+,y0
3 rep m0
4 mac x0,y0,a x:(r0)-,x0 y:(r4)+,y0
5 macr x0,y0,a (r0)+
6 movep a,x:output
7 jmp fir
The code is explained below, line by line. While reading this, it will be helpful to know that this processor has two memory banks that can be separately addressed, called "x" and "y". The code assumes that each input sample can be successively read from a memory location called "input", and that the impulse response is stored in y memory beginning at an address stored in register "r4". Moreover, it assumes that register "r0" contains the address of a section of x memory to use for storing input samples, and that this register has been set up to perform modulo addressing. Modulo addressing means that if it increments or decrements beyond the range of its buffer, then the address wraps around to the other end of the buffer. Finally, it assumes that the register "m0" contains an integer specifying the number of samples in the impulse response minus one.
An FIR filter can be easily implemented using just three digital hardware elements, a unit delay (a latch), a multiplier, and an adder. The unit delay simply updates its output once per sample period, using the value of the input as its new output value. In the convolution sum,
.
notice that at each n we need access to x(n), x(n - 1), x(n - 2), …, x(n - M). We can maintain this set of values by cascading a set of latches to form a delay line, as shown below:
![]()
For each integer n, the output sample is the values in the delay line scaled by h(0), h(1), …, h(M). To obtain these values, we simply tap the delay line, as shown in the following picture

The triangular boxes denote multipliers that multiply by a constant (h(m)). The circles denote adders. The above picture shows a tapped delay line implementation of an FIR filter.