Bandpass Filter With Boosting Resonance

Hey all & perhaps the wizard @IvanC

I’ve been using the IIR filters and have them modified a bit and in separate files from the library. I’m now taking a look at the changes going between LP -> HP -> BP as a user.

With the LP & HP, when the Q is boosted the peak raises on the filter, whereas with the BP filter the peak stays uniform in volume and the filter (width) grows or shrinks. this means you get some level jumps as you move between them.

I’ve seen in other places people have them setup so the peak after the Q is uniform through BP / HP / LP, is there a change to the coefficients to make this possible, or are people simple adding some gain compensation after the BP filter processing to match all the peaks up. I saw two different equations for the BP in the filter cookbook stuff, but not sure if that’s what this is addressing?



With s/(s^2+s/Q+1) you get a peak gain of Q and constant gain at the skirt, just like resonant LP/HP, so dividing by Q you get a peak gain of 1. This can be done on the output, or modifying the coefficients. In the cookbook, you have both sets as “bpf (constant skirt gain)” and “bpf (constant peak gain)”.

Thanks @kamedin,

So I’m trying to modify the JUCE IIR to perform with the peak gain of Q, I guess I’m a bit confused because I’m not seeing a 1 : 1 mapping of how those cook book coefficients map to the coefficients in the filters.

Any chance you have tips on vocabulary? I see the s/(s^2+s/Q+1) in the cookbook you’re referring to, is there a name for this? it doesn’t appears this directly relates to the coefficients, I’m guessing it’s an equation representing some other way of looking at the filter maybe?

I’m also guessing that these symbols in the cookbook correlate to some sort of short hand notation on how to handle the cutoff & q, but I don’t see them really defined?

For example judging by the frequency response of the current BPF it make sense it related to this set of coefficients?

Screen Shot 2020-09-26 at 9.08.12 PM

The confusing thing for me is how to apply this to the code, perhaps I’m a bit over my head :sweat: I’m so bad at math I don’t even know the name for the greek symbols.

From the current coefficients could you see what modification to make these the Q gain version of the BPF?

auto n = 1 / std::tan (MathConstants<double>::pi * frequency / (sampleRate));
auto nSquared = n * n;
auto invQ = 1 / Q;
auto c1 = 1 / (1 + invQ * n + nSquared);

inCoefficients.setCoefficients(c1 * n * invQ, 0,
                               -c1 * n * invQ, 1,
                               c1 * 2 * (1 - nSquared),
                               c1 * (1 - invQ * n + nSquared));

Or perhaps you’re aware of somewhere they really break down the cookbook even further?

Thanks for any advice or tips!

In short: replace

inCoefficients.setCoefficients(c1 * n * invQ, 0,
                               -c1 * n * invQ, 1,


inCoefficients.setCoefficients(c1 * n, 0,
                               -c1 * n, 1,

The coefficients are different because Juce uses tan instead of sin/cos, and because they’re normalised so that a0 = 1. The s-domain function is the analog one, a transformation is applied to convert it to the digital z-domain, of the form (1) in the cookbook. To go from a constant-peak to a constant-skirt bpf we multiply by Q, which means multiplying the numerator, which for the digital function means multiplying b0, b1 and b2. b1 is already zero, so we’re left with b0 and b2:

c1 * n * invQ
-c1 * n * invQ

invQ = 1/Q, so we take it out.