The Goertzel Algorithm according to Kevin Banks

The low frequency output signal of the TRX has a frequency range of approximately 300 – 3000 Hz, the speech range. Many CW-signals fit within this frequency range, each with a slightly different frequency. To filter out the desired “tone frequency” CW-signal and digitize it, we apply Discrete Fourier Transform (DFT). However, this means having a good knowledge of Digital Signal Processing, a rather difficult area of ​​knowledge.
Mr. Goertzel has made it a bit easier for us and developed an algorithm for “tone detection“. The strength of the Goertzel Algorithm is that it can perform “tone detection” with much less processing power than is possible with DTF or FFT. This brings “tone-frequency” signal processing within the reach of the – System on Chip – (SoC) processors such as the Arduino, RaspberryPi and Orange family.

If you search the internet for the Goertzel Algorithm you will find many articles about it, but one, that of Kevin Banks, it’s noticeable in that. The article provides some background information about “tone detection” by Discrete Fourier Transform. Furthermore, it gives a number of simple derivations with which we perform the desired “tone detection” in order to be able to process it as digital signal.
In it he discusses two forms of Goertzel Transform that he developed, which he calls:

  • Basic Goertzel
    This form gives the real and imaginary frequency components of the desired and detected tone as a regular Discrete Fourier Transform (DFT) or FFT would do.
    If needed, the magnitude and phase of the tone can also be calculated from the real and imaginary components of a complex number “z” representing the tone.
  • Optimized Goertzel
    Digital processing with this form is even faster (and simpler) than possible with Basis Goertzel. However, it does not give you the real and imaginary components of the detected tone. It does, however, give the relative magnitude of the detected signal squared. Taking the square root of this result will give you the relative magnitude (if needed), but there is no way to obtain the phase of the signal.

As far as it is understood, Kevin Banks derived the Basic Goertzel and the Optimized Goertzel himself and applied them in various projects. A fine achievement indeed, which many radio amateurs and others gratefully use. The formulas developed by Kevin are, as we will see later, quite easy to convert into software code.

Basic Goertzel
As noted earlier, the Goertzel Algorithm is a technique in digital signal processing (DSP) for the efficient evaluation of the individual terms of the Discrete Fourier Transform (DFT). For this purpose, a defined sample is taken from the frequency spectrum in which the desired tone is present. An intermediate calculation is performed in each sample. The actual tone detection then takes place in every N-th sample. (see the article by Kevin Banks).

As with the DFT, you work with sample blocks. However, this does not mean that you have to process the data in blocks. The processing speed of an SoC is large enough to perform calculations in the time of the interrupt service routine (ISR) of the SoC. Or, if you get buffers with samples, you can process them in batches. What exactly is meant here will become clear later in the practical implementation.

Before you can start tone detection with the Goertzel Algorithm, a number of ‘preliminary’ calculations must be done, namely:
1. Determine the sampling rate.
2. Choose the block size, N. (The total number of samples in a block)
3. Calculate one cosine and one sine term in advance.
4. Calculate one coefficient in advance.

These calculations can all be performed once and stored in RAM or ROM space of the SoC. Of course, they can also be calculated on-the-fly, at least with a sufficiently fast SoC.

Sampling Rate
The sampling frequency is determined depending on the desired application.
For the sampling rate, the usual Nyquist rules apply. This means that the sampling frequency must be at least twice as high as the highest desired (tone) frequency. At least, because an even higher sampling rate may give even better results. In any case, the desired (tone) frequency must be an integer of the sampling rate.

Block size
The Goertzel block size N is like the number of points in an equivalent FFT. It controls the frequency resolution, henceforth called the “bin width”.
For example, if the sample rate is 8928 Hz (so about three times the lf output frequency of the TRX!!) and N = 48 samples, then the bandwidth “bin” is 8928/48 = 186 Hz.
It is not clear from the article or from other information what exactly is meant by bandwidth. It may be assumed that the flanks of the passband are not infinitely good and that there is a certain damping, for example the often used -3 dB or -6 dB points

To filter the desired CW-signal from the sampling frequency with the many nearby CW-signals, it is tempting to make N as large as possible in order to obtain the highest frequency resolution, i.e. the smaller the “bin”, the larger the selectiveness.
The problem is, the higher N gets, the longer it takes to detect each desired tone. It simply takes longer because we have to wait until all samples have arrived. For example, at a sampling rate of 8 kHz, it takes 100 ms to collect all 80 samples.
A “large” N will therefore affect the detection of “fast” CW-signals. It affects the upper limit of the signal speed that can still be detected.

The next factor that influences the choice of N is the relationship between the sampling rate and the desired CW-tone, the target frequency. Ideally, the CW-tone should be centered in the bin. In other words, it is desirable that the CW tone be integer multiples of sample_rate/N.
For example, if the sampling rate is 8928 Hz and the block size N = 12 then the “selected” CW tone 8928/12 = 744 Hz will fall in the middle of the “bin”.

Precomputed constants
Once the sampling rate and block size have been determined, the previously indicated necessary constants required during processing can be calculated in five simple steps:

Step 1 Precompute one cosine and one sine term

K factor            k = (int){0.5+(N*target_freq/sample_rate)}

This includes:
–   k    = constant
–   int = integer
–   N  = block size
–   target frequency = gewenste toon
–   sample rate = bemonsteringsfrequentie

W f`actor      w = (2 * π/N) * k

Step 2 Precompute one coefficient

Step 3 Precompute three variables
For the per-sample processing you’re going to need three variables. Let’s call them Q0, Q1, and Q2.
Q1 is just the value of Q0 last time. Q2 is just the value of Q0 two times ago (or Q1 last time).
Q1 and Q2 must be initialized to zero at the beginning of each block of samples.
For every per-sample, you need to run the following three equations:

–      Q0 = coeff * Q1 – Q2 + sample
–      Q2 = Q1
–      Q1 = Q0

After running the per-sample equations N times, it’s time to see if the tone is present or not.

When the toon is there you will find a real, imagninair and magnitude from the present tone.
As mentioned before, this is much more than what you need for tone detection in a CW-decoder. That is why Kevin Banks derived an Optimized Goertzel Algorithm. An algorithm that only gives the magnitude, which is sufficient for a CW-decoder.

Optimized Goertzel Algorithm
To recognize a predetermined tone in an LF audio spectrum and process it digitally, it is not necessary to know the real and imaginary components of that tone. It is sufficient to determine the magnitude of the tone. With the difference in magnitude of the different tones, the desired and the predetermined tone can be extracted relatively easily. This is very useful for us in determining the desired CW tone. After all, we are not interested in the tone itself, but in the CW pattern that is represented by the tone. This makes processing in a SoC much easier!!!

The magnitude of the desired frequency is determined by:

As you see only the pre-computed Q1, Q2 en coeff are nessecary voor calculating the magnitude squared.

The above calculations and their results were included by Hjalmar Skovholm Hansen OZ1JHM in a simple CW-decoder software program for the Arduino Uno that he wrote.