I am trying to write my own inverse DFT function in MATLAB as I need a subset of these Fourier mode basis in real space for an application. However, when I check my inverse DFT routine after extracting the Fourier coefficients against Matlab's ifft function and the original waveform there seems to be a slight error. The code is seen from below.
% 1D fft and inverse fft
clear; clc; close all;
L=1; % total domain size
n=100;
x=linspace(0,L,n); %define x values
dx=x(1)-x(2);
F=1*cos(2*pi*5*x); %declare the function
figure(1)
plot(x,F,'linewidth',2,'Displayname','Original');
Fhat=fftshift(fft(F));%compute fft and shift to center
if(mod(n,2)==0) % even split
dk=2*pi/L.*[-n/2:1:1:n/2-1];
else %odd split
dk=2*pi/L*[-(n-1)/2:1:(n-1)/2];
end
figure % plot FFt results
plot(dk/(2*pi),abs(Fhat),'displayname','Frequency')
% Now here is my inverse fft
f=zeros(1,n);
for i=1:n
f=f+Fhat(i).*exp(1j*dk(i).*x)
end
f=f*1/n;
figure(1); hold on;
plot(x,real(f),'b-.','linewidth',2,'displayname','From my own invDFT')
plot(x,ifft(ifftshift(Fhat)),'M--','linewidth',2,'displayname','From matlab ifft')
xlabel('x','fontsize',16)
ylabel('y','fontsize',16)
legend()
Below is an image showing the discrepancy between the waveforms. Comparison of methods
I'm not sure if this issue is a floating point problem or if my frequency bins are incorrect. This is my first time using fft. Any insight is greatly appreciated.
TL;DR
Your code is calculating the inverse as
instead of
But why?
Well, first of all your signal is periodic of period L
, so when you use a vector x
going all the way from 0
to L
you overlap onto the next period of the signal, which will induce confusion (and aliasing).
This said, the DFT (and its inverse) do not explicitly use frequencies, they use bins indexed on the length n
of the signal:
replicating those bins is going to lower the risk of confusion, in your case:
clear; clc; close all;
L=1; % total domain size
n=100;
x=linspace(0,L,n); %define x values
F=1*cos(2*pi*5*x); %declare the function
figure(1)
plot(x,F,'linewidth',2,'Displayname','Original');
Fhat=fftshift(fft(F));%compute fft and shift to center
if(mod(n,2)==0) % even split
dk=2*pi/n.*[-n/2:1:1:n/2-1]; % <-- using n
else %odd split
dk=2*pi/n*[-(n-1)/2:1:(n-1)/2]; % <-- using n
end
figure % plot FFt results
% plot(dk/(2*pi),abs(Fhat),'displayname','Frequency')
% Now here is my inverse fft
f=zeros(1,n);
for i=1:n
f=f+Fhat(i).*exp(1j*dk(i).*(0:(n-1))) % <-- critical difference
end
f=f*1/n;
figure(1); hold on;
plot(x,real(f),'b-.','linewidth',2,'displayname','From my own invDFT')
plot(x,ifft(ifftshift(Fhat)),'M--','linewidth',2,'displayname','From matlab ifft')
xlabel('x','fontsize',16)
ylabel('y','fontsize',16)
legend()
The critical difference is that the exponent j-1
in the previous equation does not go all the way to n
but only to n-1
, contrary to what your x/L
was doing. It had the same effect as resampling all your frequencies by a factor n/(n-1)
, hence the slight shift of frequency you observed.
The result is now coherent: