FFT - wrong frequency

Hello,
I have a problem when I try to retrieve the frequency of a signal with fft.
Here is a test I did with a simple cosine of frequency 14.5 Hz :
Lz = 0.075 ;
nZ = 501 ;
Z = linspace(0,Lz,nZ) ;
dZ = Lz/nZ ;
Y = cos(2*pi*14.5*Z) ;
df = 1/(Lz) ;
f = (0:1:nZ-1)*df;
FFT = fft(Y) ;
% figure(1)
% plot(Z,Y)
figure(2)
plot(f,abs(FFT))
My problem is that I get a peak at f=13.33 Hz instead of 14.5 Hz .
What is also really weird is that I get the same peak (13.33Hz) when I try with a frequency of 16Hz, 18Hz... but from 20Hz the peak I get is at 26.67Hz, same for 32 Hz .
I tried to get the frequency axis differently, but I always have the same result. I also tried to use the function given by Daniel kiracofe in this issue https://fr.mathworks.com/matlabcentral/answers/132021-fft-don-t-give-correct-result : http://www.mechanicalvibration.com/Making_matlab_s_fft_functio.html
but the problem is still there.
Could someone help me please?
Thank you

Answers (1)

Peng Li
Peng Li on 11 Apr 2020
Well, you need to understand what you are doing with each of these variables. Your code is kind of weird as all things you need to known are kind of hidden somewhere.
Based on your time variable Z, your sampling frequency is 1 ./ diff(Z).
>> fs = 1./diff(Z);
>> fs = fs(1)
fs =
6.6667e+03
And your signal length (FFT size by default) is nZ = 501. Your frequency resolution is thus fs / nZ = 13.3067.
With such a frequency resolution, you cannot expect to identify your target signal 14.5, 16, or 18 Hz. And when it is for 20 Hz, it jumped to the second trace 26.6, and so on.
Your signal Y also has a fraction number of cycles. So you can expect some spectral leakage around your target frequency too.

5 Comments

clpi
clpi on 11 Apr 2020
Ok thank you very much.
In the original code, I don't want to change Lz, so I have to increase the number of points used for fft.
If for instance I write FFT = fft(Y,4000), I define the frequency axis as f=linspace(0,Fs,4000), is that correct?
It gives almost the right result, but it improves when I increase Lz so that Y has more cycles (but it annoys me too, because in my original code, I don't want to change Lz).
Peng Li
Peng Li on 11 Apr 2020
Understand your point. You could do zero padding to increase the "frequency resolution". Note that this means that you can have exactly a trace at your desired frequency. However, zero padding doesn't offer the resolution to diferentiate two close frequencies, if your signal has. This differentiation ability is determined by the actual length of data 1/T. In your case, 1/Lz.
It if fine to define f this way. But better afterwards shrink your f axis to show only the first half xlim([0 Fs/2]).
You will still have spectral leakage although you zero padding your data. Better apply a window function before fft to minimize this effect. e.g., fft(Y.*hann(size(Y)), 4000).
clpi
clpi on 11 Apr 2020
I tried with the window function ( fft(Y.*hann(length(Y)), 4000), because fft(Y.*hann(size(Y)), 4000) returned me an error ), now I always have a peak at 0Hz, is that normal? Also, it has several colors
Peng Li
Peng Li on 11 Apr 2020
try fft(Y(:).*hann(length(Y)), 4000); you can compare this with your orignal one fft(Y, 4000). If you show y axis in dB, you might able to see the drop of traces around the target frequency using window fft. You only have a bit more than 1 cycle of the cos wave so the effect might be interesting as well.
clpi
clpi on 11 Apr 2020
It is a bit better indeed, thank you very much for your time.

Sign in to comment.

Tags

Asked:

on 11 Apr 2020

Commented:

on 11 Apr 2020

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!