One representation of a biquad filter's transfer function is:

\[ H(z) = \frac{ b_0 + b_1 z^{-1} + b_2 z^{-2} } { a_0 + a_1 z^{-1} + a_2 z^{-2} } \]

Without loss of generality, it can be assumed that \(a_0 = 1\) (otherwise divide both top and bottom by the original \(a_0\) to give a new set of coefficients).

Another representation of the transfer function is:

\[ H(z) = g \frac{ (z - Z) (z - Z^*) } { (z - P) (z - P^*) } \]

where \({}^*\) denotes complex conjugation. Here \(Z\) is a zero and \(P\) is a pole, and both are complex, and \(g\) is gain factor, which is real. It will make things easier to assume \(g = 1\), if it isn't then just multiply the input \(x\) by \(g\) before-hand. Multiplying out the top and bottom, and dividing both by \(z^2\), recovers the first representation:

\[ H(z) = \frac{ 1 - 2 \operatorname{Re}{(Z)} z^{-1} + |Z|^2 z^{-2} } { 1 - 2 \operatorname{Re}{(P)} z^{-1} + |P|^2 z^{-2} } \]

Or more explicitly:

\[ \begin{aligned} a_0 &= 1 & a_1 &= -2 \operatorname{Re}{(P)} & a_2 &= |P|^2 \\ b_0 &= 1 & b_1 &= -2 \operatorname{Re}{(Z)} & b_2 &= |Z|^2 \end{aligned} \]

The utility of the second **pole-zero** representation is in filter
design, the former is useful in filter implementation. The **direct form 2**
implementation is a pair of recurrence relations, where \(x\) is the input,
\(y\) is the output, and \(w\) is only used internally:

\[ \begin{aligned} w_n &= \phantom{a_0} x_n - a_1 w_{n-1} - a_2 w_{n-2} \\ y_n &= b_0 w_n + b_1 w_{n-1} + b_2 w_{n-2} \end{aligned} \]

The software Pure-data implements its **biquad~** object
using direct form 2, except with \(a_1\) and \(a_2\) negated. So an
instantiation **biquad~ A B C D E** has the correspondence:

\[ \begin{aligned} A &= -a_1 & B &= -a_2 & C &= b_0 & D &= b_1 & E &= b_2 \end{aligned} \]

The final puzzle is the factorization from direct form 2 into pole-zero representation. Assuming \(a_0 = 1 = b_0\) (otherwise factor out the gain coefficient and normalize), we get:

\[ \begin{aligned} \operatorname{Re}{(Z)} &= -\frac{1}{2} b_1 & \operatorname{Im}{(Z)} &= \sqrt{ b_2 - \frac{1}{4} b_1^2 } \\ \operatorname{Re}{(P)} &= -\frac{1}{2} a_1 & \operatorname{Im}{(P)} &= \sqrt{ a_2 - \frac{1}{4} a_1^2 } \end{aligned} \]

The motivation for this post was
mkfilter
giving code output which is inherently unstable for higher order filters,
reducing it to smaller stages (like biquads) in serial is much less likely
to blow up. I did some experiments converting the pole-zero output from
mkfilter into Pd patches using **cpole~** and **czero~**,
but biquads are more efficient as the input and ouput are both real (a biquad
needs 5 real multiplications and 4 real additions, whereas a single complex
multiplication needs 4 real multiplications and 2 real additions).
The next step is to write a program into which I can pipe mkfilter output,
and get out a Pd patch using some chained biquads.

In the process I fixed some minor issues in the mkfilter source code (retrieved 2015-03-26) and wrote a new build system to get it to compile in the modern age.