Goertzel Algorithm: A Practical and Thorough Guide to Efficient Frequency Detection

The Goertzel Algorithm stands as one of the most efficient tools in digital signal processing for detecting specific frequency components within a signal. In many real-world applications, such as tone detection in telecommunication and feature spotting in audio streams, it delivers accurate results with significantly lower computational load than a full discrete Fourier transform (DFT). This guide explains what the Goertzel Algorithm is, how it works, and how to implement it effectively in modern systems while exploring its strengths, limitations and practical use cases.
Introduction to the Goertzel algorithm
What problem does the Goertzel algorithm solve?
The Goertzel Algorithm focuses on extracting the magnitude (and sometimes the phase) of a single frequency bin from a sequence of samples. Rather than computing the entire spectrum, it processes a window of data to determine how much energy resides at a specific target frequency. This makes the Goertzel algorithm exceptionally efficient when only a handful of frequencies are of interest, such as in dual-tone or multi-tone detection schemes, audio monitoring, or embedded sensing tasks where resources are limited.
Why choose the Goertzel algorithm over a full FFT?
In situations where you need information about just one or a few frequencies, the Goertzel algorithm offers a lower computational cost than an FFT. The FFT requires N log N operations to obtain all N frequency bins, while the Goertzel algorithm computes each targeted bin in O(N) time. This linear scaling with window length means substantial savings for systems that repeatedly monitor a small set of frequencies, especially in real-time or low-power environments.
Mathematical foundations of the Goertzel algorithm
From DFT to the Goertzel recurrence
Consider a real-valued input sequence x[n] of length N. The goal is to determine the DFT coefficient X[k] corresponding to a target index k, given by
X[k] = sum_{n=0}^{N-1} x[n] e^{-j 2π kn / N}.
The Goertzel algorithm derives a second-order linear recurrence that efficiently accumulates the necessary information for a single bin. Defining ω = 2πk / N, and initializing two state variables s[0] = 0 and s[1] = 0, the following recurrence is used for n from 0 to N-1:
s <- x[n] + 2 cos(ω) * s_prev – s_prev2
Where s_prev and s_prev2 hold the two previous states. After processing all samples, the real and imaginary parts of X[k] are obtained from:
Real(X[k]) = s_prev – cos(ω) * s_prev2
Imag(X[k]) = sin(ω) * s_prev2
From these, the magnitude |X[k]| can be computed as sqrt( Real^2 + Imag^2 ). Different implementations may store the intermediate states slightly differently, but the core recurrence and the final combination into a real and imaginary part remain consistent with this description.
The recurrence equations explained
In practice, many implementations use a compact form that updates two state variables, often denoted as s and p, in a loop. A typical version is:
Let ω = 2πk / N, and let coeff = 2 cos(ω).
Initialize: s_prev2 = 0, s_prev = 0
For each sample x[n]:
s <- x[n] + coeff * s_prev – s_prev2
s_prev2 <- s_prev
s_prev <- s
After processing all N samples: Real = s_prev – cos(ω) * s_prev2; Imag = sin(ω) * s_prev2. The magnitude is sqrt( Real^2 + Imag^2 ).
Although this description uses a particular naming convention, the underlying principle is the same: a tight, reusable recurrence that avoids computing the full spectrum and concentrates on the energy at a chosen frequency.
Practical applications of the Goertzel algorithm
DTMF detection with the Goertzel algorithm
Dual-tone multi-frequency (DTMF) signalling in telephony relies on recognising pairs of tones from a fixed set of frequencies. The Goertzel algorithm is a natural fit for DTMF decoders because each tone corresponds to a specific bin. By running the Goertzel detector for a small set of frequencies in parallel, a robust and fast decoder emerges that can operate in real time on modest hardware.
Audio analysis and spectrum monitoring
Beyond telephony, the Goertzel algorithm serves well in applications where particular harmonics or musical notes need to be tracked in real time. For instance, in musical instrument tuning, a handful of harmonic bins can be monitored to determine pitch with high accuracy while keeping computational load low.
Wireless sensing and embedded systems
In embedded systems and IoT devices, the Goertzel algorithm enables frequency-specific sensing with minimal power consumption. For RF front-ends or low-power microphones, tracking a few precise frequencies is often more important than obtaining a full spectrum, and the Goertzel approach aligns with those constraints.
Implementing the Goertzel algorithm in practice
Numerical considerations and scaling
Key design choices influence the accuracy and stability of Goertzel detectors. The window length N, the target frequency bin k, and the sampling rate Fs determine ω and the recurrence coefficient. Finite-precision arithmetic means careful handling of scaling and potential accumulation of rounding errors. In practice, fixed-point arithmetic is common in embedded contexts, with careful scaling to preserve dynamic range and precision.
Sample implementations
C implementation
// Goertzel algorithm for a single bin
#include <math.h>
double goertzel_bin(const double *x, int N, int k, double Fs) {
double omega = 2.0 * M_PI * k / N; // bin frequency index
double coeff = 2.0 * cos(omega);
double s_prev = 0.0;
double s_prev2 = 0.0;
for (int n = 0; n < N; ++n) {
double s = x[n] + coeff * s_prev - s_prev2;
s_prev2 = s_prev;
s_prev = s;
}
double real = s_prev - cos(omega) * s_prev2;
double imag = sin(omega) * s_prev2;
return sqrt(real*real + imag*imag);
}
Python implementation
import math
def goertzel(samples, target_freq, Fs):
N = len(samples)
# Determine the appropriate bin index
k = int(round((N * target_freq) / Fs))
omega = 2.0 * math.pi * k / N
coeff = 2.0 * math.cos(omega)
s_prev = 0.0
s_prev2 = 0.0
for x in samples:
s = x + coeff * s_prev - s_prev2
s_prev2 = s_prev
s_prev = s
real = s_prev - math.cos(omega) * s_prev2
imag = math.sin(omega) * s_prev2
return math.hypot(real, imag)
MATLAB/Octave style
function mag = goertzel_mag(x, k, N)
omega = 2 * pi * k / N;
coeff = 2 * cos(omega);
s_prev = 0;
s_prev2 = 0;
for n = 1:N
s = x(n) + coeff * s_prev - s_prev2;
s_prev2 = s_prev;
s_prev = s;
end
real = s_prev - cos(omega) * s_prev2;
imag = sin(omega) * s_prev2;
mag = sqrt(real^2 + imag^2);
end
Arduino/embedded pseudocode
// Simplified Goertzel for a single frequency on an Arduino
float goertzel(const float *samples, int N, float targetFreq, float Fs) {
float k = (N * targetFreq) / Fs;
float omega = 2.0f * PI * k / N;
float coeff = 2.0f * cos(omega);
float s_prev = 0.0f;
float s_prev2 = 0.0f;
for (int n = 0; n < N; ++n) {
float s = samples[n] + coeff * s_prev - s_prev2;
s_prev2 = s_prev;
s_prev = s;
}
float real = s_prev - cos(omega) * s_prev2;
float imag = sin(omega) * s_prev2;
return sqrt(real*real + imag*imag);
}
Real-time processing and streaming data
In streaming scenarios, a sliding window approach is employed. You continuously collect N samples, compute the Goertzel output for the target bin(s), and then slide the window forward by a new sample. Doing this efficiently often involves circular buffers and careful memory management. When monitoring multiple frequencies in parallel, a small set of Goertzel detectors can run concurrently, each maintaining its own state across windows.
Optimisations, pitfalls and benchmarking
Choosing N and k
The window length N determines frequency resolution and latency. Larger N gives finer frequency resolution but increases detection latency and computational load. For standard DTMF tones, a window of 205 or 205 samples at 8 kHz sampling rate is common, providing robust detection while keeping latency manageable. The bin index k should align with the target frequencies; misalignment reduces detection accuracy and can introduce leakage, which may be mitigated with windowing strategies or by selecting bins that best match the actual tones.
Precision issues and rounding
Low-cost processors use fixed-point arithmetic; here, proper scaling and careful use of fixed-point libraries are essential. Floating-point devices offer greater simplicity and precision, but power and speed trade-offs may apply. It’s important to avoid overflow in intermediate calculations and ensure intermediate results stay within the dynamic range of the chosen numeric type.
Robustness against noise
Noise can degrade the Goertzel output, particularly when the target tone is weak or closely spaced to other energy. Techniques such as windowing, averaging multiple windows, or combining results from adjacent bins can improve robustness. In some schemes, normalising the result against a baseline noise floor helps maintain stable decision thresholds in fluctuating environments.
Goertzel algorithm vs FFT: a pragmatic comparison
When to use the Goertzel algorithm
The Goertzel algorithm is ideal when you need one or a few specific frequencies with low latency and modest computational resources. It shines in embedded systems, telecommunication decoders, and applications where the full spectrum is unnecessary.
Limitations to be aware of
If you require a broad spectrum or the ability to adapt quickly to many frequencies, an FFT or other spectral estimation method may be more appropriate. The Goertzel algorithm is not a universal replacement for spectral analysis; it complements broad-spectrum techniques by providing a focused, efficient solution for target frequencies.
Extending the Goertzel algorithm for multiple frequencies
Parallelising across multiple bins
For several frequencies, you can implement a separate Goertzel detector per bin, updating their states in parallel within the same sample processing loop. This approach scales well as the number of target frequencies remains small. In hardware implementations, dedicated resources can run each detector in parallel, achieving very low latency per bin.
Efficient ways to reuse computations
When bins are closely spaced, some parts of the recurrence can be shared or reused, reducing redundant calculations. Some optimisations involve recomputing only the last stage with updated ω values or exploiting symmetries in the cosine calculations. Careful profiling will reveal the most effective strategy for a given hardware profile.
Future directions and expert tips
Goertzel algorithm in low-power devices
As devices become more capable yet power-conscious, the Goertzel algorithm remains a cornerstone for energy-efficient real-time detection. Techniques such as duty cycling, fixed-point arithmetic with aggressive scaling, and selective bin maintenance can extend battery life while preserving accuracy for targeted tones and commands.
Interface design for Goertzel-based systems
Clear interfaces for input data, window framing, bin selection, and decision thresholds are essential. Consider exposing parameters like window length N, target frequencies, and tolerance bands as configurable settings, enabling easier optimisation across different deployment scenarios.
Case studies and practical outcomes
Across industries—from telephony to consumer electronics—the Goertzel algorithm has proven its worth in speeding up detection pipelines, reducing hardware complexity, and delivering deterministic, low-latency results. Real-world deployments showcase the algorithm’s adaptability: a compact footprint for embedded controllers, accurate tone detection in noisy environments, and straightforward integration into existing DSP chains.
Common pitfalls and how to avoid them
Leakage and spectral leakage
When the target tone does not align exactly with a DFT bin, energy spreads into adjacent frequencies. Mitigation strategies include selecting a window that reduces leakage (e.g., Hann or Hamming-like windows for Goertzel analyses) or adjusting the target bin index to better match the actual tone frequency.
Incorrect frequency mapping
Miscomputing the ω value or bin index k leads to systematic errors. Always verify the relationship between sampling rate, window length, and the target frequency. A small unit test comparing known tones against Goertzel outputs helps catch misconfigurations early.
Resource budgeting for multiple detectors
Running several Goertzel detectors in parallel increases memory and CPU usage linearly with the number of bins. When resource-constrained, prioritise the most critical frequencies and consider shared memory structures or time-sliced updates to keep latency predictable.
Conclusion
The Goertzel algorithm remains a thoroughly practical and efficient method for detecting specific frequencies within a signal. Its elegance lies in a compact recurrence that processes data in linear time relative to the window length, enabling fast, resource-light implementations suitable for embedded systems, telecommunication devices and audio processing pipelines. By understanding its mathematical foundations, implementing carefully in software, and choosing the right configurations for your use case, you can leverage the Goertzel algorithm to deliver accurate tone detection, robust real-time responses, and scalable performance across diverse environments.