Here is what I did. Mine is specifically designed to get the same output as Matlab. This only works with a column matrix (you can replace AMatrix with std::vector ).
AMatrix<complex<double>> FastFourierTransform::Forward1d(const AMatrix<double> &inMat) { AMatrix<complex<double>> outMat{ inMat.NumRows(), inMat.NumCols() }; size_t N = inMat.NumElements(); bool isOdd = N % 2 == 1; size_t outSize = (isOdd) ? ceil(N / 2 + 1) : N / 2; fftw_plan plan = fftw_plan_dft_r2c_1d( inMat.NumRows(), reinterpret_cast<double*>(&inMat.mutData()[0]), // mutData here is as same v.data() for std::vector reinterpret_cast<fftw_complex*>(&outMat.mutData()[0]), FFTW_ESTIMATE); fftw_execute(plan); // mirror auto halfWayPoint = outMat.begin() + (outMat.NumRows() / 2) + 1; auto startCopyDest = (isOdd) ? halfWayPoint : halfWayPoint - 1; std::reverse_copy(outMat.begin() + 1, halfWayPoint, startCopyDest); // skip DC (+1) std::for_each(halfWayPoint, outMat.end(), [](auto &c) { return c = std::conj(c);}); return std::move(outMat); } AMatrix<complex<double>> FastFourierTransform::Forward1d(const AMatrix<double> &inMat, size_t points) { // append zeros to matrix until it the same size as points AMatrix<double> sig = inMat; sig.Resize(points, sig.NumCols()); for (size_t i = inMat.NumRows(); i < points; i++) { sig(i, 0) = 0; } return Forward1d(sig); } AMatrix<complex<double>> FastFourierTransform::Inverse1d(const AMatrix<complex<double>> &inMat) { AMatrix<complex<double>> outMat{ inMat.NumRows(), inMat.NumCols() }; size_t N = inMat.NumElements(); fftw_plan plan = fftw_plan_dft_1d( inMat.NumRows(), reinterpret_cast<fftw_complex*>(&inMat.mutData()[0]), reinterpret_cast<fftw_complex*>(&outMat.mutData()[0]), FFTW_BACKWARD, FFTW_ESTIMATE); fftw_execute(plan); // Matlab normalizes auto normalize = [=](auto &c) { return c *= 1. / N; }; std::for_each(outMat.begin(), outMat.end(), normalize); fftw_destroy_plan(plan); return std::move(outMat); } // From Matlab documentation: "ifft tests X to see whether vectors in X along the active dimension // are conjugate symmetric. If so, the computation is faster and the output is real. // An N-element vector x is conjugate symmetric if x(i) = conj(x(mod(N-i+1,N)+1)) for each element of x." // http://uk.mathworks.com/help/matlab/ref/ifft.html AMatrix<double> FastFourierTransform::Inverse1dConjSym(const AMatrix<complex<double>> &inMat) { AMatrix<double> outMat{ inMat.NumRows(), inMat.NumCols() }; size_t N = inMat.NumElements(); fftw_plan plan = fftw_plan_dft_c2r_1d( inMat.NumRows(), reinterpret_cast<fftw_complex*>(&inMat.mutData()[0]), reinterpret_cast<double*>(&outMat.mutData()[0]), FFTW_BACKWARD | FFTW_ESTIMATE); fftw_execute(plan); auto normalize = [=](auto &c) { return c *= 1. / N; }; std::for_each(outMat.begin(), outMat.end(), normalize); fftw_destroy_plan(plan); return std::move(outMat); }
source share