DSPRelated.com
Forums

Bandwidth of the Goertzel algorithm

Started by Cuencano 3 weeks ago18 replieslatest reply 2 weeks ago179 views

I needed to determine the 3 and 6 dB points of the Goertzel algorithm.

While I found many posts here that addressed bandwidth indirectly, they didn’t specifically answer the question. So I will post the answer here.

The normalized gain of the Goertzel function is X(f) = Sa(k) or Sin(k)/k.

For a Goertzel with N points and a sample frequency of Fs and an analysis frequency of Fa, then: 

X(f) = Sin((f - Fa) * N * pi / Fs) / ((f - Fa) * N * pi / Fs).

The problem is to solve 1/2 = Sa(k), for the 6 dB case and 1/2 = Sa(j)*Sa(j). The second case can be reduced to 1/Sqrt(2) = Sa(j).

Iterative methods provide the solutions, k = 1.391557 and j = 1.89549. The 3 dB bandwidth is:

BW = 2 * k * Fs / (N * pi), and the 6 dB bandwidth is BW = 2 * j * FS / (N * pi).

Andy 

[ - ]
Reply by SlartibartfastMay 23, 2025

The Goertzel algorithm is an implementation of a DFT bin computation, kind of akin to a sliding DFT, so the frequency response should be the same as it would be for a DFT bin, in other words, a sinx/x.   The 3dB and 6dB points of the sinx/x are easily computed using N and fs.  

[ - ]
Reply by CuencanoMay 23, 2025

I think that the half power point (3 dB) and the half amplitude point (6 db) are respectively the solution of 1/sqrt(2) = sinx/x and 1/2 = sinx/x is that not correct? If so I think the coefficients proposed need to be used. 

[ - ]
Reply by SlartibartfastMay 24, 2025

That sounds right.   For a rectangular-windowed DFT the 3dB points of the sinx/x response of the transform are at the bin boundaries, i.e., each sinx/x touches the adjacent bin sinx/x at the 3dB point.   The unwindowed DFT magnitude of a swept sine then has a 3dB scalloping effect due to this.

So the 3dB point of the Goertzel algorithm for a particular fs and N will be at 1/2 the effective DFT bin width from the center frequency on each side.

This is pretty straightforward to sim or verify in a tool like octave or mathcad or something to help visualization if need be.


[ - ]
Reply by CuencanoMay 24, 2025

I did a rough simulation of this earlier but with a discrete frequency resolution. I'll give it another go with a swept sine. Thanks!

[ - ]
Reply by CuencanoMay 25, 2025

I ran a simulation at a couple of frequency resolutions to check. Here are the results..

g1_38421.png

g2_43027.png

The formula for the 3 dB bandwidth gives 79.6 Hz and the measured bandwidth is 78.5 Hz. The 6 dB bandwidth with is 108.3 and the measured data is 108.5 Hz


[ - ]
Reply by SlartibartfastMay 26, 2025

Nicely done.    That looks like a decently thorough analysis of your implementation.


[ - ]
Reply by kazMay 27, 2025

I am a bit lost in the underlying concept in this thread.

Are you computing the spread (leakage) of frequency in adjacent bins?

Your -3dB formula for your example is:

bw = 2*1.391557*15625/(174*pi) = 79.6 Hz

if N is > 174 then bw decreases

iF N is < 174 then bw increases

Does that make sense? 

I assume leakage is dependant on error between bin frequency and 2245 Hz

as well as any windowing applied.

[ - ]
Reply by SlartibartfastMay 27, 2025

The Fourier transform of a rectangle is a sinx/x.   So a rectangular-windowed DFT (e.g., unwindowed DFT), has a sinx/x frequency response.   The nulls of the bin reponse sinx/x fall exactly on the centers of adjacent bins which is how the bins maintain orthogonality to each other.

Since the Goertzel algorithm only computes one bin of a DFT, the sinx/x response can be analyzed as the frequency response of the algorithm as a filter.   The response is the same regardless of whether it is computed with a DFT, a sliding DFT, a Goertzel algorithm, or any other equivalent computation.

For a DFT, the frequency response of an input with a non-integer number of cycles across the length-N aperture of the DFT input will still have a sinx/x response, but it will no longer be centered on a bin.   The adjacent bins will also no longer be aligned with the nulls between sidelobes and some sidelobe energy will be present in adjacent bins.  That sidelobe energy that appears in adjacent bins for non-integer frequency inputs is the "leakage", since it appears in bins other than the one more closely representing the actual frequency of the input.

[ - ]
Reply by kazMay 27, 2025

The topic implies there is something special about Goertzel as compared to DFT. I disagree, it is just a convenient implementation of DFT. I guess it is low quality DFT.

I have experimented with DFT of a single tone as follows:

- varying DFT resolution i.e. same tone length plus zeros

- increasing length of tone and hence DFT length. No zeros added.

In either case I cannot see a clear pattern as that of the equations posted above. I hope I am wrong.


[ - ]
Reply by CuencanoMay 27, 2025

Sorry about the confusion. Assume that the input signal is a 1 volt rms sinewave swept between two frequencies with the analysis frequency of the Goertzel in the middle. The amplitude of the output of the filter is plotted on the y axis and the input frequency on the x. A transfer function in effect. Like a conventional FFT the frequency selectivity improves with the number of bins processed say 256 vs 512 with a normal spectrum analyzer.

[ - ]
Reply by kazMay 28, 2025

Thanks for explaining your test idea.

I have this Octave code below to show my understanding:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear; clc;

fo = 2245; fs = 15625; N = 174;

freq_axis = fs*(0:1/N:1-1/N);

d = -50:10:50;    %for sweep range

for i = 1:length(d)

  f(i,:) = exp(j*2*pi*(0:N-1)*(fo+d(i))/fs);

end

plot(freq_axis, 20*log10(abs(fft(f.')/N)),'.-');

ylim([-60,0]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[ - ]
Reply by CuencanoMay 28, 2025

Thanks for your code sample. Unfortunately I am a novice with Octave. I ran your code but I don't quite understand it. Could you give me a brief explaniation please? 

[ - ]
Reply by kazMay 28, 2025

Generate complex tone, 2245 Hz @ 15625 (174 samples from zero phase): 

f = exp(j*2*pi*(0:173)*2245/15625);

For sweeping frequency you vary 2245 +/- by adding (d) variable set as you like.

f(i,:) is 2D variable holding tones, each tone stream indexed by (i) of the loop.

fft can work across each column in one call. I plotted amplitude in dB after scaling down fft output by 174.

20*log10(abs(fft(f.')/N))

The term (f.') transposes rows to columns. I could have started as f(:,i) in the loop then I don't need transposing.

The plot function decides colours per each column.

I see you got your model so you may not need coding but it might be convenient sometimes.

[ - ]
Reply by CuencanoMay 28, 2025

Thanks Kaz,

I think I see where you are going with the Octave stuff. I will play with it. It sure gets a lot done in a few lines of code! Octave looks like a great tool. Thanks for the lesson.

[ - ]
Reply by CuencanoMay 31, 2025

Kaz,

Thanks again for turning me on to Octave. I re-worked my program in Octave using the fft function an compared it to the Sa function and, guess what, the fft is identical to the Goertzel, as expected. Here is a copy of my code for your reference...

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear; clc;

fo = 2245;               % analysis frequency

fs = 15625;              % sample frequency

N = 174;                 % the number of points in the FFT

A=2;                     % peak amplitude of the sine wave

f1=1045;                 % the lower sweep frequency

f2= 3445;                % the upper sweep frequency limit

num_pts= 240;            % the number of frequency points per sweep

fo_bin = round(N*fo/fs)+1;  % the bin number of the analysis frequency

freq_axis=f1:(f2-f1)/num_pts:f2;

d = f1:(f2-f1)/num_pts:f2;

for i = 1:length(d)

  f(i,:) = A*sin(2*pi*(0:N-1)*d(i)/fs);

  k = (freq_axis(i)-fo) * N * pi / fs;

  if (k == 0)

    Sa(i) = 0;

  else

    Sa(i) = 20*log10(abs(sin(k)/k));

  endif

end

r = 20*log10(abs(fft(f.')/N));

data = r(fo_bin,:);

plot(freq_axis, data,"k", freq_axis, Sa, "m");

title("Bandwidth Comparison of Sa and FFT Functions");

xlabel("Frequency (Hz)");

ylabel("dB Amplitude");

grid;

legend ("FFT", "Sa");

ylim([-40,0]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[ - ]
Reply by kazMay 31, 2025

Great, you have beaten my quarter century experience in few hours.

Octave is GNU tool emulating Matlab within legal constraints.

Some functions are not available or may slightly mismatch with Matlab due to trade secrets.

If you want Matlab you can sign up and use their online free version.

[ - ]
Reply by LKoppMay 24, 2025

Goertzel is only a special implementation of DFT which is itself a discrete form of Fourier Transform.. 

May be it is only a tiny detail in practice but the frequency response of a finite aperture is indeed a "sinc" but if the aperture is discrete it is a "Fej" function. This may be significantly different for small number of points.

LK

[ - ]
Reply by CuencanoMay 24, 2025

Thanks for the suggestion I will investigate.