MATLAB: Time to frequency domain and back again

fftfrequency domainiffttime domain

I am trying to find the proper way to convert a periodic signal from time-domain to frequency-domain (with the proper amplitude and phase) and then retrieving the data again into time-domain. The purpose of this is to do some post processing in frequency-domain and observe the modified signal in time-domain. I am using fft() and ifft() to do so. I tested this approach by creating an arbitrary periodic function consisting of the sum two arbitrary sinusoidal waves (arbitrary phase, amplitude and frequency) and a random noise signal. However, I always get this nonlinear shift in the frequency of the retrieved signal, that is bigger at higher frequency values. The arbitrary signal:
Original signal- retrieved signal comparison (Time-domain)
Original signal- retrieved signal comparison (Frequency domain)
I am trying to investigate the source of this error. I made sure that I am compensating for the windowing effect of the fft as shown in the myfft and myifft functions. I also investigated the effect of frequency step (Spectral leakage) by sampling the total length of the time signal but it didn't seem to affect the results.
The following is the testing code and the used functions:
clc %Clear display
clear all %Clear all variable
close all %Close all windows
f1=1000; %Frequency of the first sine wave
f2=5000; %Frequency of the second sine wave
Tau=1/max([f1,f2])/100; %Sampling time step to make Fsampling = 10*Fmax
Lsignal=[10 100 1000 10^4]; %Multiplication factor applied to define total signal length to compare the effect of freqnecy resolution
Lsignal=2.^nextpow2(Lsignal); %multiplication factor applied to define total signal length
Linecolor=['b','m','k','b','r']; %Line colors array used for each total signal length/ freqnecy resolution
for NLsignal=1:length(Lsignal)
%Create time domain signal
Ttotal=max([1/f1,1/f2])*Lsignal(NLsignal); %Total sample time =Lsignal*Longest periodic time of the signal. This value was selected to insure minmum lekage effect, without windowing
t=0:Tau:Ttotal; %Time vector size is extended
A1=2; A2=5; %Signals amplitude
Phi1=135; Phi2=90; %Signals Phase shifts in degrees
y1=2*sin(2*pi*f1*t-Phi1*pi/180); %Arbitrary sine wave 1
y2=5*sin(2*pi*f2*t-Phi2*pi/180); %Arbitrary sine wave 2
y3=0.7*(rand(length(y2),1)'-0.5); %Arbitary random signal
yt=y1+y2+y3; %Total sine wave
%Display orginal time domain signal
if NLsignal==1
figure (1)
plot(t,y1,'color','r','linewidth',2)
hold on
plot(t,y2,'k','linewidth',2)
hold on
plot(t,y3,'m','linewidth',2)
hold on
plot(t,yt,'b','linewidth',2)
xlabel('Time [sec]')
ylabel('Amplitude')
legend ({'Arbitrary sine wave 1';'Arbitrary sine wave 2';'Noise' ;'Total sine wave'});
xlim([0 max([1/f1,1/f2])])
ylim([-8 8])
Fsampling=1/t(2);
WT=6; % Window type refer to myFFT help for more info

title('Single period of the time doamin of the singal')
else
end
%Display orginal time domain for comparison
if NLsignal==1
figure (2)
plot(t,yt,'color',Linecolor(NLsignal),'linewidth',2)
hold on
xlabel('Time [sec]')
ylabel('Amplitude')
legend ({'Total sine wave'});
xlim([0 max([1/f1,1/f2])])
ylim([-8 8])
Fsampling=1/t(2);
WT=6; % Window type refer to myFFT help for more info
title('Single period of the time doamin of the singal')
else
end
%To frequency domain
[Yxx,ff] = myfft(Fsampling,yt'-mean(yt),WT);
figure(3)
plot(ff,abs(Yxx),'color',Linecolor(NLsignal));
hold on
title('Frequency domain signal')
xlabel('Frequency [Hz]')
ylabel('Amplitude')
figure(4)
plot(ff,angle(Yxx)*180/pi,'color',Linecolor(NLsignal),'linewidth',2)
xlabel('Frequency [Hz]')
ylabel('angle [deg]')
%To time domain
[ yi ] = myifft((Yxx),length(t),WT);
%Display Retrieved time domain for comparison
figure(2)
hold on
plot(t,yi,'color',Linecolor(NLsignal),'linestyle','--','linewidth',2);
%To frequency domain again for verification
[Yxx2,ff2] = myfft(Fsampling,yi,WT);
%Display Retrieved frequency domain for comparison
figure(3)
hold on
plot(ff2,abs(Yxx2),'color',Linecolor(NLsignal),'linestyle','--','linewidth',2);
xlim([0 max([f1,f2])*1.5])
ylim([0 8])
figure(4)
hold on
plot(ff,angle(Yxx)*180/pi,'color',Linecolor(NLsignal),'linestyle','--','linewidth',2);
xlim([min([f1,f2])-1 min([f1,f2])+1])
xlabel('Frequency [Hz]')
ylabel('angle [deg]')
end
figure(2)
grid on
legend({'Original signal';'Retrieved signal:10*TimePeriod ';'Retrieved signal:10^2*TimePeriod ';'Retrieved signal:10^3*TimePeriod ';'Retrieved signal:10^4*TimePeriod ';'Retrieved signal:10^5*TimePeriod '})
figure(3)
grid on
legend({'10*TimePeriod';'Retrieved signal:10*TimePeriod ';'10^2*TimePeriod';'Retrieved signal:10^2*TimePeriod ';'10^3*TimePeriod';'Retrieved signal:10^3*TimePeriod ';'10^4*TimePeriod';'Retrieved signal:10^4*TimePeriod ';'10^5*TimePeriod';'Retrieved signal:10^5*TimePeriod '})
figure(4)
grid on
legend({'10*TimePeriod';'Retrieved signal:10*TimePeriod ';'10^2*TimePeriod';'Retrieved signal:10^2*TimePeriod ';'10^3*TimePeriod';'Retrieved signal:10^3*TimePeriod ';'10^4*TimePeriod';'Retrieved signal:10^4*TimePeriod ';'10^5*TimePeriod';'Retrieved signal:10^5*TimePeriod '})
myfft function:
function [ fftres, freq ] = myfft( Fs,y,WT)
% [ fftres, freq ] = myfft( Fs,y,WT)

% Inputs

% ---------------------------------------------------------------------------------------------------



% Fs: The original sampling frequency of the acquired signal
% y : Input signal in time domain
% WT : Window type. It is used to define the type of window and apply the corresponding CG correction

% 1=Rectangular window

% 2=Hamming window

% 3=Hanning window

% 4=Bartlett window

% 5=Blackman-Harris window

% 6=Flat Top window

%

% Outputs

% ---------------------------------------------------------------------------------------------------
% fftres: the resulted complex fft
% freq: Corresponding frequency vector
Windowtype = {'rectwin'; 'hamming' ;'hanning';'bartlett';'blackmanharris';'flattopwin'};
%Windowing correction factors [1] F. J. Harris, “On the use of windows for harmonic analysis with the discrete fourier transform,”Proceedings of the IEEE, vol. 66, no. 1, pp. 51–83, Jan. 1978.

%CG=1.0000; NG=1.0000; %Rectangular window

%CG=0.5400; NG=0.3974; %Hamming window

%CG=0.5000; NG=0.3750; %Hanning window

%CG=0.5000; NG=0.3333; %Bartlett window

%CG=0.3587; NG=0.2580; %Blackman-Harris window

%CG=0.2156; NG=0.1752; %Flat Top window

CG=[1.0000 0.5400 0.5000 0.5000 0.3587 0.2156];
NG=[1.0000 0.3974 0.3750 0.3333 0.2580 0.1752];
L = length(y);
NFFT = 2^nextpow2(L);
eval(['Y = fft(y.*',char(Windowtype(WT)),'(L),NFFT)/L;'])
f = Fs/2*linspace(0,1,NFFT/2+1);
fftres = 2*(Y(1:NFFT/2+1))/CG(WT);
freq = f(1:NFFT/2+1) ;
end
*myifft* function:
function [ Pt ] = myifft( Pf,Lt,WT)
% [ fftres, freq ] = myfft( Fs,y,WT)
% Inputs
% ---------------------------------------------------------------------------------------------------
% Pf: Vector representing frequency-domain complex amplitudes
% Lt : Length of the vector
% WT : Window type. It is used to define the type of window and apply the corresponding CG correction
% 1=Rectangular window
% 2=Hamming window
% 3=Hanning window
% 4=Bartlett window
% 5=Blackman-Harris window
% 6=Flat Top window
%
% Outputs
% ---------------------------------------------------------------------------------------------------
% Pt: the resulted time domain signal
Windowtype = {'rectwin'; 'hamming' ;'hanning';'bartlett';'blackmanharris';'flattopwin'};
%Windowing correction factors [1] F. J. Harris, “On the use of windows for harmonic analysis with the discrete fourier transform,”Proceedings of the IEEE, vol. 66, no. 1, pp. 51–83, Jan. 1978.
%CG=1.0000; NG=1.0000; %Rectangular window
%CG=0.5400; NG=0.3974; %Hamming window
%CG=0.5000; NG=0.3750; %Hanning window
%CG=0.5000; NG=0.3333; %Bartlett window
%CG=0.3587; NG=0.2580; %Blackman-Harris window
%CG=0.2156; NG=0.1752; %Flat Top window
CG=[1.0000 0.5400 0.5000 0.5000 0.3587 0.2156];
NG=[1.0000 0.3974 0.3750 0.3333 0.2580 0.1752];
Nfft=length(Pf);
Pt = ifft(Pf,Lt,'symmetric');
LPt=length(Pt);
eval(['Winl=' ,char(Windowtype(WT)),'(LPt);']);
Pt=Pt*LPt/2./Winl*CG(WT);
end

Best Answer

Hi weam,
This kind of error occurs all the time. Because of the frequency shift I was interested to see if you had used nextpow(2) anywhere in your calculations. You had, and after replacing
NFFT = 2^nextpow2(L); with NFFT = L;
it works like a charm.
Nextpow can be made to work, although zerofilling has disadvantages in any case. You had the right idea to use NFFT instead of L to construct the frequency grid, so it is not very clear how the error is propagating. But rather to chase that down, it much better and easier besides, to forget about nextpow altogether. You have 10^4 points, so the fft is super fast anyway and there is no need for the complications brought in by going to 2^n points.
At one time 2^n was integral to a breakthrough in computing, but since then ffts have improved and there is no need to use 2^n all the time. It made sense 40 years ago, but it's really time to move on. Unless you have a very large number of points and it is a prime number, there is no need to do any zerofilling.
Related Question