Two loops, each computing one DFT bin, hear a 770 Hz tone. Watch the one tuned near 770 Hz climb while the other wanders below 20.
A loop that rings at one frequency
Input: a 770 Hz tone at 8 kHz, 205 samples. Two loops, tuned to bins 20 and 18.
Both loops start with the first sample: size 1.00.
Describe this picture
One panel, for a 770 Hz tone at 8 kHz, 205 samples, fed to two loops tuned to bins 20 and 18. It shows the size of each loop’s running total against the sample from 0 to 204. The solid line, ending in a ring, is the loop for (780.5 Hz); the dashed line, ending in a square, is the loop for (702.4 Hz). The readouts are the sample and the two sizes to 2 decimals. There is no control.
The clip plays by itself, and the caption speaks only at the key frames. Both loops start at size 1.00. At the halfway frame, , they are at 49.93 and 7.54. At the end the caption reads “After 205 samples: 91.18 and 13.65. These are |X[20]| and |X[18]|, the same as the FFT gives, at one real multiply per sample each.” With reduced motion on, the picture steps through , 25, 50, 102, 150 and 204, with captions such as “n = 25: 13.06 and 11.52.” The “Hear the tone” button plays the 770 Hz input for 0.5 s.
A loop that rings at one frequency
Your phone’s keypad sends two tones per key. The exchange must know which of 8 frequencies are present, 25 ms at a time. An FFT computes 256 bins to read 8.
This page computes one bin at a time. I start from the sum of The DFT (13.2), where is the walking vector: each sample is multiplied by a probe that turns by per step, and the products are added. Now run that sum as a loop. Start from and, for each new sample, write
This is a loop of the kind in Difference equations (6.1): each output comes from the last one. The factor is an arrow of length 1 (Complex exponentials, 3.4), so each step spins the running total by and does not make it bigger or smaller. Then the new sample is added.
After samples the loop holds
Because , the factor equals , so . The loop gives turned by a fixed angle: , and .
Why does it ring at one frequency? If the input matches the loop’s frequency, each new sample lands in step with the spinning total, and the total grows steadily. If not, the additions drift in and out of step, and the total stays small. It is pushing a child on a swing: in time with the swing, the swing climbs; out of time, your pushes cancel.
The picture at the top of the page runs two such loops on a 770 Hz tone, one tuned to bin 20 (780.5 Hz) and one to bin 18 (702.4 Hz). Both start with the first sample, at size 1. Step or pause on the halfway frame, : the loop tuned near 770 Hz has grown to 49.93, and the other is at 7.54 and going nowhere. After 205 samples they are 91.18 and 13.65. These are and , the same as the FFT gives.
A tone that sits exactly on a bin gives the largest possible answer. Unit-amplitude cosine on bin 20 gives . The 770 Hz tone is between bins 18 and 20, so the loop at 20 reaches 91.18, and the loop at 18 reaches only 13.65.
The real form and the cost
The complex loop needs a complex multiply per sample, which is 4 real multiplies (Complex numbers for signals, 3.3). A rearrangement avoids that. Use two delays and a real coefficient:
That is one real multiply per sample. This is Goertzel’s algorithm. After the last sample, two numbers are enough:
When you need only the size, no complex arithmetic remains:
For the 770 Hz tone and the coefficient is , and the loop ends with and . Then , which is what the FFT gives.
A loop like this, which keeps ringing at one frequency, is a resonator. Resonators, notches and combs (17.4) designs them properly, and Transfer functions, poles and zeros (16.3) explains why it rings. I leave the poles until then.
Now the cost. Eight bins on 205 samples take real multiplies, plus a few at the end of each bin. A 256-point FFT has complex multiplies (The FFT, 14.1), which is real multiplies. Its bins also sit at multiples of 31.25 Hz, not where the keypad tones are.
Per bin, Goertzel costs real multiplies and the FFT costs in total. So Goertzel wins when you want fewer than about bins: 16 of them for .
The maths behind it · inner products
One Goertzel loop computes one row of the DFT matrix times : an inner product with a probe, done by a recursion instead of a stored row.
Which key was pressed
Each key sends one row tone (697, 770, 852 or 941 Hz) and one column tone (1209, 1336, 1477 or 1633 Hz). This is the DTMF scheme of ITU-T Recommendations Q.23 and Q.24. With kHz and , which is 25.6 ms of sound, the bins are Hz apart. Rounding gives bins 18, 20, 22, 24, 31, 34, 38 and 42, at 702.4, 780.5, 858.5, 936.6, 1209.8, 1326.8, 1482.9 and 1639.0 Hz. Each is within 11 Hz of its tone.
Use eight loops, one per tone. The strongest row loop and the strongest column loop name the key. It is how a voicemail menu hears “press 1”. The next picture dials four keys by itself. Watch the bars: exactly two stand out each time, one in each group.
Which key was pressed
Eight Goertzel loops, N = 205 at 8 kHz, one per DTMF tone.
Key 1 sends 697 Hz and 1209 Hz.
Describe this picture
Two panels: eight Goertzel loops, at 8 kHz, one per DTMF tone. The top panel is a telephone keypad of four rows and four columns, with the rows labelled 697, 770, 852 and 941 Hz and the columns 1209, 1336, 1477 and 1633 Hz. The dialled key is outlined and the decoded key is filled, so the two states differ without colour. The bottom panel has eight bars of , one per loop, labelled with its tone in Hz, in a group of rows and a group of columns. The strongest bar of each group gets a ring on top and a thick outline. The readouts are the key sent and the key decoded, which shows “listening…” while the bars grow and then the form “770 + 1336 Hz → 5”.
The clip dials 1, 5, 9 and 0, and the caption names the two loops that stand out for each key. For key 5 they are 45.9 and 46.9, and every other loop stays below 7. The last caption reads “Dialled 1, 5, 9, 0. Each key needed 8 loops × 205 samples: 1640 multiplies, 25.6 ms of sound.” Once the clip has finished, pressing a key, or typing it (0 to 9, *, #, A to D), regrows the bars for that key. “Hear the key” plays the two tones for 0.2 s.
Key 1 sends 697 Hz and 1209 Hz, and those two loops stand out. For key 5, 770 and 1336 Hz stand out at 45.9 and 46.9, and every other loop stays below 7. Each key needs 8 loops × 205 samples: 1640 multiplies, for 25.6 ms of sound.
Then it is yours. Press a key, or type it, and the bars regrow for that key. Try key 0: its bars are about 51.6 at 941 Hz and 46.4 at 1336 Hz, and the other six stay below 4.
The sixteen keys are told apart because every pair of tones sits on its own pair of bins. The bars of the other six loops are small but not zero, because a tone between bins leaks a little into the rest. I come back to leakage in Windowing and spectral leakage (15.1).
The maths behind it · detection tests
Deciding “is this tone present?” by comparing to a threshold is a detection test. Noise sets the false-alarm rate; 25.x returns to this.
Zoom into a band
Now the opposite need. The DFT samples the spectrum at evenly spaced points (Sampling the spectrum, 13.1). Suppose you want to see the curve finely between 1000 and 1080 Hz. You could zero-pad to 8192 points (Zero-padding and resolution, 15.3), which computes 8192 bins to use 81.
Instead, compute only the points you want. Choose a lowest frequency , a highest frequency , a step and a number of points . Evaluate the spectrum at
Each point is a DFT-like sum with in it. More FFT algorithms (14.2) showed that Bluestein’s chirp trick turns sums of this form into one convolution, which an FFT computes. The same trick handles all the zoom points at once. The next picture zooms into 80 Hz around a 1037 Hz tone. Watch the peak readout move from the nearest FFT bin to the tone.
Zoom into a band
A 1037 Hz tone, 256 samples at 8 kHz. FFT bins every 31.25 Hz.
Describe this picture
One panel for a 1037 Hz tone, 256 samples at 8 kHz, with FFT bins every 31.25 Hz: against frequency from 900 to 1180 Hz. The FFT bins are stems with filled dots. A shaded stretch is the zoom band, and a solid line through 81 points, 1 Hz apart, crosses it, with a small open square every 10 Hz. A ring marks the highest FFT bin and a diamond marks the zoom’s peak. The readouts are where the peak is and the grid spacing.
The clip plays by itself. First the stems rise, and the caption says the tone is somewhere between the bins. The peak readout shows ”–” until the ring lands on bin 33, then 1031.25 Hz with a spacing of 31.25 Hz. The band shades in from 1000 to 1080 Hz and the line draws across it; when the diamond appears the readouts change to 1037.00 Hz and 1.00 Hz. The last caption reads “81 points, 1 Hz apart, from 1000 to 1080 Hz: the peak is at 1037 Hz. Same curve, finer grid; it cannot split two tones closer than about 31 Hz.” Once the clip has finished, dragging the band sideways, the arrow keys (steps of 5 Hz), Home or End move it, 80 Hz wide, with from 900 to 1100 Hz, and the caption gives the highest point in the band.
The FFT’s nearest bin is 33, at 1031.25 Hz: the tone is somewhere between the bins. The zoom’s 81 points, 1 Hz apart from 1000 to 1080 Hz, put the peak at 1037 Hz.
Compare the two peak readouts. The FFT’s nearest bin is 5.75 Hz from the tone at 1037 Hz, while the 1 Hz grid lands 0.06 Hz from the true top of the curve at 1037.06 Hz. The zoom did not find a new tone. Like a map app, zooming in shows the same coastline in more detail; it does not add islands. In the same way, two tones closer than about 31 Hz still blur into one hump here, because 256 samples limit what the curve can show.
Afterwards the band is yours. Drag it sideways, or use the arrow keys, and the zoom recomputes. When the band leaves out 1037 Hz, the highest point sits at an edge of the band.
The cost of one zoom with Bluestein’s trick is three FFTs of 512 points, the first power of two at least . That is 6912 complex multiplies, against 53 248 for the 8192-point zero-padded FFT.
The general version evaluates the spectrum along any spiral, not only along the circle you used here. The spiral lives in the z-plane of The z-transform (16.1), and that is why the method is called the chirp z-transform.
Worked example
Every number below was recomputed in Python and compared with numpy.fft.fft.
- DTMF bins ( kHz, , spacing 39.02 Hz): gives 18, 20, 22, 24, 31, 34, 38 and 42, at 702.4, 780.5, 858.5, 936.6, 1209.8, 1326.8, 1482.9 and 1639.0 Hz.
- Goertzel on a 770 Hz tone (amplitude 1): , and , each equal to the FFT bin. In real form for : , , , and .
- A tone exactly on bin 20 gives .
- Cost. Eight bins by Goertzel: 1640 real multiplies, plus 3 per bin at the end. A 256-point FFT: 4096 real multiplies. A direct DFT of 8 bins on real input: real multiplies.
- Zoom. A 1037 Hz tone, , kHz. FFT bins 32, 33 and 34 sit at 1000, 1031.25 and 1062.5 Hz, with of 19.16, 121.34 and 26.93. The zoom from 1000 to 1080 Hz, 81 points, peaks at 1037.0 Hz with . SciPy’s
zoom_fft(withendpoint=True) matches the direct sum to about .
Where you’ll meet this
Resonators and poles on the unit circle come in 16.3 and 17.4. Zero-padding and what resolution really means come in 15.3. Windowing, which tames the small leakage in the DTMF bars, is 15.1. Detection thresholds and false-alarm rates return in Chapter 25.
Reference card
| Quantity | Formula | Notes |
|---|---|---|
| Goertzel, complex form | ||
| Goertzel, real form | one real multiply per sample | |
| Result | ||
| Power only | no complex arithmetic | |
| DTMF | kHz, , bins 18, 20, 22, 24, 31, 34, 38, 42 | 4 row and 4 column tones |
| Zoom (chirp z) | spectrum at , | finer grid, not finer resolution |