Finite Impulse Reseponse Decimator (firdecim)

API Keywords: firdecim

The firdecim object family implements a basic interpolator with an integer output-to-input resampling ratio \(D\) . It is essentially just a firfilt object which operates on a block of samples at a time. An example of the firdecimator can be seen in [ref:fig-filter-firdecim-crcf] .

doc/firdecim/filter_firdecim_crcf.png

Figure [fig-filter-firdecim-crcf]. firdecim_crcf (firdecimator) example with \(D=4\) , compensating for filter delay.

Listed below is the full interface to the firdecim family of objects. While each method is listed for firdecim_crcf , the same functionality applies to firdecim_rrrf and firdecim_cccf .

  • firdecim_crcf_create(D,*h,N) creates a firdecim object with a firdecimation factor \(D\) using \(N\) filter coefficients \(\vec{h}\) .
  • firdecim_crcf_create_prototype(D,m,As) creates a firdecim object from a prototype filter with a firdecimation factor \(D\) , a delay of \(Dm\) samples, and a stop-band attenuation \(A_s\) dB.
  • firdecim_crcf_create_rnyquist(type,D,m,beta,dt) creates a firdecim object from a square-root Nyquist prototype filter with a firdecimation factor \(D\) , a delay of \(Dm\) samples, an excess bandwidth factor \(\beta\) , and a fractional sample delay \(\Delta t\) (see [ref:section-filter-firdes-rnyquist] for details).
  • firdecim_crcf_destroy(q) destroys a firdecim object, freeing all internally-allocated memory.
  • firdecim_crcf_print(q) prints the parameters of a firdecim object to the standard output.
  • firdecim_crcf_clear(q) clears the internal buffer of a firdecim object.
  • firdecim_crcf_execute(q,*x,*y,k) computes the output firdecimation of the input sequence \(\vec{x}\) (which is \(D\) samples in size) at the index \(k\) and stores the result in \(y\) .

Filter Delay

The delay of the decimator will depend upon the filter coefficients themselves. Normally, an FIR filter has symmetric coefficients and has a length \(2Mm+1\) in which case the output delay is \(Mm\) samples, where \(M\) is the decimation rate and \(m\) is the filter semi-length. But if the filter coefficients are not symmetric or if the filter length follows a different length, the delay will be something different. Unfortunately the decimator cannot compensate for this automatically since it doesn't know the filter response. The delay could even be a fraction of a sample.

If the filter does have a length \(2Mm+1\) then the output delay will be \(m\) samples; this is one of the reasons designing a filter of this length is convenient. If this is the case, you can then just ignore the first \(m\) output samples (e.g. after decimation), and then flush \(m\) blocks of \(M\) samples each through the filter to compensate for that delay.

Example

An example of the firdecim interface is listed below.

#include <liquid/liquid.h>

int main() {
    // options
    unsigned int M = 4;         // decimation factor
    unsigned int h_len = 21;    // filter length

    // design filter and create decimator object
    float h[h_len];             // filter coefficients
    firdecim_crcf q = firdecim_crcf_create(M,h,h_len);

    // generate input signal and decimate
    float complex x[M];         // input samples
    float complex y;            // output sample

    // run decimator (repeat as necessary)
    {
        firdecim_crcf_execute(q, x, &y);
    }

    // destroy decimator object
    firdecim_crcf_destroy(q);
}

A more detailed example is given in examples/firdecim_crcf_example.c in the main liquid project directory.