One low-pass design can be turned into a high-pass, a band-pass or a band-stop. Below, an order-3 Butterworth takes the four shapes in turn. Watch the zeros, the open circles, more than the poles.
One prototype, four shapes
An order-3 Butterworth at f_s = 8 kHz: low-pass and high-pass at 1 kHz, band-pass and band-stop from 1 to 2 kHz.
Low-pass, 1 kHz: three poles, and a triple zero at z = −1 that makes the gain 0 at 4 kHz.
Describe this picture
Two panels for an order-3 Butterworth at kHz: low-pass and high-pass at 1 kHz, band-pass and band-stop from 1 to 2 kHz. The plane has the real part across and the imaginary part up, both from −1.2 to 1.2, and always shows the unit circle. Poles are crosses and zeros are open circles; a repeated zero carries its count beside it, such as “○3”. The gain panel plots the gain from −60 to 5 dB against frequency from 0 to 4000 Hz as a solid curve, with dotted verticals at 1000 and 2000 Hz. The readouts are the shape, the number of poles and where the zeros are.
The clip lasts 16 s, with a blank caption while the picture moves. The low-pass at 1 kHz has three poles and a triple zero at that makes the gain 0 at 4 kHz. The triple zero slides round the circle to , and at 5.5 s the high-pass has the same three poles, with 0 Hz now blocked. Then each pole splits into two and moves, and three of the zeros return to −1. At 10 s the band-pass has six poles near the band, and three zeros at and three at block both ends. Then the zeros slide along the circle to ±65.5°. At the end the band-stop has the same six poles and all six zeros on the circle at ±65.5°, the band’s centre, 1456 Hz, where the gain falls below −60 dB. After the clip four buttons in a group named “Shape” choose a shape; choosing one plays the move to it, and the choice is kept in the link, as types.s.
One prototype, four shapes
In Filter specifications (18.1) a spec came in four shapes: low-pass, high-pass, band-pass and band-stop. Analog prototype filters (20.1) gave us only low-passes. IIR design by the bilinear transform (20.2) turned them into digital filters. So where do the other three shapes come from?
I don’t design them from scratch. I take the low-pass and replace its variable by something else, and that move is called a frequency transformation. Think of one stencil: flip it, or repeat it, and the same cut-out makes new patterns.
Analog and digital frequencies meet again on this page, so here are the letters once more. Analog frequency is (rad/s), digital frequency is (rad/sample); Oppenheim and Schafer use the opposite letters.
Start from 20.1’s analog Butterworth prototype, the low-pass with its cutoff at 1 rad/s. Its squared gain is , and its poles sit evenly on the left half of the unit circle. For they are and .
Four substitutions
The low-pass is the plainest case. Replace every by . The new filter does at what the prototype did at , so the cutoff moves from 1 rad/s to .
For a high-pass, replace by . At low frequencies is large, so the filter acts like the prototype’s stop band. At high frequencies it is small, like the prototype’s pass band. At it equals , of size 1, so that is the cutoff, at −3 dB.
A band-pass from to needs a substitution with its own centre, , and width, :
On the axis, becomes . At that is 0, the prototype’s zero frequency, so the band’s centre passes. Near 0 and far above the band it is large, which is the prototype’s stop band. At and at its size is 1, so both edges sit at −3 dB.
A band-stop uses the reciprocal, . Now the band’s centre goes where the prototype’s frequency is infinite, deep in its stop band, and both far ends pass.
Each band substitution is quadratic in . A prototype pole becomes the two roots of , so each pole becomes two. An order-3 prototype gives an order-6 band filter.
The digital design adds 20.2’s two steps. Pre-warp the edges with , substitute, and map with the bilinear transform. SciPy does all of it in one call, such as butter(3, 1000, btype='high', fs=8000).
The picture at the top of the page shows the four results in the z-plane, where the filter is used. Watch where the poles, drawn as crosses, and the zeros, drawn as open circles, go.
After the clip, choose a shape with its button to play the move to it again. Notice that both band filters have six poles, twice the prototype’s three.
Why the poles stay where they are
The high-pass surprised me the first time I drew it: its poles are the low-pass’s poles. The prototype’s poles lie on the unit circle, where . So the high-pass substitution sends a pole to . That is the low-pass pole reflected across the real axis, and poles come in such pairs, so the set does not change.
The zeros are what moves. The prototype has no zeros at finite , but its gain falls like as grows: three zeros “at infinity”. By 20.2 the bilinear map lands those at , which is why the low-pass’s gain is 0 at 4 kHz. The high-pass substitution swaps 0 and infinity, so its three zeros sit at , which the map sends to .
The band-pass substitution is infinite both at and at infinity. So its six zeros split three and three: three at and three at , blocking both ends. The band-stop substitution is infinite at , so its zeros sit there, three on each, and the map puts them on the unit circle at the band’s centre. By the same argument, its poles are the band-pass’s poles.
On the circle, the band’s centre is not 1500 Hz, the middle of 1000 and 2000 Hz. The pre-warp bends the axis, and the centre lands at 1456 Hz. The worked example below does the arithmetic.
The maths behind it · changes of variable
Each substitution is a change of variable, and changes of variable compose like functions. A low-pass to band-pass transformation is the low-pass composed with a degree-2 map, so the order doubles. Composing polynomials multiplies their degrees in the same way.
One number retunes the filter
There is a second route. Instead of substituting for before the map, substitute for after it. Use the first-order all-pass of All-pass systems (17.1), with a real number between −1 and 1:
Why an all-pass? By 17.1 it has gain 1 at every frequency. So when , it gives back another point on the circle, which I’ll write . The new filter at then gives what the old one gave at .
The gain keeps its values; they only move along the frequency axis. As runs from 0 to , also runs from 0 to , always climbing, so nothing is folded or repeated.
Constantinides worked out an all-pass for each shape, and Oppenheim and Schafer print his table in their chapter 7. For the band shapes it is a second-order all-pass, so the order doubles there too. To move a low-pass’s cutoff, the first-order one above is enough, and it needs one number, .
The tuning constant
Let’s find . I want the new cutoff to land on the old cutoff :
Multiply out and collect the terms with . Then take half of each angle out of the top and the bottom, and use from Complex exponentials & phasors (3.4). That gives the tuning constant:
A lower cutoff gives a positive and a higher one a negative . With no change, and the all-pass is itself.
Each pole and zero moves too. Put the all-pass into a factor of 16.3’s factored form, and the root goes to . A zero at goes to , so it stays, and the gain at 4 kHz stays 0.
The instrument below applies this to the 1 kHz low-pass of the first instrument. Think of a synthesiser’s cutoff knob: you turn one thing, and the whole filter follows. Watch the poles slide together while the curve keeps its shape.
One number retunes the filter
The order-3 Butterworth low-pass at 1 kHz, every z⁻¹ replaced by (z⁻¹ − a)/(1 − az⁻¹).
Cutoff 1 kHz, a = 0: nothing is substituted yet.
Describe this picture
The same two panels as the first instrument, the plane and the gain, for the order-3 Butterworth low-pass at 1 kHz with every replaced by . The 1 kHz design’s poles stay in the plane as faint crosses for reference, and a dotted path shows how far each pole has travelled. The readouts are the cutoff and . Every frame is the design at the current cutoff, on a 10 Hz grid, so the picture and the readouts follow the cutoff as it moves.
The clip lasts 13 s. It starts at a cutoff of 1 kHz with : nothing is substituted yet. The cutoff eases down to 500 Hz, and all three poles slide together. At 5.5 s, : the poles have moved toward , and the curve has kept its shape. Then the cutoff eases up to 2000 Hz. At the end : the real pole has reached the centre and the pair sits at ±90°, and the caption adds that each frame is exactly the Butterworth design at that cutoff. After the clip the gain curve’s −3 dB point is a handle, a ring on the curve named “Cutoff”, from 100 to 3900 Hz in steps of 10 Hz, with a value like “2000 Hz, a = −0.4142”. The arrow keys move it by 10 Hz, Page Up and Page Down by 250 Hz, and Home and End jump to 100 and 3900 Hz. At 1000, 500 and 2000 Hz the caption is the clip’s own; elsewhere it reads like “Cutoff 3000 Hz: a = −0.7071.” The position is kept in the link, as tune.f.
Notice where the real pole goes at 2 kHz. There and the old real pole is , so : the pole sits at the centre of the circle.
After the clip, drag the ring at the −3 dB point along the curve, or use the arrow keys, to retune the cutoff yourself. Try 100 Hz: climbs to 0.8267 and all three poles crowd near . Then try 3900 Hz, where and the poles crowd near .
The same Butterworth either way
Is the retuned filter a real Butterworth, or only an imitation? Here it is the real thing. The all-pass multiplies every pre-warped frequency by the same number, , which is the analog step in disguise.
A Butterworth’s gain depends only on . So the analog route and the digital route give the same filter: SciPy’s butter(3, f, fs=8000) at the new cutoff. This holds for every low-pass made by the bilinear map, which is why the reference card says “exact for bilinear designs”.
The maths behind it · changes of scale
Changing a random variable’s scale, such as putting a skewed quantity on a log scale, warps the axis and keeps the probabilities. The all-pass does the same to a filter: it keeps the gain’s values and only moves the frequencies they sit at.
Worked example
Let’s redo the page’s numbers. All three designs are order-3 Butterworths at kHz, so rad/s.
1. High-pass from low-pass, 1 kHz. butter(3, 1000, fs=8000) has poles , that is rad, and . Its three zeros sit at . The high-pass has the same poles, and its zeros move to .
What changes besides the zeros is the gain constant of 16.3’s factored form. It is set so that the pass band has gain 1. For the low-pass, at , gives . For the high-pass, at , .
2. Band-pass, 1 to 2 kHz. The edges are and . Pre-warped, they become rad/s and rad/s.
So the centre is rad/s, and the width is rad/s. The map sends the centre to rad, which is or 1456.2 Hz.
The six poles are , and . The prototype’s real pole gives the last pair. The band-stop has the same poles, and its zeros are , three each. Its gain is −65.7 dB at Hz, and the gain itself is zero at 1456.2 Hz.
3. The tuning table. For 500 Hz, and , so . The table gives for eight cutoffs.
| New cutoff (Hz) | Tuning constant |
|---|---|
| 100 | 0.8267 |
| 250 | 0.6158 |
| 500 | 0.3512 |
| 1000 | 0 |
| 1500 | −0.2346 |
| 2000 | −0.4142 |
| 3000 | −0.7071 |
| 3900 | −0.9680 |
At 3000 Hz the poles are and . These are the 1 kHz poles reflected across the imaginary axis: , and becomes .
Where you’ll meet this
A tunable filter has to follow a knob quickly: the cutoff of a synthesiser’s filter, or a band of a tunable equaliser. With the all-pass substitution the knob sets one number, , and the new coefficients follow from it without a new design. Audio equalisers and biquads (20.5) builds the equaliser shapes from second-order filters.
In SciPy the analog route sits behind the btype argument. butter(3, [1000, 2000], btype='bandpass', fs=8000) pre-warps the edges, substitutes into the prototype and applies the bilinear map, as above. Band-pass filters of this kind split a signal into bands in Filter banks (23.1).
Reference card
| Transformation | Analog substitution | Result |
|---|---|---|
| Low-pass, new cutoff | same order | |
| High-pass | zeros at 0 (z = 1) | |
| Band-pass | , | twice the order |
| Band-stop | zeros at | |
| Digital retune | , | exact for bilinear designs |
| Roots under the retune | a zero at stays |