1

I need to find the frequency and amplitude of a signal. My signal is this (Number of Samples= 9500 taken at 500Hz):

![enter image description here

I tried the following code for FFT (found here):

Fs=500;
L=numel(pitch);
Y=fft(pitch);
f = Fs*(0:(L/2))/L;
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
figure
plot(f,P1)

The result I get is this (amplitude=7.501): enter image description here

But this is not accurate. If I calculate the amplitude from the peaks, amplitude=9.3, which looks correct.

Why does the FFT give a inaccurate result and how can I find the correct result (frequency + amplitude) by using FFT or any other method? I have several signals which are in general noisy, so finding peaks is not possible.

  • 3
    Some of the power of the signal is spread out. See the FFT bins close to your peak, which are not zero. If you use a windowing function you’ll get a better result. – Cris Luengo Oct 05 '20 at 13:29
  • Thanks for the answer. How can I do this properly? – Alexandros Mel Oct 06 '20 at 07:28
  • Also, here's a very good summary of the why and how of windowing functions: https://stackoverflow.com/q/7337709/7328782 – Cris Luengo Oct 21 '20 at 14:36
  • Windowing the signal makes the result worse, it gives an even lower amplitude. – Alexandros Mel Oct 21 '20 at 15:20
  • Instead of `P2 = abs(Y/L)` you need to normalize by the integral (sum) of the windowing function. `L` there is basically the sum of the square windowing function implicitly used when sampling for a limited time. – Cris Luengo Oct 21 '20 at 15:34
  • The key to look for is a smaller spread of the peak into adjacent bins. Note that the value you're after is the integral over that whole peak, not the peak's value. Because of spectral leak, the impulse at your given frequency is spread out over many frequency bins, so taking these all together should match the amplitude of the original impulse function. – Cris Luengo Oct 21 '20 at 15:37
  • Some signal energy is indeed spread into other bins, as @CrisLuengo mentions above. But that's not really the core of the problem here. The energy in bins away from the main lobe is typically small. The problem for amplitude accuracy is when the signal frequency doesn't line up exactly with an FFT bin. The amplitude of the nearest FFT bin will be affected by the frequency-domain shape of the window. The typical solution is to use a flat-top window. Or, if you know the signal frequency ahead of time, you can use the Goertzel algorithm instead of an FFT. – Eric Backus Oct 22 '20 at 16:39
  • Thank you for the answers! @Eric I need to find both the frequency and the amplitude. The signal represents a movement, which I need to define. But the frequency can be easily obtained eg by normal DFT and then apply maybe the Goertzel algorithm. If I use the flat-top window (flattopwin() in Matlab), should I then normalize be 1/(a0*(L-1)) right? How can I solve the issue that according to the samples of the signal, I have different result in amp - also by using the topflatwin(). Eg when I give 3000 samples to DFT I got a result and when I give 5000 a slightly but noticeable different – Alexandros Mel Oct 23 '20 at 09:32
  • When using a flat-top window (or any window really) you do need to normalize to get the correct amplitude. Whether that normalization uses `L-1` or just `L` depends on the window definition. In most cases, you normalize using a0, but in the case of a flat-top window that is not always optimal. In any case, even a flat-top window is not totally flat (there are different flat-top windows with different flatness), so there will be some small variation even when using it. If you know that the input is a pure tone, there are also window-specific techniques for improving/correcting your result. – Eric Backus Oct 23 '20 at 18:30
  • In general I don't have a pure tone, but what I want is to find the dominant frequency + amplitude from that signal, so only one frequency. Maybe this window-specific techniques give a better result. Could you suggest any? Also, how can I solve the problem of the sampling data number -eg I get result when I give 3000 data to DFT/Goertzel and a different one when I give 5000. – Alexandros Mel Oct 26 '20 at 11:20
  • @EricBackus Any idea how can I solve the problem why I get different result according to the number of the samples? Is it normal? – Alexandros Mel Nov 06 '20 at 14:18
  • For your problem, you need to either 1) use a flat-top window, or 2) do some post-processing to correct for window non-flatness between bins. Using a flat-top window is simpler, though not quite as accurate, but usually good enough. Then your final accuracy is limited by the combination of the flatness of the flat-top window and the noise level of the signal. Using different number of samples doesn't change the flatness of the flat-top window, but larger number of samples may help reduce the effects of noise. – Eric Backus Nov 06 '20 at 22:32
  • You can't expect identical answers when the number of samples is different, but you should expect them to be fairly close. If they're not, you probably have some other problem. Perhaps not normalizing correctly, or perhaps some of your samples are zero. – Eric Backus Nov 06 '20 at 22:34
  • @EricBackus Thanks a lot! I add zeros when I use the FFT in order to make the number of samples power of 2. When using the flat top window (https://nl.mathworks.com/help/signal/ref/flattopwin.html) the normalization is 1/(a0*(L-1)) right? – Alexandros Mel Nov 10 '20 at 08:24
  • OK. I like to think of the normalization as having several parts. I think you should: 1) window before adding zeros, 2) normalize for the window using 1/(a0), 3) normalize for the zero padding by using N/L, where L is the window length and N is the FFT input length, and 4) normalize for the FFT using 1/N, where N is the number of samples going into the FFT. The net normalization is then 1/(a0*L). Also, when calling flattopwin, set the second parameter to `'periodic'`. – Eric Backus Nov 10 '20 at 17:27

0 Answers0