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 ];
}








