The Frequency is how many times the sine wave crosses the zero line per second. The Amplitude is how high above or below the zero line the sine wave rises to. The Phase indicates where the sine wave was at time = 0. If it was at zero amplitude and rising it has Phase 0 by definition. If it is at it's maximum amplitude and falling it has Phase 90 degrees (pi/2).
F(f) is the transform at frequency f. s(t) is the amplitude of the signal at time t. e is the natural exponent.
j is the square root of -1 as used by complex numbers. The IFT is
s(t)=∫+∞-∞F(f) e j 2 p f t df (2)
This identity
-- e^j*theta = cos(theta) + j sin(theta)
ejq = cos(q) + j sin(q)
gets rid of the exponent:
F[f] = 1/N S
s[k]
cos( -j k p f / N)
+ j sin( -j k p f / N)
for k=0..N-1, for f= 0..N-1
#define _USE_MATH_DEFINES
#include
double arg = -1 * 2.0 * M_PI / (double) NumSamples();
Where NumSamples() returns the number of samples, i.e. N. Substitute back into the equation:
F[f] = 1/N Z s[k]*(cos(k * f * arg) + j*sin(k * f * arg)) for k=0..N-1, for f=0..N-1
mData[k] * Complex(cos(k * f * arg), sin(k * f * arg));If the result is held in an array result[]:
result[f] += mData[k] * Complex(cos(k * f * arg), sin(k * f * arg));
for (long f = 0; f < NumSamples(); f++)
for (long k = 0; k < NumSamples(); k++)
result[f] += mData[k] * Complex(cos(k * f * arg), sin(k * f * arg));
The indicies range from 0 to N-1 and are integers. Because of this the
multiplication k*f will take on the same values as k and f range across 0..N-1. For example if N = 4:
f k f*k 0 0 0 0 1 0 0 2 0 0 3 0 1 0 0 1 1 1 1 2 2 1 3 3 2 0 0 2 1 2 2 2 4 2 3 6 3 0 0 3 1 3 3 2 6 3 3 9In fact, k*f only has 7 values 0, 1, 2, 3, 4, 6, 9. Here's a table comparing N to the number of unique values generated by k*f:
#unique
N values
2 2
3 4
4 7
5 10
6 15
7 19
8 26
9 31
A large number of k and f combinations result in k*f
equal to 0. We can speed up the algorithm by detecting when f or k is zero,
and therefore k*f is zero, and using:
if (f == 0 || k == 0)
result[f] += mData[k] * Complex(1.0, 0.0);
else
result[f] += mData[k] * Complex(cos(k * f * arg), sin(k * f * arg));
Further increases in speed can be found by using the Fast Fourier Transform (see links below).
result /= (double) NumSamples();
Using a parameter we can switch between the forward and inverse DFT's.
double arg = -direction * 2.0 * M_PI / (double) NumSamples();
//...
if (direction == 1)
result /= (double) NumSamples();
//direction = 1 => forward Transform
//direction = -1 => inverse Transform
void Signal::DFT(short int direction)
{
ComplexVector result;
result.resize(NumSamples());
double arg = -direction * 2.0 * M_PI / (double) NumSamples();
for (long f = 0; f < NumSamples(); f++)
for (long k = 0; k < NumSamples(); k++)
if (f == 0 || k == 0)
result[f] += mData[k] * Complex(1.0, 0.0);
else
result[f] += mData[k] * Complex(cos(k * f * arg), sin(k * f * arg));
if (direction == 1)
result /= (double) NumSamples();
mData = result;
}
The remainder of the array is information about the frequencies in the original signal. The frequency information is duplicated so only the first half of the array needs to be examined.
For each array item:
double Complex::length() const
{
return sqrt(real() * real() + imag() * imag());
}
double Complex::direction() const
{
return atan(imag() / real());
}
void Signal::printFreqDomain(const string& title)
{
cout << title << endl;
cout << "Bias: ampl="
<< fmtdouble(mData[0].real())
<< endl;
double arg = (double) NumSamples() / (double)mSampleRate;
for(long i = 1; i < NumSamples() / 2 ; ++i)
{
double ampl = 2.0 * mData[i].length();
double phase = mData[i].direction();
cout << fmtdouble(i / arg)
<< " "
<< fmtdouble(ampl)
<< " "
<< fmtdouble(phase)
<< endl;
}
}
A good reference for the DFT is here:
http://astronomy.swin.edu.au/~prourke/analysis/dft