I implemented the plain DTF / inverse DFT algorithm in C++ in order to help me understand the method. As a sample input I considered
$$ f(x) = \sin \left( \tfrac{\pi}{5} x \right) $$
and collected samples for x = 0, ..., 9. So my input data was (0, 0.58778, 0.951057, ...).
Computing the DFT formula gives two non-zero coefficients: c_1 = (0 - 5i) and c_9 = (0 + 5i).
Now, I compute the inverse DFT. For x=1, these coefficients multiplied with their basis functions give
$$ \tfrac{1}{10} e^{i 2 \pi (1/10)} \cdot (0 - 5i) = (0.293893 -0.404508i) $$
and
$$ \tfrac{1}{10} e^{i 2 \pi (9/10)} \cdot (0 + 5i) = (0.293893 +0.404508i) $$
respectively which is correct as the real parts sum up to 0.58778 (thus, reconstructing the input value) and the imaginary parts sum up to 0. This works great for integral timestamps x=0, 1, 2, ...
My question: ... but how to interpret the results if I plug in x=0.5 (result 0.000000 - 0.951057i) or x=1.5 (result 0.000000 - 0.587785i) for example? I see that it is not DFT's promise to provide a good interpolation here. But is there an intuitive interpretation? (Came across this because I wanted to plot the DFT/IDFT result as a time-continuous graph and don't know how to deal with the complex results between)
EDIT
I add my C++ code here:
void dft( const std::vector<double> & vInput, std::vector< std::complex<double> > & vCoeff )
{
const std::complex<double> i( 0., 1. );
const int nElem = vInput.size();
vCoeff = std::vector< std::complex<double> >( nElem, std::complex<double>(0., 0.) );
for( int k = 0; k < nElem; ++k )
{
for( int j = 0; j < nElem; ++j )
{
vCoeff[k] += exp( -2. * M_PI * i * std::complex<double>( j, 0. ) * std::complex<double>( (double)k / nElem, 0. ) ) * vInput[j];
}
}
}
std::complex<double> inverseDft( const std::vector< std::complex<double> > & vCoeffs, const double t )
{
std::complex<double> result( 0., 0. );
const std::complex<double> i( 0, 1 );
const int nElem = vCoeffs.size();
for( int j = 0; j < nElem; ++j )
{
result += vCoeffs[j] * exp( 2. * M_PI * i * std::complex<double>( j, 0. ) * std::complex<double>( t / nElem, 0. ) );
}
return (result / nElem);
}
This is how I define my input:
std::vector<double> vInput;
for( int i = 0; i < 10; ++i )
{
vInput.push_back ( sin( i * M_PI / 5 ) );
}
And this is the output I did not expect for t=0.5, t=1.5, etc.:
inverseDft( vCoeffs, 0. ); // okay (0.000000, -0.000000)
inverseDft( vCoeffs, 0.5 ); // ?? (0.000000, -0.951057)
inverseDft( vCoeffs, 1. ); // okay (0.587785, -0.000000)
inverseDft( vCoeffs, 1.5 ); // ?? (0.000000, -0.587785)
EDIT2
Great to have these expert answers here! I can contribute the 3D plot which supports my intuition and therefore might also be helpful for others. It shows f(t) computed by IDFT and how it travels over the original data points (crosses). In order to achieve this, it makes use of the whole space including the complex plane.