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

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

Sign in to comment.

 Accepted Answer

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

Thank you. It is rare (or impossible) that our real data will have integer # of periods (for all frequencies) in a 'frame'. So I looked into the windows.
The Hanning only provides moderate improvement, but flat top seems to work pretty well.
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,"window","none");
[omegahan,P1han]=fft1D(t,x,"window","Hann");
[omegaft,P1ft]=fft1D(t,x,"window","flattop");
plot(omega,P1)
hold on
plot(omegahan,P1han)
plot(omegaft,P1ft)
hold off
legend(["Uniform","Hanning","Flat top"],"location","best")
xlim([0,400])
function [omega,P1]=fft1D(t,x,Options)
arguments
t (:,1) {mustBeReal}
x (:,1) {mustBeReal}
Options.Window (1,1) string {mustBeMember(Options.Window,["none","Hann","flattop"])} = "none";
end
[x,t]=resample(x,t);
L=numel(t);
Fs=L/(max(t)-min(t));
switch Options.Window
case "none"
w=ones(L,1);
case "Hann"
w=hann(L,"periodic");
case "flattop"
w=flattopwin(L,"periodic");
end
xfft=fft(x.*w);
P2=abs(xfft/L);
wA=L/sum(w); %Amplitude correction factor
if rem(L,2)
% L is odd
idx=(1:(L+1)/2).';
else
idx=(1:L/2+1).';
end
P1=wA*P2(idx);
P1(2:end-1)=2*P1(2:end-1);
omega=Fs*(idx-1)/L*2*pi; %Angular freq
end
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...
Yes, many of them compare different window in terms of spectral accuracy and amplitude accuracy.
I wonder, however, why don't people use uniform window (no window) to identify frequencies first then flat top to determine the amplitude of these frequencies to get the best of both worlds?

Sign in to comment.

More Answers (0)

Products

Release

R2019b

Tags

Community Treasure Hunt

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

Start Hunting!