Skip to main content

IirFilter

Namespace: RTPROCESSINGLIB  ·  Library: DSP Library

Python equivalent

mne.filter.filter_data (method='iir') in MNE-Python.

#include <dsp/iirfilter.h>

class UTILSLIB::IirFilter

Butterworth IIR filter design and application using second-order sections.

All filter types (LP, HP, BP, BS) are supported via the classical analogue-prototype → bilinear-transform design route with pre-warped cutoff frequencies. The resulting biquad cascade is numerically stable for high filter orders.

src/examples/ex_dsp_spectral/main.cpp
const QVector<IirBiquad> sos = IirFilter::designButterworth(4, IirFilter::LowPass, 30.0, 0.0, kSFreq);
const RowVectorXd lowPassed = IirFilter::applyZeroPhase(signal, sos); // forward-backward, no phase shift

Static Methods​

designButterworth(iOrder, type, dCutoffLow, dCutoffHigh, dSFreq)​

Design a Butterworth filter as a cascade of second-order sections.

Parameters:

  • iOrder : int Filter order (≥ 1). For BP/BS the effective order is 2*iOrder.

  • type : FilterType Filter type: LowPass, HighPass, BandPass, or BandStop.

  • dCutoffLow : double Lower cutoff frequency in Hz. Used for LP, HP, BP, BS.

  • dCutoffHigh : double Upper cutoff frequency in Hz. Used for BP and BS only.

  • dSFreq : double Sampling frequency in Hz.

Returns:

  • QVector< IirBiquad > — QVector of IirBiquad sections (multiply their transfer functions to get H(z)).

applySos(vecData, sos)​

Apply a biquad cascade to one data row (causal, single-pass).

Parameters:

  • vecData : const Eigen::RowVectorXd & Input row vector.

  • sos : const QVector< IirBiquad > & Second-order sections from designButterworth().

Returns:

  • Eigen::RowVectorXd — Filtered row vector (same length as vecData).

applyZeroPhase(vecData, sos)​

Apply a biquad cascade with zero-phase (forward + backward pass) to one row.

The effective order is doubled and there is no phase distortion.

Parameters:

  • vecData : const Eigen::RowVectorXd & Input row vector.

  • sos : const QVector< IirBiquad > & Second-order sections from designButterworth().

Returns:

  • Eigen::RowVectorXd — Zero-phase filtered row vector (same length as vecData).

applyZeroPhaseMatrix(matData, sos)​

Apply zero-phase filtering to every row of a matrix (each row = one channel).

Parameters:

  • matData : const Eigen::MatrixXd & Input matrix (n_channels x n_samples).

  • sos : const QVector< IirBiquad > & Second-order sections from designButterworth().

Returns:

  • Eigen::MatrixXd — Filtered matrix (n_channels x n_samples).

Example​

Used in examples​

ex_dsp_spectral​

Spectral and filtering tools of the dsp library on signals with known content.

src/examples/ex_dsp_spectral/main.cpp, line 192
const QVector<IirBiquad> sos = IirFilter::designButterworth(4, IirFilter::LowPass, 30.0, 0.0, kSFreq);
const RowVectorXd lowPassed = IirFilter::applyZeroPhase(signal, sos); // forward-backward, no phase shift
// scipy.signal.butter(4, 30, 'low', fs=200, output='sos') and sosfreqz: |H| = 0.99996, 0.70711, 0.01878
ok &= expect(sos.size() == 2 && std::fabs(gainAt(sos, 10.0) - 0.9999564172449813) < 1e-9 && std::fabs(gainAt(sos, 30.0) - 0.7071067811865477) < 1e-9 && std::fabs(gainAt(sos, 60.0) - 0.018777212012474308) < 1e-9,
"Butterworth gain at 10/30/60 Hz = scipy");
RowVectorXd only20(n);
for (int t = 0; t < n; ++t) {
only20(t) = std::sin(2.0 * kPi * 20.0 * t / kSFreq);
}
// scipy.signal.sosfiltfilt deviates from the 20 Hz sine by 0.02593 in the interior (|H(20 Hz)|^2 < 1)
const double lowPassErr = (lowPassed - only20).segment(50, n - 100).cwiseAbs().maxCoeff();
ok &= expect(std::fabs(lowPassErr - 0.02592545936305224) < 1e-3,
QString("zero-phase low-pass: 55 Hz removed, 20 Hz in phase (deviation %1, scipy 0.02593)").arg(lowPassErr));

Authors of this file​