Butterworth bandpass filter needed

I need to add a butterworth bandpass filter to my audio plugin URGENTLY.

Currently I’m using Juce’s dsp::IIR::Filter (which is great!) but I need a butterworth filter instead and I’ve learned that it will be supported only in the future.

Could anyone recommend me a library to use until then?

I can’t find one which matches all of my requirements:

  • center frequency can be set
  • Q can be set
  • can process one sample at a time
  • can calculate filter response
  • does the coefficients calculation
  • can be used without bothering with complex numbers

Thanks!

Don’t you just cascade a LP and a HP together. Or a bit of googling later…

Audio ToolKit has also lots of EQ filters like that one. And exists as JUCE modules.

1 Like

Thanks, I’ll check them!

Why is it a requirement to change the Q? That’s not a property of Butterworth filters, they always have a Q of sqrt(0.5).

Maybe it’s technically not a Q, but a bandwidth.

DaveH, thanks but it seems that Juce’s butterworth filter supports only LP… There is a designIIRLowpassHighOrderButterworthMethod
but no designIIRHighpassHighOrderButterworthMethod.

I’ve also checked ruohoruotsi’s library earlier but I couldn’t use it without documentation and example code.
And I’m afraid it doesn’t support filter response calculation.

Q and bandwidth are inversely related, so it still doesn’t make sense. You need a bandpass filter with variable Q, which is great, but it will only be a butterworth in the case of Q = sqrt(0.5).

So I’m just saying… you’re looking for something that doesn’t exist. Any 2nd order filter structure is able to create a filter that you want (including juce’s one). Perhaps more relevant, why are you looking for a “butterworth” bandpass?

You can use a lowpass to highpass transformation, quick pseudo code:

float processHighpass (float x)
{
    return x - processLowpass (x);
}

Holy_City, sounds great, I’ll try this, thanks!

@Mayae, OK, how would you draw it up without the words “bandwidth” and “Q”? :slight_smile:

I need a sharp cutoff, this is why I chose Butterworth, but Chebyshev would be fine too.

Bandwidth = c * 1 / Q
where c is some constant that scales bandwidth to your context (eg. hertz), or 1.

Butterworth filters are designed to be maximally flat. This basically means to have the passband as ideal as possible while having no ripple or overshoot. This is generally achieved by having the Q = sqrt(0.5), ie. constant. If you change the Q, it is no longer a butterworth filter because it isn’t maximally flat.

Only “abstract” or generalized 2nd order filter structures have flexible Q, usually based on analog prototypes - they are not of a specific type. Filter designs like butterworth are special cases of the generalized structures. A chebyshev filter doesn’t have “Q” either, it is designed in terms of ripple factors.

Even terms like cutoff, usually defined as the -3 dB point for a maximally flat filter, do not make sense for variable Q filters.

The only thing to draw from this is, that if you need variable Q, it is not a butterworth, cheb. filter or whatever, but just an abstract filter (like the juce one). So use that one :wink: If you need “exotic” filters, use Vinnie’s dsp filters, that can design cheb., elliptical and even legendre filters:

@Mayae, there is for example Renoise’s built-in Butterworth filter which has a parameter named “Q”. What is it then?


I need something like this…

And what do you think about the solution that DaveH and Holy_City suggested?

If you can actually modify the Q, then it’s just not a butterworth. Perhaps they errornously refer to a standard abstract/analog filter as “butterworth”.

DaveH’s system can make a “standard” (where standard usually is RBJ’s cookbook formulas) bandpass if you tune the filters just right. However, it is not straightforward and 2x times slower for both coefficient calculation and processing than a direct bandpass, with (possibly) worse signal quality.

Calculating a highpass from a lowpass should work for any filter implemented using BLT. But please,

IIRCoefficients::makeBandPass(double sampleRate, double frequency, double Q);

is exactly what you want. If you want to analyse the response, use this formula:

http://musicdsp.org/showone.php?id=186

Where a0, a1, a2, b0, b1 is, respectively:
IIRCoefficients.coeffcients[0], IIRCoefficients.coeffcients[1] … etc.

If you don’t like the JUCE implementation, you can use this one:
http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/

However, be aware that it doesn’t calculate shelving filters correctly (neglects Q) and that biquads in general are poor for modulation and low center frequencies. Note that juce’s IIRFilter is also a biquad. If this is a problem, find a suitable SVF filter (but that is a different conversion - welcome to the rabbit hole :wink: )

@Mayae, currently I’m using Juce’s IIR::Filter, but I need something else because it “doesn’t cut sharp enough” (don’t know what terms should I use here but I hope it’s clear: even at a very high Q value you can hear the whole dry input).
So I need some filter which sounds like Butterworth or Chebyshev. Obviously there exist filters like these and their frequencies (cutoff freqs OR center freq+bandwidth) can be set since I use them on daily basis in my music production.
But since I need to add one to my plugin and I don’t have time to develop one or immerse myself into technical details, I asked if anyone could suggest me a library which is capable of this out of the box.

(Meanwhile I’m trying to do this cascaded LP+HP thing, but I have dfficulties, I can’t find any combination of designIIRLowpassHighOrderButterworthMethod parameters which result in any coefficient array… probably this was what you meant when you said “…if you tune the filters just right. However, it is not straightforward…”)

“doesn’t cut sharp enough”

The term you’re looking for is “roll-off.”

A Butterworth is not a particularly well suited filter for steep roll-offs. The design tradeoff is a maximally flat pass band for a shallow roll-off for a given filter order. The solution is to use either a higher order (you get 12dB/octave for every 2nd order added, so an 8th order is needed for a 48/dB rolloff) or to use a different filter like a Chebychev or Elliptical filter.

Looking at the documentation page you can see those methods return an IIR coefficient array.

Thanks :slight_smile:

I mean I get empty arrays… I’ve tried several combinations of parameters (I’ve got the valid ranges from the jasserts in designIIRLowpassHighOrderGeneralMethod) but the result was always an empty array.

Hello afsq !

Could you give me an example of a call you do with the filter design function, which should return something and which gives you an empty array instead ?

Hi @IvanC! I haven’t studied this filter yet so I don’t know if these parameter values make any sense. But they return an empty array:
designIIRLowpassHighOrderButterworthMethod (1000.0f, 44100.0, 0.5f, -19.0f, -21.0f);
designIIRLowpassHighOrderButterworthMethod (1000.0f, 44100.0, 0.2f, -10.0f, -50.0f);
designIIRLowpassHighOrderButterworthMethod (5000.0f, 44100.0, 0.4f, -5.0f, -150.0f);
designIIRLowpassHighOrderButterworthMethod (10000.0f, 44100.0, 0.5f, -0.1f, -290.0f);

Since then I’ve found some combinations which return something but I’d like to understand it before I start using it… :slight_smile:

The problem with your code is that the transition width is too high. In your first instruction, you are basically asking a filter design method to generate a filter that does nothing and with a transition between the passband and the stopband as large as the whole digital frequency spectrum !

The transition width parameter is between 0 and 0.5, and it’s very rare to need any value higher than 0.2 there. The lower the better for the efficiency of the filtering. Moreover, the passband basically stops at cutoff - width * sampleRate / 2 and the stopband starts at cutoff + width * sampleRate / 2. Which means that cutoff - width * sampleRate / 2 can’t be < 0…

Anyway I’m going to work on new high order IIR filter design algorithms designs this week, and I’ll update the documentation + jasserts of the current code :wink:

And I have some tools that I could provide at some point to help people using the filter design classes, since it’s complicated to understand what you do without seeing the frequency response easily…