Skip to main content

Playground · app-grounded instrument

DSP · Audio

Biquad Filter Calculator

Hear a cascade, not just see a curve. Design 1–4 biquads in series, watch the exact magnitude + phase of the total chain, and preview live on real audio — white noise, oscillator, or mic — using the same DF2T core Biquadia ships.

Cascade

The whole cascade is encoded in the URL — send the link, get the same filters.

Frequency response (total cascade)

Mag dBPhase °
Frequency response chart showing the total cascade magnitude (dB) and phase (degrees) from 20 Hz to 20 kHz. The numeric chain coefficients are listed alongside this chart.

Current chain coefficients (normalized, a0=1)

Live audio preview — Biquadia-style

Uses Web Audio IIRFilterNode with the exact coefficients above. Pick a source, hit play, toggle bypass to hear the chain.

stoppedGain

DF2T — JavaScript

// Direct Form II Transposed — one biquad stage
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
// State: z1 = b1*x[n-1]+b2*x[n-2]-a1*y[n-1]-a2*y[n-2], z2 = b2*x[n-1]-a2*y[n-1]
function biquadProcess(x, b0,b1,b2,a1,a2, state){
  const y = b0*x + state[0];
  state[0] = b1*x - a1*y + state[1];
  state[1] = b2*x - a2*y;
  return y;
}
// Cascade: for (const stage of cascade) x = biquadProcess(x, ...stage.coeffs, stage.state);

Reference implementation for your own code — the designer above computes frequency response, not this time-domain recurrence.

DF2T — Swift (Biquadia)

// Swift — same DF2T, stereo-safe
struct Biquad {
  var b0,b1,b2,a1,a2: Double
  var z1: Double = 0, z2: Double = 0
  mutating func process(_ x: Double) -> Double {
    let y = b0 * x + z1
    z1 = b1 * x - a1 * y + z2
    z2 = b2 * x - a2 * y
    return y
  }
}

Swift port for your own project.

Anatomy of the designer

Every knob and curve above answers to the RBJ cookbook below. Here is what each piece is actually doing.

The cascade builder and response plot

  1. 01

    Stage cards. Each card is one biquad. Type selects the RBJ formula branch, freq sets w0 = 2πf0/Fs, and gain only affects peaking/shelf types. Q sets alpha = sin(w0)/(2Q) for every type except the two shelves, which fix the slope at S = 1 exactly as Web Audio’s BiquadFilterNode does — their Q input is disabled rather than left to look live. Removing a stage splices the chain — the remaining stages recompute and redraw instantly.

  2. 02

    Magnitude + phase plot. For each frequency from 20 Hz to 20 kHz (log-spaced, 400 steps), the script evaluates every stage's transfer function H(e^jω) on the unit circle via exact complex arithmetic, then multiplies all Hk for the cascade. dB is 20 log10|H_total|. Phase is the sum of arg(Hk), wrapped to [-180°, 180°]. The plot is not a visual approximation — those curves are the literal mathematical response of the coefficients you see.

  3. 03

    Coefficient readout. The real-time b0,b1,b2,a1,a2 for every stage, normalized to a0=1. These are the exact numbers fed to Web Audio's IIRFilterNode and the same format Biquadia's Metal kernel expects. Copy them into any DF2T implementation and the filter is identical.

Audio pipeline and interaction

  1. 01

    Web Audio chain. Source → IIRFilterNode × N → Gain → destination. Each IIRFilterNode is constructed from the current biquad coefficients with feedforward [b0,b1,b2] and feedback [1,a1,a2]. Changing any parameter tears down and rebuilds the chain — new IIR nodes, clean state, no pops.

  2. 04

    Noise generators. White noise is Math.random() × 2 − 1. Pink noise uses the Voss-McCartney algorithm (seven white noise sources at octave intervals) producing −3 dB/octave rolloff — flatter to the ear. Sine is a standard OscillatorNode at 440 Hz. The sweep does an exponential ramp from 20 Hz to 20 kHz over 8 seconds.

  3. 05

    Bypass toggle. Disconnects the IIR chain and reconnects source directly to gain — zero added latency, direct A/B. The coefficients stay live in the readout, so the plot still shows what you are not hearing. Toggling bypass back rebuilds the chain from the same coefficients.

What the render loop evaluates per pixel

Htotal(ejω)=∏k=1Nb0,k+b1,ke−jω+b2,ke−j2ω1+a1,ke−jω+a2,ke−j2ωH_{\text{total}}(e^{j\omega}) = \prod_{k=1}^{N} \frac{b_{0,k} + b_{1,k}e^{-j\omega} + b_{2,k}e^{-j2\omega}}{1 + a_{1,k}e^{-j\omega} + a_{2,k}e^{-j2\omega}}

This is computed 400 times per plot redraw — once per log-spaced frequency bin. Each evaluation unpacks to a complex division: real/imag numerator divided by real/imag denominator. The cascade multiplies complex numbers, not dB — the dB display is the final step.

What this computes

One stage is five numbers. The designer uses the RBJ Audio EQ Cookbook: three intermediate quantities, then a row of coefficients per filter type, then a division by a0.

01 · Intermediate quantities

ω0=2πf0/Fsα=sin⁡ω0/(2Q)A=10G/40\begin{aligned} \omega_0 &= 2\pi f_0 / F_s \\ \alpha &= \sin\omega_0 / (2Q) \\ A &= 10^{G/40} \end{aligned}

f₀ is the corner or centre frequency, Fs the sample rate, Q the quality factor and G the peak gain in dB (peaking and shelf types only).

02 · Low-pass

b0=b2=(1−cos⁡ω0)/2,b1=1−cos⁡ω0a0=1+α,a1=−2cos⁡ω0,a2=1−α\begin{aligned} b_0 = b_2 &= (1-\cos\omega_0)/2, \quad b_1 = 1-\cos\omega_0 \\ a_0 &= 1+\alpha, \quad a_1 = -2\cos\omega_0, \quad a_2 = 1-\alpha \end{aligned}

At f₀ the magnitude is exactly Q, so Q = 1/√2 puts the corner at −3.01 dB.

03 · Peaking EQ, then normalise

b0=1+αA,b1=−2cos⁡ω0,b2=1−αAa0=1+α/A,a1=−2cos⁡ω0,a2=1−α/A\begin{aligned} b_0 &= 1+\alpha A, \quad b_1 = -2\cos\omega_0, \quad b_2 = 1-\alpha A \\ a_0 &= 1+\alpha/A, \quad a_1 = -2\cos\omega_0, \quad a_2 = 1-\alpha/A \end{aligned}

Every type divides all six values by a₀, which leaves the five numbers b₀, b₁, b₂, a₁, a₂ in the readout. The gain at f₀ is exactly G dB.

Two worked examples

Both are solved when the page is built, by the same rbjCoeffs and freqResponse functions the designer runs, and checked against the cookbook formulas in the site's test suite. The same cookbook design is available as an embeddable card and an API at /api/v1/biquad-design, which takes type, freq, fs, q and gain.

A · A 1 kHz low-pass at 48 kHz

f₀ = 1000 Hz, Fs = 48000 Hz, Q = 0.7071.

b0=(1−cos⁡ω0)/21+α=0.003916b_0 = \frac{(1-\cos\omega_0)/2}{1+\alpha} = 0.003916
b0
0.003916
b1
0.007832
b2
0.003916
a1
-1.815340
a2
0.831004
Gain at 1 kHz
-3.01 dB
Gain at DC
0 dB
Gain at 2 kHz
-12.37 dB

With a0 = 1, the filter runs as y[n] = b0·x[n] + b1·x[n−1] + b2·x[n−2] − a1·y[n−1] − a2·y[n−2]. The response is 20·log10(Q) = -3.01 dB at the corner and falls 9.365 dB further over the next octave. At Nyquist the response is zero, which is −∞ dB.

B · A +3 dB peaking EQ at 2.5 kHz

f₀ = 2500 Hz, Fs = 48000 Hz, Q = 1.41, G = 3 dB.

20log⁡10∣H(ejω0)∣=3 dB20\log_{10}\left|H(e^{j\omega_0})\right| = 3\ \text{dB}
b0
1.036103
b1
-1.728121
b2
0.788870
a1
-1.728121
a2
0.824972
Gain at 2.5 kHz
3 dB
Gain at DC
0 dB
Gain at Nyquist
0 dB

A peaking filter returns to 0 dB at both ends and reaches exactly G at f₀. Here b1 = a1 = -1.728121: both are −2·cos(ω₀)/a₀ for this type.

Gear behind this build

Biquadia stack · 15 picks

Audio & DSP hardware15

More gear across every app: the full Gear list →

Two gotchas worth knowing

RBJ α inversion

LLMs love writing α=Qsin⁡w0\alpha = Q \sin w_0 (inverted). The correct formula is α=sin⁡w0/(2Q)\alpha = \sin w_0 / (2Q). A high-Q filter with inverted α shifts the cutoff by an octave and changes the shape entirely. This page uses the real RBJ — check the α line in the script if you are porting it to your own codebase.

Cascade phase pile-up

Each biquad adds its phase shift to the total. Four stages can easily exceed ±360° of total phase at Nyquist. That is not a bug — it is real group delay. If you stack four high-Q peaking filters, you will hear audible pre-ringing on transients. Phase-wrapping the plot to ±180° hides this, but your ears and an oscilloscope will not be fooled.

Already know the corner you want? 248 designs are solved in advance →Eight types at every third-octave centre from 20 Hz to 20 kHz, each with coefficients at eight sample rates, pole radii solved from the quadratic, and the word length it stops working at.

Frequently asked questions

How do I calculate biquad filter coefficients?

Compute w0 = 2π·f0/Fs and alpha = sin(w0)/(2Q). For a low-pass: b0 = (1 − cos w0)/2, b1 = 1 − cos w0, b2 = (1 − cos w0)/2, a0 = 1 + alpha, a1 = −2·cos w0, a2 = 1 − alpha. Divide all five by a0 so that a0 = 1. For a 1000 Hz low-pass at Fs = 48000 Hz and Q = 0.7071 this gives b0 = 0.003916, b1 = 0.007832, b2 = 0.003916, a1 = -1.815340, a2 = 0.831004. The designer above computes the same cookbook formulas for eight filter types and shows the normalised numbers under "Current chain coefficients".

Can the calculator give coefficients for a peaking EQ as well as a low-pass?

Yes. Choose the Peaking type and set frequency, Q and gain. With A = 10^(gain/40), the peaking filter uses b0 = 1 + alpha·A, b1 = −2·cos w0, b2 = 1 − alpha·A, a0 = 1 + alpha/A, a1 = −2·cos w0, a2 = 1 − alpha/A, then divides by a0. A 2500 Hz peak at Q = 1.41, +3 dB and Fs = 48000 Hz gives b0 = 1.036103, b1 = -1.728121, b2 = 0.788870, a1 = -1.728121, a2 = 0.824972. Its gain at 2500 Hz is 3 dB, and it is 0 dB at DC and at Nyquist.

Is DF2T better than Direct Form 1?

DF2T uses two state variables per biquad instead of four. Fewer state variables mean less memory and less quantization noise because you only round once per sample instead of twice. The transposed topology also eliminates the feed-forward delay line. The trade-off is that the internal node can clip at high Q if not guarded with saturation — Biquadia clamps z1/z2 after every sample for exactly this reason.

Why do the coefficients change when I switch sample rates?

The RBJ cookbook formulas compute w0 = 2π f0 / Fs. Changing Fs changes w0, which cascades through every cos/sin computation and alpha. A 1 kHz lowpass at 48 kHz and 44.1 kHz needs different b0–a2 to hit the same f0. The frequency response recalculates automatically, but if you are switching rates mid-audio-stream in a real app, you must recompute all coefficients at the new Fs before the next buffer.

Can I implement more than four biquads on a microcontroller?

Yes — on a 180 MHz Cortex-M4 with a CMSIS-DSP biquad cascade, you can run 30–60 biquads at 48 kHz before hitting the real-time deadline. Each DF2T stage costs 5 MACs per sample. At 48 kHz, 60 stages is 14.4 MMAC/s — well within budget. Q format (Q1.31 fixed-point) matters more than stage count. See the MPU9250 field note for Biquadia's fixed-point DF2T ARM implementation used on-device.

Why does a high-Q peaking filter ring even after the impulse stops?

High Q means poles are close to the unit circle — near |z| = 1. The impulse response is an exponentially-decaying sinusoid where decay rate = ln(r) per sample. At Q = 10 and f0 = 1 kHz, r ≈ 0.96, so it takes about 100 samples (~2 ms) to decay to 10%. That ringing is not a bug — it is what makes a resonant filter sound like an instrument body or a room mode.

How does Biquadia run hundreds of these on Metal?

Biquadia serializes cascade coefficients into a Metal buffer, then dispatches one compute kernel per audio channel. Each thread processes a DFT block (512–4096 samples), pulling coefficients from the buffer and applying DF2T in an unrolled loop. The GPU's SIMD lanes handle stereo pairs in parallel. The same kernel verified via Accelerate vDSP on CPU for bit-exact cross-check. The Metal path adds ~0.3 ms latency at 512-sample blocks.

Coefficient export

Getting the coefficients out of the browser

Four ways, all free, none metered

  • The copy buttons above. The Direct Form II Transposed JavaScript and the Swift port each copy in one click.
  • The URL. The share link carries the whole cascade, so a design travels as a link and reopens exactly.
  • A plain GET. curl "https://makerportal.ai/api/v1/biquad-design?type=highpass&freq=80&fs=48000&q=0.707" returns the same solve as JSON. No key, no account, CORS open; add &include=curve for the 240-point response.
  • The published catalog. /lab/biquad solves every RBJ type at every ISO corner, with pole radii and 16/24/32-bit behaviour.

None of that sits behind a sign-in, an email or a limit, and none of it is going to.

What this page does not do

It solves and it plots. It does not capture audio, it does not run a file or a batch offline, and outside this tab it is not in your device's audio graph. Those are the jobs a native app exists for, and the studio ships one.

Biquadia — Local Neural DSP & Sound Laboratory. CoreML · Neural Engine (ANE) · Metal Shaders · Native Swift. iOS (iPhone + iPad).

Shareable still

The instrument, captured—not illustrated.

This 16:9 frame is rendered from the real browser instrument above. It is the page's canonical preview for image search, link unfurls, and posts that need to show what the tool actually does.

Download 1280 × 720 JPEG
Biquad Filter Designer — live MakerPortal instrument screenshot
Canonical capture · real UI · no generated scientific artwork