The latest version of the biquad calculator. It also takes on the functionality of the frequency response grapher:
more filters: I probably won’t go deep into allpass filters, but people ask about calculating their coefficients from time to time, so here it is. And added first order filters for comparison.
phase plot: In earlier versions of the calculator, phase wasn’t important, we’re interested in an amplitude response and live with the phase response. But in adding the allpass filter type, phase is everything. It’s also good to know for other filter types, and for plotting arbitrary coefficients.
frequency response grapher: Edit or paste in coefficients and complete the edit with tab or a click outside the editing field to plot it. You can change the plot controls, but if you change a filter control then the calculator will resume as a biquad calculator.
For instance, clear the b coefficients, and place this sequence into the a coefficients: 1,0,0,0,0,1. Then click on the graph or anywhere outside the edit field to graph it. That’s the response of summing a signal with a copy of it delayed by five samples, a simple FIR filter—a comb filter.
Because the calculator can also plot the response of arbitrary coefficients, the biquad calculator now displays the normalized b0 coefficient (1.0)—which you can ignore in a typical biquad implementation.
The coefficients fields accept values separated by almost anything—commas, spaces, new lines, for instance. And they ignore letters and values followed by “=”. You can use “a0 = 0.971, a1 = 0.215…”, for instance. Even scientific notation is accepted (“1.03e4”,).
Very cool. Thank you so much.
It doesn’t seem like the gain slider changes anything.
It’s subtle, but notice that the Gain field is dimmed for all but the filters where gain makes sense—peak and shelf filters.
I liked your content. Thank you so much.
I have one small doubt.
We are doing audio Equalizer testing, where the default values we are using for the Equalizer are:
FC_lowShelf – 250
FC_highShelf – 1000
Sample rate – 44100
gain – 6
Q factor – 0.707
If I use the above values I am getting noise when I run my code.
What if I set “Gain= 0”? what is the impact?
And the values used for “Sample Rate”, “Qfactor”, and “Gain” are the default configurations?
I don’t understand the question. Are you using my biquad code, or other? For the shelves, Q is not used, so the setting doesn’t matter. Gain is the gain of the shelf. You should not get noise.
thank you very much for the cool tool and webpage.
Having al look at your Biquad formulas I wonder, that some approaches for lowpass 2nd order coefficients use other formulas:
Q = 1/sqrt(2);
w0 = 2*pi*Fc/Fs;
alpha = sin(w0)/2*w0;
a0 = 1+alpha;
a2 = 1-alpha;
b1 = 1-cos(w0);
b0 = b1/2;
b2 = b0;
coeffs = [b0 b1 b2 a0 a1 a2]
coeffs_norm = coeffs / a0;
Do you have an idea what the connection is between these and your formulas ?
They yield the same coefficient values. The only differences are that Robert names his feedback coefficients a and I name mine b, and he uses the identity tan x = sin x / cos x—this can yield less error in for angle angles when using fixed point math for the calculation. They are both derived from the same analog prototypes in the s-domain, via the bilinear z transform, and produce the same values in floating point (with a and b swapped).
The alpha formula is not correct, you need to replace wo for Q at the division: alpha = sin(w0)/2*Q, then the coefficients are the same.
thank you very much for your reply!
Why for the bandpass b1 (resp. a1) is always zero?
Can’t post more. Getting an Internal Server Error.
Hi Dina. It’s just due to the symmetry. A generic second-order bandpass places a zero at 1 and another at -1 on the horizontal axis of the z plane, to pull the response down from each end. The a coefficients dictate the positions of the zeros. The symmetry cancels out the a1 coefficient. You’ll see a different symmetry with the second-order lowpass and highpass, which place both zeros at -1 (Nyquist) for the lowpass, and 1 (0, DC) for the highpass—in both cases a0 and a2 will always be the same value. You can also play with this from the other direction with Pole-Zero placement widget.
thank you very much for your reply!
1. Why for the bandpass b1 (resp. a1) is always zero?
(Whereas with matlab it seems to be composed of a low pass and a high pass filter
with b0-b1 always:
b0 b1 b2
1 2 1
1 -2 1)
2. And how can I calculate a 4th order Biquad with the Biquad formulas?
1. “1 2 1” looks like a lowpass filter. Are you sure you asked the matlab function for a bandpass?
2. Biquads are inherently second order (the “bi”). But you can make higher order filters out of biquads. See Cascading filters.
1. Yes, I’m sure. Therefore I thought, it seems to be composed of a low pass and a high pass filter. Post the matlab code:
n = 2;
ftype = ‘bandpass’
fs = 100e6;
Wn = [1e6 3e6] / fs * 0.5
[z,p,k] = butter(n, Wn, ftype);
[sos, g] = zp2sos(z, p, k);
1.0000 2.0000 1.0000 1.0000 -1.9676 0.9693
1.0000 -2.0000 1.0000 1.0000 -1.9865 0.9868
– see the bottom example.
2. Thank you for the link. I will have a look at. Does this also work for bandpass filters?
1. OK, but that’s a high pass filter and a lowpass filter. Taken together, you get bandpass. But that’s a completely different thing than a second order bandpass derived by bilinear transform. So, I don’t understand the question. Matlab is giving you a lowpass filter, and the same thing transposed to highpass (their b1 flipped in sign). If you run through both, you get a fourth order bandpass.
2. A similar point to the one above. Yes, it works, but will it give you the bandpass filter you want? There are limited absolutes in filters—you’ll only get exactly the same thing if you specify exactly the same constraints—this is why some 12 dB/oct synth filters don’t sound like other designs of the same thing. (Which one is “correct”?) A first order highpass or lowpass will have the expected rolloff and corner, in general, but even then it depends on where the zero is (compare the “one-pole lp” lowpass with the first order lowpass). The Cascading filters calculator produces the exact expected results for a Butterworth (which means maximally flat, in which case Q= 0.7071) second order lowpass derived by bilinear z transform. If you want a Butterworth filter of a higher order than 2, the tool will give you the info to build exactly that. But if you want an arbitrary Q, it won’t give you what you want. In the case of bandpass, Q is an important setting—whether the tool give you the bandpass you want is up to your needs.
thank you very much for the helpful reply.
1. It was just a matter of uncertainty, whether I understood the matlab approach correctly.
2. No, a lowpass- highpass composition is certainly not what I want.
3. Related to the higher order cascaded filter: Does the filter with the first Q have to be the first? In other words: is the order relevant?
4. Is there a way to construct a bandpass filter with a frequency range instead of a single frequency?
3. Related to the higher order cascaded filter: Does the filter with the first Q have to be the first?
It’s not critical. Basically, if limited computing precision is available (rarely the case these days), then you want to have the stages with more gain (includes high Q) first, just so they aren’t boosting accumulated errors from previous stages.
4. Is there a way to construct a bandpass filter with a frequency range instead of a single frequency?
No. There is just a single complex conjugate pair of poles in a second order filter, a single frequency that gets pushed up (a single pole in a tent). In the Pole-Zero placement v2, uncheck “Pair” for the zeros. Slide one zero all the ways left (-1), the other all the way right. That’s a bandpass filter. Set “Pole mag” higher for greater Q, slide “Pole angle” to visit different frequencies. Those are the two degrees of control you have with bandpass.
3. O.K. that makes sense.
4. I see. But if there would be another second order bandpass filter with the same zeros like the first and the pair of poles with a certain slightly different angle and magnitude, the “tent” seems to get a “wider roof”.
Isn’t there a formula to calculate the poles and zeros for a given -3dB “roof beginning” to a given -3DB “end of the roof”?
Thank you very much and sorry for insisting.
“and the pair of poles with a certain slightly different angle and magnitude”—That’s what sets the frequency and Q of the bandpass. You’ll get a better understanding of poles and zeros if you experiment with the Pole-Zero placement widget. Remember that for the poles to move off the horizontal axis, they have to be a conjugate pair. In other word, there may be two poles, but you can only set them to one frequency. It’s not like two poles in a tent, it’s like one, the other is a mirror image. The top and bottom half of the pole-zero plot are always mirror images in any realizable filter. It’s for the same reason that the upper-half any sampled signal mirrors the lower half.
thank you very much for the update.
Would it be possible to add Q to the shelf filters, such that their steepness can be controlled? I’ve seen this with another EQ editor of which I’m rather sure it uses biquads, and found use for it.
The “cookbook formulae” (http://shepazu.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html) have it as well. I fail to transfer that form into yours, looks so different…
Yes, that’s a bit of a can of worms, I found. Robert’s cookbook implementation is certainly one way, but in my mind it has a feature that’s less useful from a musical perspective—on shelf boost, it produces a peak above the shelf level. Many analog shelf filter implementations have a dip before the shelf. My guess is that it was not a targeted design feature, but simply because they made the shelf by summing a lowpass or highpass with variable gain with the direct signal; the inevitable phase difference will cause that dip. I did try to emulate that at one time by manipulating the pole and zero motion in the s-plane prototype, but ultimately there is no single “correct” way to do it, I gave up because I’m not designing a product and have no reason to go down the road of implementing a certain behavior. And trying to make a more general design that can have different behaviors was too much work. If you check both analog and digital shelf filters from many sources, their behaviors vary widely.
I did some more comparisons between the cookbook formulae and yours. The only filters where both implementations give identical results are lowpass and highpass. For the others, there seems to be a different interpretation of the Q value. The result can be matched when changing Q. Except the shelf filters, here Fc seems off to me. The cookbook shelfs yield 50% of the step amplitude at the center frequency, are point symmetric around it. Yours rather have a 3db point there, the symmetry is further away.
A more detailled breakdown of the 2nd order filters:
The gain setting has a dependency to the relative “spread” of the hump. Example: 10 dB boost gives a remaining 58% of the boost level at 2*Fc, versus 1 dB boost has only 34% at 2*Fc. (With the cookbook formulae, this ratio stays approximately constant. However, with very high boost values the hump gets “pointy”, changes its shape.) By changing Q, the results can be matched. The correction is no constant factor, it depends on the boost level. It does not depend on the center frequency.
Low pass, high pass:
Identical results, cheers!
Band pass, all pass, notch:
Different Q interpretation. The results can be matched by changing Q, the “correction factor” is however not constant, but depends on Fc.
Low shelf, high shelf:
Here, it’s rather a different Fc interpretation! The results can be matched by changing Fc to achieve symmetry. (And selecting Q=1 on the cookbook side.) It’s approximately a factor of 0.75 for low shelf and 1/0.75 for high shelf.
I did not see the dip or peak before the shelf which you mentioned, with Q=1.
I can give you some code for comparison, if you like, get in touch.
On bandpass, Robert has two interpretations of bandwidth, IIRC, my implementation matches one of them. His other doesn’t have the peak constant at 0 dB, it’s more of an engineering choice, probably not one you’d implement for an EQ plug-in.
On shelves, we differ, as you noted. I prefer the frequency to be the edge of the step. In other words, if I raise a low shelf at 100 Hz, I want the response to be mostly flat at 100 Hz. But, it’s all a musical choice. iZotope puts theirs in the middle. For Waves, PEQ middle and Q does nothing; REQ edge and Q is very limited but gives the dip all the time. Motu MW EQ is edge, full Q but only puts the dip at the baseline (no edge peaking), unlike Robert’s. Motu’s older PEQ is edge, no Q available. None of it’s wrong, just choices. Though I think Robert’s Q peaking at the edge of a shelf boost is not the right thing, musically. If you’re already boosting a shelf, I don’t think it’s often that you want an additional peak above that at the edge. (And if you do, add a peaking filter.)
Notch: Are you sure? I thought I implemented s^2 / (s^2 + s/Q + 1), looks like that’s what Robert’s doing too. I’ll have to check the APF.
Lowpass and highpass definition is pretty universal, at least for BLT-derived, because the zeros are always at the extremes, the poles at the frequency. For notch, the frequency is obvious (where the zeros sits on the unit circle, complex conjugate), and you’re just sliding the poles toward the zeros. For something like shelf, you have to decide what frequency and Q even mean. For bandpass and peaking filters, you have to decide what bandwidth means (and Q is related to bandwidth). But that’s OK, because even analog implementations are different.
Great work have been done here.
I was trying to use this calculations in Sigma Studio, however it seems that some the values are stocked, from what i found i need to rearrange results to this:
a2: inverted b2
a1: inverted b1
Why is this? Same goes with miniDSP coefs
Thanks, Stian. See here about conventions.
Hello, and thanks for this site.
but: i use minidsp!
your biquads of the a site is b! and the b´s are the a´s, and there turns – to+ und + to-. so it´s right!
grüße aus münchen
Very useful, thanks ! I’m facing the opposite issue, where I’m trying to figure out filter type and params from the biquad coefficients, do you have a source somewhere for doing so, as he equations are quite tight to revert (most likely would necessitate identifying the filter type first looking at the coeffs, and then solving the backward equations…) ?
Yes, you’d need to know the filter type and work backwards, making assumptions about how it was derived (bilinear z transform, for instance). But if it’s a standard type, you should be able to tell by putting the coefficients in the fields, using the frequency response grapher capabilities described below the calculator.
Hello Nigel – great information. I am testing a cascaded biquad shelf filter demo on a TI DSP and it is performing poorly. I am looking at their calculated coefficients and they match exactly to any number of online calculators with the exception of yours (for the low shelf filter). I compared the results of your calculator for a low pass filter, and those match the other online tools I have found exactly.
So I am wondering if your low shelf coefficients are correct (maybe that is the issue with my TI DSP demo), or maybe something is wrong with the low shelf calculations for your tool?
There is no single definition of a shelf filter. If you have a number of EQ plug-ins, you’ll find different behaviors—bring up several at the same frequency, and see what happens when you increase the shelf gain. (See my answer to a comment on this page, search for iZotope.) Even hardware shelving filters differ from each other. If you imagine a shelf by summing a lowpass with direct, and just raise the level of the lowpass, that’s the behavior I use—the shelf frequency is that of the lowpass. For some, frequency is the middle of the slope, and the corners moves as you change gain.
1) I try to implement peek filter with CMSIS-DSP library. How to practically use results obtained from your calculator? Your calculator normalizes b0 (1) while, I guess, CMSIS-DSP normalize a0 but maybe values just have to be swapped (a-b)?
2) Coefficients obtained from Robert Bristow-Johnson formulae are not normalized. How to normalize them correctly to compare with your results and/or use with CMSIS-DSP library?
3) Are the formulae used by your calculator documented somewhere?
The above questions are probably trivial but I am not an expert in this field.
1) You hav your answer right there. Think about it, it’s the output that needs to be normalized. you don’t want the output level changing depending on filter settings. If the other filter is normalizing a0, then yes, they are calling the right side of the DF1, “a”, I call it “b”.
2) Robert’s filters are normalized, we’re doing the same thing is a slightly different way. As I’ve said elsewhere, some filters (especially shelving) are open to interpretation, so there are differences there.
3) Yes, I give source code.
1) ARM in their CMSIS-DSP lib uses the same a/b symbols for coefs but two different algorithms (df1 and df2).
The above diagram indicates that their a0 (on the right side) is always 1 thus it is omitted. What I do not know is if their a0 corresponds to your b0 OR coefs are normalized (“anchored”) in a different way, other place (a0/b0).
2) What I meant by Robert’s coefs not being normalized was that all 6 values are being calculated, none of them has a fixed value (e.g. 1) but maybe I am looking at different version of his equations – link below.
1) The algorithms don’t matter. I haven’t looked at their code, but there is no treason for them to choose one symbol (a or b) for the numerator in one form, but a different one in another. Besides, as I said before, there is only one choice of variable to normalize to, if you want unity gain. I’m normalizing to b0 and they are normalizing to a0, that’s your answer—they are using a where I use b.
2) OK, I hadn’t looked at Robert’s equations in a long time—he doesn’t normalize. Obviously you can do that yourself. He shows the transfer function, his “a” variables in the denominator, so you’d normalize by dividing by a0 (he points this out in equation 2). Just normalize, and swap a/b to compare with mine, you’ll find like filters come up with the same values.
So, do they (ARM) simply use “a” symbols (feedback) where you use “b” symbols and I can simply use coefs created by your calculator with their functions without “re-normalization”?
Both algorithms (df1/df2) use the same a/b symbols and coefs normalization, that is, a0=1 but a0 is in the right (feedback) side.
That is correct. Although from the image, it appears you need to also flip the sign of the feedback coefficients. The image shows all paths being summed, whereas my feedback coefficients (and rbj’s) need to be subtracted (or the signs flipped). If you work out the difference equation from the transfer function, it’s natural to subtract the feedback paths, but some implementations sum all paths, which requires the feedback coefficients to be negated.
Could you include plotting the step response (and maybe the impulse response)?
Request noted! I will think about that when I get a chance (it may be a while, I have some long-delayed projects ahead of it).
It would be nice to be able to set the gain to 65536 in order to generate coefficients for integer systems.
Shouldn’t the sum of the coefficients be zero if the gain is unity?
Hi Ian. For an FIR, the sum of its coefficients is its DC gain (for instance, if all coefficients were 0 except for one coefficient of 1, then FIR filter would have unity gain and a delay related to its tap). For an IIR, the gain is the sum of a coefficients divided by the sum of b coefficients.
Thank you for such clean work, I have created a Pure Data version converted, based on your calculations and it works like a charm!
Your credits are in PD external and GitHub tree.
If you are interested you can find it here:
Thanks for the acknowledgement!
First, thank you for making this grapher it helps me a lot. Can you make the cutoff slider easing change depending on the scale chosen for the frequency (x) axis? This because in log2 and log10 scales the cutoff is a bit inconsistent with the actual position of the slider.
The frequency slider is linear in all cases. True, that makes movement of the curve log, but we normally set cutoff by frequency and not by a good visual position on a log scale, so I think it’s right, from my point of view. I can see why it might be nice to do it the other way, from the point of view of playing with the graph, but…
Or maybe adding an option to do so? not necessarily have it always like this?
Yes, could. Just a time factor, I already lack time for keeping the site properly update with new posts. The number one item I need to do is have a good index page to properly navigate the site, then I’d post more often.
Excellent little web widget Nigel! Very intuitive.
If only it also had a plot showing the positions of the resulting poles and zeros in the Z-domain… Like your pole-zero placement widget does. Maybe something to think about for v4 !?!? 😉
Thanks for sharing,