Biquad filters in C++ using KFR

25 July 2016

Digital biquad filters and biquad design functions have been part of the KFR framework since its first version.

The biquad algorithm uses Transposed Direct Form II, which reduces quantization errors in floating-point calculations.

Frequency arguments are normalized to the sample rate (cycles per sample). They must lie strictly between 0.0 and 0.5, where 0.5 is the Nyquist frequency.

Include the header <kfr/dsp.hpp> to use the biquad functions.

Example 1

#include <kfr/dsp.hpp>
 
using namespace kfr;
 
void test_biquad_lp(double f, double fs, univector<double>& data)
{
    // create the coefficients for the low-pass filter (Q=0.5)
    biquad_section<double> bq = biquad_lowpass<double>(f / fs, 0.5);
 
    // perform the filtering and write the result back to data
    // iir() returns a lazy expression; assigning it runs the filter
    data = iir(data, iir_params{ bq });
}

The following filter design functions are implemented: biquad_allpass, biquad_bandpass, biquad_highpass, biquad_highshelf, biquad_lowpass, biquad_lowshelf, biquad_notch, biquad_peak (All pass, Band pass, High pass, High shelf, Low pass, Low shelf, Notch and Peak filter, respectively).

This code snippet plots the impulse and frequency response of the constructed biquad filter. It requires Python with NumPy, SciPy, and Matplotlib, plus the dspplot module, and python or python3 must be on the PATH.

Example 2

#include <kfr/all.hpp>
 
using namespace kfr;

void show_biquad_freqresp()
{
    // create the filter
    // the list can hold any number of sections, so you can build
    // a higher-order IIR filter from a biquad cascade
    auto params = iir_params{ biquad_lowshelf<double>(0.3, -1.0) };
    univector<double, 128> output = iir(unitimpulse(), params);
    plot_save("biquad_lowshelf", output, "title='Biquad low shelf'");
}

Biquad performance benchmark

Benchmark source code

Reviewed and updated for KFR 7 in Oct 2026.