For fixed filters, we can plug biquad coefficients into our programs. But often, we need to calculate them on the fly, to user settings or changes in sample rate. As a companion to the biquad calculator, here are the formulas used, in JavaScript; refer to our article on biquads for implementation diagrams:
function calcBiquad(type, Fc, Fs, Q, peakGain) {
var a0,a1,a2,b1,b2,norm;
var V = Math.pow(10, Math.abs(peakGain) / 20);
var K = Math.tan(Math.PI * Fc / Fs);
switch (type) {
case "lowpass":
norm = 1 / (1 + K / Q + K * K);
a0 = K * K * norm;
a1 = 2 * a0;
a2 = a0;
b1 = 2 * (K * K - 1) * norm;
b2 = (1 - K / Q + K * K) * norm;
break;
case "highpass":
norm = 1 / (1 + K / Q + K * K);
a0 = 1 * norm;
a1 = -2 * a0;
a2 = a0;
b1 = 2 * (K * K - 1) * norm;
b2 = (1 - K / Q + K * K) * norm;
break;
case "bandpass":
norm = 1 / (1 + K / Q + K * K);
a0 = K / Q * norm;
a1 = 0;
a2 = -a0;
b1 = 2 * (K * K - 1) * norm;
b2 = (1 - K / Q + K * K) * norm;
break;
case "notch":
norm = 1 / (1 + K / Q + K * K);
a0 = (1 + K * K) * norm;
a1 = 2 * (K * K - 1) * norm;
a2 = a0;
b1 = a1;
b2 = (1 - K / Q + K * K) * norm;
break;
case "peak":
if (peakGain >= 0) { // boost
norm = 1 / (1 + 1/Q * K + K * K);
a0 = (1 + V/Q * K + K * K) * norm;
a1 = 2 * (K * K - 1) * norm;
a2 = (1 - V/Q * K + K * K) * norm;
b1 = a1;
b2 = (1 - 1/Q * K + K * K) * norm;
}
else { // cut
norm = 1 / (1 + V/Q * K + K * K);
a0 = (1 + 1/Q * K + K * K) * norm;
a1 = 2 * (K * K - 1) * norm;
a2 = (1 - 1/Q * K + K * K) * norm;
b1 = a1;
b2 = (1 - V/Q * K + K * K) * norm;
}
break;
case "lowShelf":
if (peakGain >= 0) { // boost
norm = 1 / (1 + Math.SQRT2 * K + K * K);
a0 = (1 + Math.sqrt(2*V) * K + V * K * K) * norm;
a1 = 2 * (V * K * K - 1) * norm;
a2 = (1 - Math.sqrt(2*V) * K + V * K * K) * norm;
b1 = 2 * (K * K - 1) * norm;
b2 = (1 - Math.SQRT2 * K + K * K) * norm;
}
else { // cut
norm = 1 / (1 + Math.sqrt(2*V) * K + V * K * K);
a0 = (1 + Math.SQRT2 * K + K * K) * norm;
a1 = 2 * (K * K - 1) * norm;
a2 = (1 - Math.SQRT2 * K + K * K) * norm;
b1 = 2 * (V * K * K - 1) * norm;
b2 = (1 - Math.sqrt(2*V) * K + V * K * K) * norm;
}
break;
case "highShelf":
if (peakGain >= 0) { // boost
norm = 1 / (1 + Math.SQRT2 * K + K * K);
a0 = (V + Math.sqrt(2*V) * K + K * K) * norm;
a1 = 2 * (K * K - V) * norm;
a2 = (V - Math.sqrt(2*V) * K + K * K) * norm;
b1 = 2 * (K * K - 1) * norm;
b2 = (1 - Math.SQRT2 * K + K * K) * norm;
}
else { // cut
norm = 1 / (V + Math.sqrt(2*V) * K + K * K);
a0 = (1 + Math.SQRT2 * K + K * K) * norm;
a1 = 2 * (K * K - 1) * norm;
a2 = (1 - Math.SQRT2 * K + K * K) * norm;
norm = 1 / (1 + Math.sqrt(2/V) * K + K * K / V);
b1 = 2 * (K * K / V - 1) * norm;
b2 = (1 - Math.sqrt(2/V) * K + K * K / V) * norm;
}
break;
}
return [ a0, a1, a2, b1, b2 ];
}
Your entire series of posts on filters and resampling has been very helpful. Thanks!
useful
Hi Nigel,
Do you have plan to write a tutorial how to calculate the FIR coefficient based on cut-off frequency for lowpass or bandpass filters?
I’ll keep that in mind. I’ve been busy—I have a couple of partially written articles on other subjects that I need to get back to and finish up, but I’ll think about an article on FIRs. Thanks for the feedback.
Hello Nigel,
I am planning to implement a Biquad IIR filter on an FPGA platform. Right now, I’m searching for a simple yet useful Audio Application for the biquad filter. I would like to ask for your suggestions.
Thanks,
Marika