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.
-
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 by30-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
- 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:
- coeffslist[float]
List of normalised biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0
- fsint
Sampling frequency in Hz.
- n_chansint
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:
- fsint
Sampling frequency in Hz.
- n_chansint
Number of channels the block runs on.
- Q_sig: int
Q format of the signal, number of bits after the decimal point.
- coeffslist[float]
List of normalised float biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, rounded to int32 precision.
- int_coeffslist[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_shiftint
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:
- samplefloat
The input sample to be processed.
- channelint, 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_coeffslist[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.
-
q2_30 target_coeffs[8]#
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()
.
- 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:
- coeffslist[float]
List of normalised biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0
- fsint
Sampling frequency in Hz.
- n_chansint
Number of channels the block runs on.
- slew_shiftint
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:
- fsint
Sampling frequency in Hz.
- n_chansint
Number of channels the block runs on.
- Q_sig: int
Q format of the signal, number of bits after the decimal point.
- coeffslist[float]
List of normalised float biquad coefficients in the form in the form [b0, b1, b2, -a1, -a2]/a0, rounded to int32 precision.
- int_coeffslist[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_shiftint
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_coeffslist[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_intlist[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:
- samplefloat
The input sample to be processed.
- channelint, 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_coeffslist[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.
-
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
- 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_listlist
List of coefficients for each biquad in the cascade.
- fsint
Sampling frequency in Hz.
- n_chansint
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:
- fsint
Sampling frequency in Hz.
- n_chansint
Number of channels the block runs on.
- Q_sig: int
Q format of the signal, number of bits after the decimal point.
- biquadslist
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:
- samplefloat
The input sample to be processed.
- channelint
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.
See Cascaded Biquads.
- 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_listlist
List of coefficients for each biquad in the cascade.
- fsint
Sampling frequency in Hz.
- n_chansint
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:
- fsint
Sampling frequency in Hz.
- n_chansint
Number of channels the block runs on.
- Q_sig: int
Q format of the signal, number of bits after the decimal point.
- biquadslist
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:
- samplefloat
The input sample to be processed.
- channelint
The channel index to process the sample on.
- Returns:
- float
The processed output sample.
- reset_state()
Reset the biquad saved states to zero.