FFT spectral leak?
36 views (last 30 days)
Show older comments
I find that in the power spectrum returned by fft the amplitude of peaks are much smaller than expected, even for artifical signals. This is in contrast to the examples given in documation
openExample('matlab/FFTOfNoisySignalExample')
I wonder what can be done to improve? Increasing sampling rate seem to have very little effect.
t=linspace(0,10,1e4);
x=1*cos(7e1*t)+2*cos(3e2*t);
%should make peaks at 70 and 300 with amplitude of 1 and 2
[omega,P1]=fft1D(t,x);
plot(omega,P1)
function [omega,P1]=fft1D(t,x)
L=numel(t);
Fs=L/(max(t)-min(t));
xfft = fft(x);
P2 = abs(xfft/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
omega = Fs*(0:(L/2))/L*2*pi;
end
1 Comment
Marcel Kreuzberg
on 9 Nov 2022
in the example 'matlab/FFTOfNoisySignalExample' the intervall parameters are defined first.
if you play in your example with the line t=linspace(0,10,1e4) you will get different peak values as the fft is not the exact analytic result
Accepted Answer
Mathieu NOE
on 9 Nov 2022
hello
the amplitude accuracy depends if your signal frequency matches or not the fft frequency vector bins . If not your estimated amplitudes will be slghtly off, depending of the frequency mismatch between fft bins and actual signal frequency and also what king of window you are using (or none).
you can play with example below to see the effects (mismatch, window)
to make it simple I choose fs = samples = 500 so df = 1 Hz.
if your signals have integer frequencies, amplitudes are exact , if not... see by yourself and try with hanning window for improved amplitude computation.
samples = 500;
dt = 2e-3; % fs = 500 Hz
t=(0:samples-1)*dt;
x=1*cos(2*pi*40*t)+2*cos(2*pi*70*t); % case 1 : signal frequencies are exact match with fft bins (fft freq points are separated by df = fs/nfft and nfft = samples)
% x=1*cos(2*pi*40.2*t)+2*cos(2*pi*70.3*t); % case 2 : signal frequencies are not exact match with fft bins
% FFT plot
[f1,fft_spectrum1] = do_fft(t,x);
figure(1)
plot(f1,fft_spectrum1,'-*')
title('Scheme 1')
ylabel('|X(f)|')
xlabel('Frequency[hz]')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [freq_vector,fft_spectrum] = do_fft(time,data)
time = time(:);
data = data(:);
dt = mean(diff(time));
Fs = 1/dt;
nfft = length(data); % maximise freq resolution => nfft equals signal length
%% use windowing or not at your conveniance
% no window
fft_spectrum = abs(fft(data))*2/nfft;
% % hanning window
% window = hanning(nfft);
% window = window(:);
% fft_spectrum = abs(fft(data.*window))*4/nfft;
% one sidded fft spectrum % Select first half
if rem(nfft,2) % nfft odd
select = (1:(nfft+1)/2)';
else
select = (1:nfft/2+1)';
end
fft_spectrum = fft_spectrum(select,:);
freq_vector = (select - 1)*Fs/nfft;
end
3 Comments
Mathieu NOE
on 10 Nov 2022
sure - hanning is a bit the everyday solution by default (for guys like me working on noise and vibration data) but cleary the window type must be carefully selected depending of signal type and your expectations
internet is ful of publications about what window for which job and performance...
More Answers (0)
See Also
Categories
Find more on Fourier Analysis and Filtering in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!