I am trying to create a pitch-detection program which extracts the frequencies of peaks in a power spectrum obtained from an FFT (fftpack). I am extracting the peak frequencies from my spectrum using Quinn's First Estimator to interpolate between bin numbers. This scheme seems to work well under certain conditions. For example, using a rectangular window function with a window size of 1024 and a sample rate of 16000, my algorithm correctly identifies the frequency of a pure A440 tone as 440.06 with a second partial frequency of 880.1. However, under other conditions, it produces inaccurate results. If I change the sample rate (e.g to 8000) or the window size (e.g. to 2048), it still correctly identifies the first partial as 440, but the second partial is somewhere around 892. The problem becomes even worse for inharmonic tones like those produced by a guitar or piano.

My general question is: In what way do the sample rate, window size, and window function affect frequency estimation of FFT peaks? My assumption was that simply increasing the resolution of the spectrum would increase the accuracy of peak frequency estimation, but this is clearly not my experience (zero padding also does not help). I am also assuming that the choice of window function will not have much effect because spectral leakage should not change the peak location (though, now that I think about it, spectral leakage could potentially influence the interpolated frequency estimate if the magnitudes of bins adjacent to the peak are artificially increased by leakage from other peaks...).

Any thoughts?


3 Answers 3

  1. Use a Gaussian window - the Fourier transform of a Gaussian is a Gaussian
  2. Log-scale the spectrum to emphasize peaks and turn the Gaussian peaks into parabolic peaks
  3. Use parabolic interpolation to find the true peaks.

Note that, as mentioned in §D.1, the Gaussian window transform magnitude is precisely a parabola on a dB scale. As a result, quadratic spectral peak interpolation is exact under the Gaussian window. Of course, we must somehow remove the infinitely long tails of the Gaussian window in practice, but this does not cause much deviation from a parabola, as shown in Fig.3.30.


enter image description here

I estimate 1000.000004 Hz for a 1000 Hz waveform this way: https://gist.github.com/255291#file_parabolic.py

If you're having trouble, plot the spectrum and use your eyes to see why it's not working.

  • 2
    $\begingroup$ Thank you! This makes perfect sense. The log of a Gaussian is a parabola, so parabolic interpolation of the peaks in a Gaussian-windowed log spectrum is nearly exact. After implementing this, I am getting consistent FFT peak frequency estimates across different sample rates and window sizes. Huzzah! $\endgroup$
    – willpett
    Nov 9, 2011 at 1:26
  • $\begingroup$ @will.pett: So maybe the problem was caused by "Quinn's First Estimator" more than by the FFT? $\endgroup$
    – endolith
    Nov 9, 2011 at 4:35
  • $\begingroup$ I don't think the interpolation method was entirely to blame because quadratic interpolation also gave me bad results with certain window functions and sample rates. I think it was the combination of the above parameters that was important. I was not using the proper window function and had not log-transformed my spectrum. I bet the most important thing was the log-transform. Probably standard protocol that I was just unaware of. $\endgroup$
    – willpett
    Nov 9, 2011 at 5:46
  • $\begingroup$ @endolith, thanks, got it (questions may follow) $\endgroup$
    – denis
    Nov 16, 2013 at 14:51

First, peak frequency estimation and pitch estimation are two different things. Pitch is a psycho-acoustic phenomenon. People can hear a pitch even with the fundamental frequency completely missing, or relatively weak compared to most other peaks, as in the low notes produced by some instruments.

Second, using no window on an FFT is equivalent to using a rectangular window, which convolves your spectrum with the Sinc function. The Sinc function has lot of humps spread far from the peak which will show up for all frequencies that are not exactly periodic in the FFT length (also know as "spectral leakage"). All this energy leakage from one strong frequency will interfere with the position estimation of other frequency peaks. So a more suitable window function (Hamming or von Hann) might help reduce this interference between peaks.

A longer FFT will reduce the delta frequency between bin centers, which should increase interpolation and thus frequency estimation accuracy for stationary spectrums. However if the FFT is so long that the spectrum changes within the FFT window, all those changed frequencies will be blurred together in a longer FFT.


You definitely need a suitable window function - the effects of spectral leakage vary significantly depending on how the pitch period and FFT window length are related - if you get a large transient between the last and first sample of the FFT window then this will produce very nasty smearing of the spectrum, whereas if you get lucky and this discontinuity is small then the resulting spectrum will be a lot cleaner. This is probably why you are seeing inconsistencies when you change any of your parameters such as FFT size. With a suitable window function you will get a consistent spectrum as the pitch changes.

  • $\begingroup$ I have now tried different window functions (Hamming, Blackman-Harris, Gauss, Weedon-Gauss) and all of them give me wildly inaccurate results under any sample rate / window size conditions (e.g estimating the first partial frequency at 460, 488, and others). Only a rectangular window was able to correctly identify a peak at 440 Hz. Interestingly, this peak is largely invariant with different sample-rate/window-size combinations in a rectangular window, though the second partial is still variable. How do I reconcile these results with your advice? $\endgroup$
    – will.pett
    Nov 7, 2011 at 17:16
  • $\begingroup$ As a side note, I am also using an autocorrelation algorithm to compare with the FFT. This method (which is independent of the window function) gives ~440.4 Hz for the wikipedia tone, while the FFT method gives nearly exactly 440 without a window function. I realize that autocorrelation does not directly estimate the first partial frequency, but rather the psychoacoustic "pitch", but it is still interesting to compare. From experimenting with piano tones, I have noticed that the autocorrelation method consistently overestimates the first partial frequency compared with the FFT method. $\endgroup$
    – will.pett
    Nov 7, 2011 at 17:28
  • 1
    $\begingroup$ It's hard to guess what the problems might be without seeing the code etc. Have you tried plotting the power spectrum to see what the peaks actually look like with/without a window function ? This should not only tell you whether your windowing/FFT/etc is behaving correctly but also may give you some insight as to why your pitch estimation algo is giving the results that it does. $\endgroup$
    – Paul R
    Nov 7, 2011 at 20:10
  • $\begingroup$ It is weird, because the window functions do indeed produce cleaner looking spectra, with little smearing. However, the estimates of the peak frequencies are not right. When I use the settings that give me 440 Hz with no windowing, then switch to a Hamming window, I get 444.6 Hz. With a Blackman-Harris window I get 460.9 Hz, and with a Gaussian window I get 446.4 Hz. Is it possible that peak interpolation methods make implicit assumptions about the window function that I might be violating? $\endgroup$
    – willpett
    Nov 7, 2011 at 22:16
  • $\begingroup$ I'm not really familiar with the interpolation methods in the article that you link to - they seem to be using both magnitude and phase information rather than just magnitude, but I wouldn't have thought that windowing would have a significant impact on phase. $\endgroup$
    – Paul R
    Nov 7, 2011 at 22:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.