#include "DiscreteFourierTransform.hh" #include template DiscreteFourierTransform::DiscreteFourierTransform(vector signal_, double sampleSpacing_) { signal = signal_; sampleSpacing = sampleSpacing_; } template void DiscreteFourierTransform::compute(bool computeFFT) { if (computeFFT) { const int N = signal.size(); const int powerOf2 = DiscreteFourierTransform::highestPowerof2(N); // Zero padding is a simple concept; it simply refers to adding zeros to end of a time-domain signal to increase its length to reach power of 2. while (signal.size() < powerOf2) signal.push_back((T)0); phasors = DiscreteFourierTransform::fft(signal); } else phasors = DiscreteFourierTransform::dft(signal); } template std::vector DiscreteFourierTransform::createTestPoints(int N, double sampleSpacing) { std::vector out; const E t = (E)sampleSpacing; for (int i = 0; i < N; i++) { out.push_back((E)t * i); } return out; } template std::vector DiscreteFourierTransform::createTestFunction(std::vector x) { const int N = x.size(); std::vector out; for (int i = 0; i < N; i++) { const E val = (E)sin(50.0 * 2.0 * M_PI * x[i]) + 0.5 * sin(80.0 * 2.0 * M_PI * x[i]); out.push_back(val); } return out; } /** * @brief We use Cooley-Tukey FFT Algorithm if the size of the signal is a power of 2 otherwise you should DFT brut. In The future we will use bluestein algorithm instead of DFT. * Cooley-Tukey FFT Algorithms: http://people.scs.carleton.ca/~maheshwa/courses/5703COMP/16Fall/FFT_Report.pdf * * @tparam T template type of input data * @tparam E template type of output data * @param sig the signal as an input * @return std::vector> the phasors (array of complex number) */ template std::vector> DiscreteFourierTransform::fft(std::vector sig) { const int N = sig.size(); if (N == 1) { std::vector> out; const std::complex temp((E)sig[0], (E)0); out.push_back(temp); return out; } const std::complex WN = (complex)std::polar(1.0, 2 * M_PI / N); std::complex W((E)1, (E)0); // divide and conquer: // Recurse: all even samples std::vector> x_evens = fft(getEven(sig)); // Recurse: all odd samples std::vector> x_odds = fft(getOdd(sig)); // Now, combine and perform N/2 operations! std::complex zeroComplex((E)0, (E)0); std::vector> x(N, zeroComplex); for (int k = 0; k < N / 2; k++) { x[k] = x_evens[k] + W * x_odds[k]; x[k + (N / 2)] = x_evens[k] - W * x_odds[k]; W = W * WN; } return x; } template std::vector> DiscreteFourierTransform::dft(std::vector x) { const int N = x.size(); std::complex zeroComplex((E)0, (E)0); std::vector> out(N, zeroComplex); for (int k = 0; k < N; k++) { for (int n = 0; n < N; n++) { const std::complex expVal = (complex)std::polar(1.0, -2 * k * n * M_PI / N); out[k] += ((E)x[n]) * expVal; } } return out; } template std::vector DiscreteFourierTransform::computeDSP(std::vector> x, double frequency_) { const int N = x.size(); std::vector out; for (int k = 1; k < N / 2; k++) { const E magnitudePower2 = (E)pow(abs(x[k]), 2); // const E dsp = (E)(2.0 / (N * frequency_)) * magnitudePower2; out.push_back(magnitudePower2); } return out; } template std::vector DiscreteFourierTransform::getFreq(std::vector> x, double frequency_) { const int N = x.size(); std::vector out; for (int k = 1; k < N / 2; k++) { const E freq = (E)k * frequency_ / N; out.push_back(freq); } return out; } template std::vector DiscreteFourierTransform::getPeriods(std::vector> x, double frequency_) { const int N = x.size(); std::vector out; for (int k = 1; k < N / 2; k++) { const E period = N / ((E)k * frequency_); out.push_back(period); } return out; } template std::vector DiscreteFourierTransform::getOdd(std::vector x) { std::vector odd; for (int i = 0; i < x.size(); i++) { if (i % 2 != 0) odd.push_back(x[i]); } return odd; } template std::vector DiscreteFourierTransform::getEven(std::vector x) { std::vector even; for (int i = 0; i < x.size(); i++) { if (i % 2 == 0) even.push_back(x[i]); } return even; } template bool DiscreteFourierTransform::isPowerOfTwo(int N) { return (N & (N - 1)) == 0; } template int DiscreteFourierTransform::highestPowerof2(int n) { int p = n; while (!DiscreteFourierTransform::isPowerOfTwo(p)) { p += 1; } return p; }