Figure 2: Partial listing of file FIR.h, the FIR filter implementation

const double pi = 3.14159265359;
const complex<double> j(0,1);            // Imaginary unit

#include "filter_types.h"
#include "conversions.h"
#include "Matrix.h"

template <class T>
class basic_FIR
{
public:
    struct Constraint_point { double w, gain; };    
        // For the frequency-sampling filter design method

        // ***************  Constructors  ********************
    basic_FIR (valarray<T> coefficients)
        : h (coefficients)
    { reverse (&h[0], &h[0] + h.size()); }

    basic_FIR (const T * coefficients, size_t N);
        // Not shown here -- similar to the previous one

    basic_FIR (struct Low_pass, double scale_factor = 1);
    basic_FIR (struct High_pass, double scale_factor = 1);
    basic_FIR (struct Band_pass, double scale_factor = 1);

    basic_FIR (double (*frequency_response) (double), 
               int N, double scale_factor = 1);
    basic_FIR (const vector <struct Constraint_point> & H, 
               double scale_factor = 1);

        // *************  Filtering operations  ***************
    template <class Iterator, class Type>
    void output (Iterator sample, Type & result) const
    {
            // Use convert in case rounding is required
        convert (inner_product(sample-h.size()+1, sample+1, 
                               &(const_cast<basic_FIR *>(this)->h[0]), 
                               Type()), 
                 result);
    }

    template <class Iterator, class IteratorOut>
    void operator() (Iterator first, Iterator last, 
                     IteratorOut OutputSignal) const
    {
        for (Iterator current = first; current != last; ++current)
            output (current, *OutputSignal++);
    }

        // ************  Misc. member functions  *************

    complex<double> H (double w) const;   // Frequency response

    int length () const  { return h.size(); }

private:
    valarray<T> h;      // filter coefficients

    void compute_coefficients(const vector<Constraint_point>&);
};

typedef basic_FIR<double> FIR;


// *************************************
//      Member functions definitions
// *************************************

template <class T>
basic_FIR<T>::basic_FIR (struct Low_pass filter_descriptor, 
                         double scale_factor)
{
    if (filter_descriptor.N < 2)
        filter_descriptor.N = 2;    // N can not be < 2

    vector<Constraint_point> H (filter_descriptor.N);

    const double Wc = filter_descriptor.Fc * 2 * pi / 
                      filter_descriptor.Fs;

    for (int i = 0; i < H.size(); i++)
    {
        const double delta_w = pi / (H.size() - 1);     
                // delta_w is the difference in w between two 
                // consecutive frequency samples

        H[i].w = i * delta_w;

        if (H[i].w <= Wc - 2 * delta_w)     // In the pass-band
        {
            H[i].gain = 1 * scale_factor;
        }
        else if (H[i].w >= Wc + 2 * delta_w)    // stop-band
        {
            H[i].gain = 0;
        }
        else        // Transition band (near Wc)
        {           // Use a raised cosine to calculate values 
            H[i].gain = (1 + cos(pi * (H[i].w - (Wc - 2 * delta_w)) / 
                        (4 * delta_w))) * scale_factor / 2;
        }
    }

    compute_coefficients (H);
}

template <class T>
basic_FIR<T>::basic_FIR (double (*frequency_response) (double), int N, double scale_factor)
{
    if (N < 2)  N = 2;      // N can't be < 2

    vector <struct Constraint_point> H(N);

    for (int i = 0; i < N; i++)
    {
        H[i].w = pi * i / (N - 1);
        H[i].gain = scale_factor * frequency_response (H[i].w);
    }

    compute_coefficients (H);  // compute_coefficients resizes h
}

// *** Other constructors not shown here -- see note below 

template <class T>
complex<double> basic_FIR<T>::H (double w) const
{
    complex<double> result = complex<double> (0,0);
    for (int n = 0; n < h.size(); n++)
        result +=  static_cast<double>(h[n]) * exp (-j * (w * n));

    return result;
}

template <class T>
void basic_FIR<T>::compute_coefficients 
                   (const vector<struct Constraint_point> & H)
{
        // Use Gauss method to solve the linear set of eqs.

    const int N = H.size();

    Matrix A (N, N);
    valarray<long double> x(N), b(N);

    for (int n = 0; n < N; n++)
    {
        A[n][0] = 1;
        for (int k = 1; k < N; k++)
            A[n][k] = 2 * cos(k * H[n].w);

        b[n] = H[n].gain;
    }

    Gauss (A,x,b);

    h.resize (2*N - 1);

    convert (x[0], h[N-1]);
    for (int i = 1; i < N; i++)
    {
        convert (x[i], h[N-1 + i]);
        h[N-1 - i] = h[N-1 + i];    // Symmety condition
    }
}

// Some of the functions are omited here (as well as in the 
// next listings) to save magazine space.  The complete version 
// of the code can be downloaded from the Journal's web site, 
// or from my my web site, at http://www.mochima.com/downloads