Skip to content
Back to top

# Biquad Filters

## Single Biquad

A second order biquadratic filter, which can be used to implement many common second order filters. The filter had been implemented in the direct form 1, and uses the xcore.ai vector unit to calculate the 5 filter taps in a single instruction.

Coefficients are stored in Q1.30 format to benefit from the vector unit, allowing for a filter coefficient range of `[-2, 1.999]`. For some high gain biquads (e.g. high shelf filters), the numerator coefficients may exceed this range. If this is the case, the numerator coefficients only should be right-shifted until they fit within the range (the denominator coefficients cannot become larger than 2.0 without the poles exceeding the unit circle). The shift should be passed into the API, and the output signal from the biquad will then have a left-shift applied. This is equivalent to reducing the overall signal level in the biquad, then returning to unity gain afterwards.

The `state` should be initialised to `0`. The `state` and `coeffs` must be word-aligned.

C API

int32_t adsp_biquad(

  int32_t new_sample,
  q2_30 coeffs[5],
  int32_t state[8],
  left_shift_t lsh,

)

  Biquad filter. This function implements a biquad filter. The filter is implemented as a direct form 1. The `coeffs` parameter should contain b0/a0, b1/a0, b2/a0, -a1/a0, and -a2/a0 in that order, all represented by fixed-point values shifted left by `30-lsh` bits.

  Note

  No saturation applied. If output exceeds INT32_MAX, it will overflow.

  Parameters:

    - new_sample – New sample to be filtered

    - coeffs – Filter coefficients

    - state – Filter state. Must be double-word aligned

    - lsh – Left shift compensation value, must be positive

  Returns:

    int32_t Filtered sample

Python API

class audio_dsp.dsp.biquad.biquad(coeffs: list[float], fs: int, n_chans: int = 1, Q_sig: int = 27)

  A second order biquadratic filter instance.

  This implements a direct form 1 biquad filter, using the coefficients provided at initialisation: a0*y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]

  For efficiency the biquad coefficients are normalised by a0 and the output a coefficients multiplied by -1.

  When the coefficients are updated, the biquad states are reset. This helps avoid large errors, but can make this implementation unsuitable for real time control. For real time control, `biquad_slew` may be a better choice.

  Parameters:
    coeffs list[float]

      List of normalised biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0

    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    coeffs list[float]

      List of normalised float biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, rounded to int32 precision.

    int_coeffs list[int]

      List of normalised int biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, scaled and rounded to int32.

    b_shift int

      The number of right shift bits applied to the b coefficients. The default coefficient scaling allows for a maximum coefficient value of 2, but high gain shelf and peaking filters can have coefficients above this value. Shifting the b coefficients down allows coefficients greater than 2, with the cost of b_shift bits of precision.

  process(sample: float, channel: int = 0) → float

    Filter a single sample using direct form 1 biquad using floating point maths.

    Parameters:
      sample float

        The input sample to be processed.

      channel int, optional

        The channel index to process the sample on. Default is 0.

    Returns:
      float

        The processed sample.

  update_coeffs(new_coeffs: list[float])

    Update the saved coefficients to the input values.

    Parameters:
      new_coeffs list[float]

        The new coefficients to be updated.

  reset_state()

    Reset the biquad saved states to zero.

## Single Slewing Biquad

This is similar to Biquad, but when the target coefficients are updated it slew the applied coefficients towards the new values. This can be used for real time adjustable filter control. If the left-shift of the coefficients changes, this is managed by the `biquad_slew_t` object:

struct biquad_slew_t

  Slewing biquad state structure.

  Public Members

  q2_30 target_coeffs[8]

    Target filter coefficients, the active coefficients are slewed towards these

  q2_30 active_coeffs[8]

    Active filter coefficients, used to filter the audio

  left_shift_t lsh

    Left shift compensation for if the filter coefficents are large and cannot be represented in Q1.30, must be positive

  int32_t slew_shift

    Shift value used by the exponential slew

  left_shift_t remaining_shifts

    Remaining shifts for cases when the left shift changes during a target_coeff update.

C API

Filtering the samples can be carried out using `adsp_biquad`:

    for (int j=0; i < n_samples; i++){
        adsp_biquad_slew_coeffs(&slew_state, states, 1);
        for (int i=0; i < n_chans; i++){
          samp_out[i, j] = adsp_biquad(samp_in[i, j], slew_state.active_coeffs, states[i], slew_state.lsh);
        }
    }

void adsp_biquad_slew_coeffs(

  biquad_slew_t *slew_state,
  int32_t **states,
  int32_t channels,

)

  Slew the active filter coefficients towards the target filter coefficients. This function should be called either once per sample or per frame, and before calling `adsp_biquad` to do the filtering.

  Parameters:

    - slew_state – Slewing biquad state object

    - states – Filter state for each biquad channel

    - channels – Number of channels in states

See also `adsp_biquad_slew_init()` and `adsp_biquad_slew_update_coeffs()`.

Python API

class audio_dsp.dsp.biquad.biquad_slew(

  coeffs: list[float],
  fs: int,
  n_chans: int = 1,
  slew_shift: int = 6,
  Q_sig: int = 27,

)

  A second order biquadratic filter instance that slews between coefficient updates.

  This implements a direct form 1 biquad filter, using the coefficients provided at initialisation: a0*y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]

  For efficiency the biquad coefficients are normalised by a0 and the output a coefficients multiplied by -1.

  When the target coefficients are updated, the applied coefficients are slewed towards the new target values. This makes this implementation suitable for real time control. A table of the first 10 slew shifts is shown below:

  slew_shift | Time constant (ms)
  --- | ---
  1 | 0.03
  2 | 0.07
  3 | 0.16
  4 | 0.32
  5 | 0.66
  6 | 1.32
  7 | 2.66
  8 | 5.32
  9 | 10.66
  10 | 21.32

  Parameters:
    coeffs list[float]

      List of normalised biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0

    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    slew_shift int

      The shift value used in the exponential slew.

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    coeffs list[float]

      List of normalised float biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, rounded to int32 precision.

    int_coeffs list[int]

      List of normalised int biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, scaled and rounded to int32.

    b_shift int

      The number of right shift bits applied to the b coefficients. The default coefficient scaling allows for a maximum coefficient value of 2, but high gain shelf and peaking filters can have coefficients above this value. Shifting the b coefficients down allows coefficients greater than 2, with the cost of b_shift bits of precision.

    target_coeffs list[float]

      List of normalised float target biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, rounded to int32 precision. The coeffs are slewed towards these values.

    target_coeffs_int list[int]

      List of normalised int target biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, scaled and rounded to int32. The int_coeffs are slewed towards these values.

  process(sample: float, channel: int = 0) → float

    `process` is not implemented for the slewing biquad, as the coefficient slew is shared across the channels.

    Parameters:
      sample float

        The input sample to be processed.

      channel int, optional

        The channel index to process the sample on. Default is 0.

    Returns:
      float

        The processed sample.

  update_coeffs(new_coeffs: list[float])

    Update the saved coefficients to the input values.

    Parameters:
      new_coeffs list[float]

        The new coefficients to be updated.

  reset_state()

    Reset the biquad saved states to zero.

## Cascaded Biquads

The cascaded biquad module is equivalent to 8 individual biquad filters connected in series. It can be used to implement a simple parametric equaliser or high-order Butterworth filters, implemented as cascaded second order sections.

C API

int32_t adsp_cascaded_biquads_8b(

  int32_t new_sample,
  q2_30 coeffs[40],
  int32_t state[64],
  left_shift_t lsh[8],

)

  8-band cascaded biquad filter This function implements an 8-band cascaded biquad filter. The filter is implemented as a direct form 1 filter.

  Note

  The filter coefficients must be in [8][5]

  Parameters:

    - new_sample – New sample to be filtered

    - coeffs – Filter coefficients

    - state – Filter state

    - lsh – Left shift compensation value

  Returns:

    int32_t Filtered sample

Python API

class audio_dsp.dsp.cascaded_biquads.cascaded_biquads_8(coeffs_list, fs, n_chans, Q_sig=27)

  A class representing a cascaded biquad filter with up to 8 biquads.

  This can be used to either implement a parametric equaliser or a higher order filter built out of second order sections.

  8 biquad objects are always created, if there are less than 8 biquads in the cascade, the remaining biquads are set to bypass (b0 = 1).

  For documentation on individual biquads, see `audio_dsp.dsp.biquad.biquad`.

  Parameters:
    coeffs_list list

      List of coefficients for each biquad in the cascade.

    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    biquads list

      List of biquad objects representing each biquad in the cascade.

  process(sample, channel=0)

    Process the input sample through the cascaded biquads using floating point maths.

    Parameters:
      sample float

        The input sample to be processed.

      channel int

        The channel index to process the sample on.

    Returns:
      float

        The processed output sample.

  reset_state()

    Reset the biquad saved states to zero.

## Cascaded Biquads 16

This extends the CascadedBiquads class to have 16 cascaded filters. However, The 8 filter C implementation should still be used.

C API

See Cascaded Biquads.

Python API

class audio_dsp.dsp.cascaded_biquads.cascaded_biquads_16(coeffs_list, fs, n_chans, Q_sig=27)

  A class representing a cascaded biquad filter with up to 16 biquads.

  This can be used to either implement a parametric equaliser or a higher order filter built out of second order sections.

  16 biquad objects are always created, if there are less than 16 biquads in the cascade, the remaining biquads are set to bypass (b0 = 1).

  For documentation on individual biquads, see `audio_dsp.dsp.biquad.biquad`.

  Parameters:
    coeffs_list list

      List of coefficients for each biquad in the cascade.

    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    biquads list

      List of biquad objects representing each biquad in the cascade.

  process(sample, channel=0)

    Process the input sample through the cascaded biquads using floating point maths.

    Parameters:
      sample float

        The input sample to be processed.

      channel int

        The channel index to process the sample on.

    Returns:
      float

        The processed output sample.

  reset_state()

    Reset the biquad saved states to zero.