#pragma once /** * @file fft.hpp FFT and related facilities. */ #include "sample.hpp" #include #include #include #ifndef M_PI #define M_PI 3.141592653589793 #endif #define M_TAU (2.0 * M_PI) namespace da { // With g++ optimization -fcx-limited-range should be used for 5x performance boost. // Based on the description of Volodymyr Myrnyy in // http://www.dspdesignline.com/showArticle.jhtml?printableArticle=true&articleId=199903272 template struct DanielsonLanczos { static void apply(std::complex* data) { constexpr std::size_t N = 1 << P; constexpr std::size_t M = N / 2; // Compute even and odd halves DanielsonLanczos

().apply(data); DanielsonLanczos

().apply(data + M); // Combine the results std::complex w(1.0); for (std::size_t i = 0; i < M; ++i) { const std::complex temp = data[i + M] * w; data[M + i] = data[i] - temp; data[i] += temp; w *= std::polar(1.0, -M_TAU / N); } } }; template struct DanielsonLanczos<0, T> { static void apply(std::complex*) {} }; /** Perform FFT on data. **/ template void fft(std::complex* data) { // Perform bit-reversal sorting of sample data. constexpr std::size_t N = 1 << P; std::size_t j = 0; for (std::size_t i = 0; i < N; ++i) { if (i < j) std::swap(data[i], data[j]); std::size_t m = N / 2; while (m > 1 && m <= j) { j -= m; m >>= 1; } j += m; } // Do the actual calculation DanielsonLanczos::apply(data); } /** Perform FFT on data from floating point iterator, windowing the input. **/ template std::vector > fft(InIt begin, Window window) { std::vector > data(1 << P); // Perform bit-reversal sorting of sample data. constexpr std::size_t N = 1 << P; std::size_t j = 0; for (std::size_t i = 0; i < N; ++i) { data[j] = *begin++ * window[i]; std::size_t m = N / 2; while (m > 1 && m <= j) { j -= m; m >>= 1; } j += m; } // Do the actual calculation DanielsonLanczos::apply(&data[0]); return data; } template void ifft(std::complex* data) { constexpr std::size_t N = 1 << P; for (std::size_t i = 0; i < N; ++i) data[i] = std::conj(data[i]); // Invert phase so that we can use FFT to do IFFT fft

(data); constexpr std::complex scale(1.0/N, 0.0); for (std::size_t i = 0; i < N; ++i) data[i] = scale * std::conj(data[i]); // Invert back, and apply IFFT scaling } }