Juce DSP::IIR Filter Linkwitz-Riley 4th order coefficients question

I am trying to implement a Linkwitz-Riley 4th order low pass filter using the juce dsp IIR filter.
I found some code at musicdsp.org and i am trying to plugin the coefficients it to the juce IIR filter, but the dsp::IIR::Coefficients class takes in max 8 coefficients, but i need 9…can someone point me in the right direction?

here is my code so far:

auto wc = 2.0 * MathConstants<float>::pi*frequency;
auto wc2 = wc * wc;
auto wc3 = wc2 * wc;
auto wc4 = wc2 * wc2;
auto k = wc / tan(MathConstants<float>::pi*frequency / sampleRate);
auto k2 = k * k;
auto k3 = k2 * k;
auto k4 = k2 * k2;
auto sqrt2 = sqrt(2);
auto sq_tmp1 = sqrt2 * wc3*k;
auto sq_tmp2 = sqrt2 * wc*k3;
auto a_tmp = 4 * wc2*k2 + 2 * sq_tmp1 + k4 + 2 * sq_tmp2 + wc4;

auto b1 = (4 * (wc4 + sq_tmp1 - k4 - sq_tmp2)) / a_tmp;
auto b2 = (6 * wc4 - 8 * wc2*k2 + 6 * k4) / a_tmp;
auto b3 = (4 * (wc4 - sq_tmp1 + sq_tmp2 - k4)) / a_tmp;
auto b4 = (k4 - 2 * sq_tmp1 + wc4 - 2 * sq_tmp2 + 4 * wc2*k2) / a_tmp;

auto a0 = wc4 / a_tmp;
auto a1 = 4 * wc4 / a_tmp;
auto a2 = 6 * wc4 / a_tmp;
auto a3 = a1;
auto a4 = a0;

Why don’t you simply cascade two second order low-pass IIR filters and two second order high-pass? They are all stable.

You are using floats (at least with pi), and you might get instabilities here with your calculated coefficients.

If you decide to use the cascaded second orders, don’t use one and the same filter to filter your signal twice, create two separate filter objects and just give them the same coefficients.

What’s the reasoning behind this? (genuine curiosity)

oh is it the ‘previous sample gets used in the current calculation’ thing?

right :slight_smile: as a filter object has an internal state, it’s only allowed to be used one time per audio callback

or in other words: a filter must not see one point in time twice :slight_smile:

1 Like

Cascading two second order Butterworth filters was the first approach I tried, and it worked great. just wanted to see if I can make it more “efficient” without cascading filters. I am still new to audio development, and trying to experiment with things.

so there is no way to use 9 coefficients with the juce IIR Filter, right?

If you really want to do it, look at this code:

I use it in one of my plug-ins for a visualization of the frequency response of a Linkwitz Riley filter

auto newCoeffs = IIR::Coefficients<double>::makeLowPass (sampleRate, frequency);
    newCoeffs->coefficients = FilterVisualizerHelper<double>::cascadeSecondOrderCoefficients (newCoeffs->coefficients, newCoeffs->coefficients);

However, that just for visualization of the filters, the audio runs through two separate second order filters.

It’s basically a hard coded convolution of the filter coefficients. The trick to get it into the coefficient object is to directly access the coefficient array.

Oh and use doubles! :slight_smile: Otherwise your filter might explode when the crossover frequency is low

thanks alot :slight_smile:

Using a big 9th order IIR filter instead of several cascaded 1st or 2nd order is a very very bad idea, because of this specific accuracy issue, and it’s not going to make the calculation that much more efficient.

One more thing, two cascaded Butterworth filters don’t make one Butterworth filter, you’ll need to adjust the Q factor of your filters to get a true Butterworth (there are topics about this on KVR-DSP I think)

For a Linkwitz-Riley crossover it’s intended to not get a Butterworth characteristic, as you want a 6dB attenuation at the crossover frequency, instead of -3dB what you’d get with a Butterworth.

That’s why I use it only to call the getMagnitudeForFrequencyArray method for the visualization. I don’t believe it’s faster at all for the processing. Btw it’s a 4th order not 9th :slight_smile:

OK found the topic again : https://www.kvraudio.com/forum/viewtopic.php?f=33&t=278736&start=45

I know, just wanted to provide additional insight.

And I would like to add that it’s a bad idea in general to copy and paste some of this code to do DSP, it’s a lot better to understand what you do instead, otherwise you might miss some important information like the need for all-pass filters in 3+ band separation cases, or the reason why the two Butterworth cascaded filters work in the 4th order case. The topic I posted is interesting for that.

1 Like

Can’t disagree with that! I also noticed that a lot of people want to realize something regarding audio signal processing and try to search for tools/algorithms they can use/copy to achieve this, without exactly knowing what happens from a signal processing or even physics theory point of view. And most of the time without wanting to know exactly. Important topics which come to mind: digital filter theory (especially stability!) or Fourier analysis

Re LR-Crossovers: there also has been a discussion about the needed all-pass filters here on the JUCE forum I think.

Hey Alex / Everyone.

Do you know if it’s possible to have a larger number of coefficients than 8 for dsp::IIR::Coefficients?

No, the class is not designed for that.
If you want to make a Linkwitz-Riley 4th order filter, then you just cascade two second order butterworth filters which coeffs you can create using


1 Like

Have to disagree, the IIR class actually can handle higher orders of IIR filters: https://github.com/WeAreROLI/JUCE/blob/ce6339f33262fb9a342d904fc66d60bb4a51e3c1/modules/juce_dsp/processors/juce_IIRFilter_Impl.h#L171

However, I’d advise against using higher order IIRs, and recommend cascading second order structures.

Also, 4th order Linkwith-Riley crossovers can (should) be design with makeLowPass and makeHighPass, cascading two of each. https://docs.juce.com/master/classIIRCoefficients.html#a789e5863ae22b5a1c817c7156e406874
Two 2nd order butterworth LPs are not the same es one 4th order butterworth LP.

1 Like

Hi @danielrudrich,

Your answers are really helpful. Do you have any suggestion to compute coefficients without instabilities?