11#include "./InternalHeaderCheck.h"
20template <
typename Scalar_>
22 typedef Scalar_ Scalar;
23 typedef std::complex<Scalar> Complex;
24 std::vector<Complex> m_twiddles;
25 std::vector<int> m_stageRadix;
26 std::vector<int> m_stageRemainder;
27 std::vector<Complex> m_scratchBuf;
30 static const Scalar m_pi4;
32 inline void make_twiddles(
int nfft,
bool inverse) {
36 m_twiddles.resize(nfft);
37 Scalar phinc = m_pi4 / nfft;
38 Scalar flip =
inverse ? Scalar(1) : Scalar(-1);
39 m_twiddles[0] = Complex(Scalar(1), Scalar(0));
40 if ((nfft & 1) == 0) m_twiddles[nfft / 2] = Complex(Scalar(-1), Scalar(0));
42 for (; i * 8 < nfft; ++i) {
43 Scalar c = Scalar(
cos(i * 8 * phinc));
44 Scalar s = Scalar(
sin(i * 8 * phinc));
45 m_twiddles[i] = Complex(c, s * flip);
46 m_twiddles[nfft - i] = Complex(c, -s * flip);
48 for (; i * 4 < nfft; ++i) {
49 Scalar c = Scalar(
cos((2 * nfft - 8 * i) * phinc));
50 Scalar s = Scalar(
sin((2 * nfft - 8 * i) * phinc));
51 m_twiddles[i] = Complex(s, c * flip);
52 m_twiddles[nfft - i] = Complex(s, -c * flip);
54 for (; i * 8 < 3 * nfft; ++i) {
55 Scalar c = Scalar(
cos((8 * i - 2 * nfft) * phinc));
56 Scalar s = Scalar(
sin((8 * i - 2 * nfft) * phinc));
57 m_twiddles[i] = Complex(-s, c * flip);
58 m_twiddles[nfft - i] = Complex(-s, -c * flip);
60 for (; i * 2 < nfft; ++i) {
61 Scalar c = Scalar(
cos((4 * nfft - 8 * i) * phinc));
62 Scalar s = Scalar(
sin((4 * nfft - 8 * i) * phinc));
63 m_twiddles[i] = Complex(-c, s * flip);
64 m_twiddles[nfft - i] = Complex(-c, -s * flip);
68 void factorize(
int nfft) {
88 m_stageRadix.push_back(p);
89 m_stageRemainder.push_back(n);
90 if (p > 5) m_scratchBuf.resize(p);
94 template <
typename Src_>
95 inline void work(
int stage, Complex *xout,
const Src_ *xin,
size_t fstride,
size_t in_stride) {
96 int p = m_stageRadix[stage];
97 int m = m_stageRemainder[stage];
98 Complex *Fout_beg = xout;
99 Complex *Fout_end = xout + p * m;
107 work(stage + 1, xout, xin, fstride * p, in_stride);
108 xin += fstride * in_stride;
109 }
while ((xout += m) != Fout_end);
113 xin += fstride * in_stride;
114 }
while (++xout != Fout_end);
121 bfly2(xout, fstride, m);
124 bfly3(xout, fstride, m);
127 bfly4(xout, fstride, m);
130 bfly5(xout, fstride, m);
133 bfly_generic(xout, fstride, m, p);
138 inline void bfly2(Complex *Fout,
const size_t fstride,
int m) {
139 for (
int k = 0; k < m; ++k) {
140 Complex t = Fout[m + k] * m_twiddles[k * fstride];
141 Fout[m + k] = Fout[k] - t;
146 inline void bfly4(Complex *Fout,
const size_t fstride,
const size_t m) {
148 int negative_if_inverse = m_inverse * -2 + 1;
149 for (
size_t k = 0; k < m; ++k) {
150 scratch[0] = Fout[k + m] * m_twiddles[k * fstride];
151 scratch[1] = Fout[k + 2 * m] * m_twiddles[k * fstride * 2];
152 scratch[2] = Fout[k + 3 * m] * m_twiddles[k * fstride * 3];
153 scratch[5] = Fout[k] - scratch[1];
155 Fout[k] += scratch[1];
156 scratch[3] = scratch[0] + scratch[2];
157 scratch[4] = scratch[0] - scratch[2];
158 scratch[4] = Complex(scratch[4].
imag() * negative_if_inverse, -scratch[4].
real() * negative_if_inverse);
160 Fout[k + 2 * m] = Fout[k] - scratch[3];
161 Fout[k] += scratch[3];
162 Fout[k + m] = scratch[5] + scratch[4];
163 Fout[k + 3 * m] = scratch[5] - scratch[4];
167 inline void bfly3(Complex *Fout,
const size_t fstride,
const size_t m) {
169 const size_t m2 = 2 * m;
173 epi3 = m_twiddles[fstride * m];
175 tw1 = tw2 = &m_twiddles[0];
178 scratch[1] = Fout[m] * *tw1;
179 scratch[2] = Fout[m2] * *tw2;
181 scratch[3] = scratch[1] + scratch[2];
182 scratch[0] = scratch[1] - scratch[2];
185 Fout[m] = Complex(Fout->real() - Scalar(.5) * scratch[3].
real(), Fout->imag() - Scalar(.5) * scratch[3].
imag());
186 scratch[0] *= epi3.imag();
188 Fout[m2] = Complex(Fout[m].
real() + scratch[0].
imag(), Fout[m].
imag() - scratch[0].
real());
189 Fout[m] += Complex(-scratch[0].
imag(), scratch[0].
real());
194 inline void bfly5(Complex *Fout,
const size_t fstride,
const size_t m) {
195 Complex *Fout0, *Fout1, *Fout2, *Fout3, *Fout4;
198 Complex *twiddles = &m_twiddles[0];
201 ya = twiddles[fstride * m];
202 yb = twiddles[fstride * 2 * m];
206 Fout2 = Fout0 + 2 * m;
207 Fout3 = Fout0 + 3 * m;
208 Fout4 = Fout0 + 4 * m;
211 for (u = 0; u < m; ++u) {
214 scratch[1] = *Fout1 * tw[u * fstride];
215 scratch[2] = *Fout2 * tw[2 * u * fstride];
216 scratch[3] = *Fout3 * tw[3 * u * fstride];
217 scratch[4] = *Fout4 * tw[4 * u * fstride];
219 scratch[7] = scratch[1] + scratch[4];
220 scratch[10] = scratch[1] - scratch[4];
221 scratch[8] = scratch[2] + scratch[3];
222 scratch[9] = scratch[2] - scratch[3];
224 *Fout0 += scratch[7];
225 *Fout0 += scratch[8];
227 scratch[5] = scratch[0] + Complex((scratch[7].
real() * ya.real()) + (scratch[8].real() * yb.real()),
228 (scratch[7].imag() * ya.real()) + (scratch[8].imag() * yb.real()));
230 scratch[6] = Complex((scratch[10].
imag() * ya.imag()) + (scratch[9].imag() * yb.imag()),
231 -(scratch[10].real() * ya.imag()) - (scratch[9].real() * yb.imag()));
233 *Fout1 = scratch[5] - scratch[6];
234 *Fout4 = scratch[5] + scratch[6];
236 scratch[11] = scratch[0] + Complex((scratch[7].
real() * yb.real()) + (scratch[8].real() * ya.real()),
237 (scratch[7].imag() * yb.real()) + (scratch[8].imag() * ya.real()));
239 scratch[12] = Complex(-(scratch[10].
imag() * yb.imag()) + (scratch[9].imag() * ya.imag()),
240 (scratch[10].real() * yb.imag()) - (scratch[9].real() * ya.imag()));
242 *Fout2 = scratch[11] + scratch[12];
243 *Fout3 = scratch[11] - scratch[12];
254 inline void bfly_generic(Complex *Fout,
const size_t fstride,
int m,
int p) {
256 Complex *twiddles = &m_twiddles[0];
258 int Norig =
static_cast<int>(m_twiddles.size());
259 Complex *scratchbuf = &m_scratchBuf[0];
261 for (u = 0; u < m; ++u) {
263 for (q1 = 0; q1 < p; ++q1) {
264 scratchbuf[q1] = Fout[k];
269 for (q1 = 0; q1 < p; ++q1) {
271 Fout[k] = scratchbuf[0];
272 for (q = 1; q < p; ++q) {
273 twidx +=
static_cast<int>(fstride) * k;
274 if (twidx >= Norig) twidx -= Norig;
275 t = scratchbuf[q] * twiddles[twidx];
284template <
typename _Scalar>
285const typename kiss_cpx_fft<_Scalar>::Scalar kiss_cpx_fft<_Scalar>::m_pi4 =
286 numext::atan(kiss_cpx_fft<_Scalar>::Scalar(1));
288template <
typename Scalar_>
290 typedef Scalar_ Scalar;
291 typedef std::complex<Scalar> Complex;
295 m_realTwiddles.clear();
298 inline void fwd(Complex *dst,
const Complex *src,
int nfft) { get_plan(nfft,
false).work(0, dst, src, 1, 1); }
300 inline void fwd2(Complex *dst,
const Complex *src,
int n0,
int n1) {
301 EIGEN_UNUSED_VARIABLE(dst);
302 EIGEN_UNUSED_VARIABLE(src);
303 EIGEN_UNUSED_VARIABLE(n0);
304 EIGEN_UNUSED_VARIABLE(n1);
307 inline void inv2(Complex *dst,
const Complex *src,
int n0,
int n1) {
308 EIGEN_UNUSED_VARIABLE(dst);
309 EIGEN_UNUSED_VARIABLE(src);
310 EIGEN_UNUSED_VARIABLE(n0);
311 EIGEN_UNUSED_VARIABLE(n1);
318 inline void fwd(Complex *dst,
const Scalar *src,
int nfft) {
321 m_tmpBuf1.resize(nfft);
322 get_plan(nfft,
false).work(0, &m_tmpBuf1[0], src, 1, 1);
323 std::copy(m_tmpBuf1.begin(), m_tmpBuf1.begin() + (nfft >> 1) + 1, dst);
325 int ncfft = nfft >> 1;
326 int ncfft2 = nfft >> 2;
327 Complex *rtw = real_twiddles(ncfft2);
330 fwd(dst,
reinterpret_cast<const Complex *
>(src), ncfft);
331 Complex dc(dst[0].
real() + dst[0].
imag());
332 Complex nyquist(dst[0].
real() - dst[0].
imag());
334 for (k = 1; k <= ncfft2; ++k) {
335 Complex fpk = dst[k];
336 Complex fpnk =
conj(dst[ncfft - k]);
337 Complex f1k = fpk + fpnk;
338 Complex f2k = fpk - fpnk;
339 Complex tw = f2k * rtw[k - 1];
340 dst[k] = (f1k + tw) * Scalar(.5);
341 dst[ncfft - k] =
conj(f1k - tw) * Scalar(.5);
344 dst[ncfft] = nyquist;
349 inline void inv(Complex *dst,
const Complex *src,
int nfft) { get_plan(nfft,
true).work(0, dst, src, 1, 1); }
352 inline void inv(Scalar *dst,
const Complex *src,
int nfft) {
354 m_tmpBuf1.resize(nfft);
355 m_tmpBuf2.resize(nfft);
356 std::copy(src, src + (nfft >> 1) + 1, m_tmpBuf1.begin());
357 for (
int k = 1; k < (nfft >> 1) + 1; ++k) m_tmpBuf1[nfft - k] =
conj(m_tmpBuf1[k]);
358 inv(&m_tmpBuf2[0], &m_tmpBuf1[0], nfft);
359 for (
int k = 0; k < nfft; ++k) dst[k] = m_tmpBuf2[k].
real();
362 int ncfft = nfft >> 1;
363 int ncfft2 = nfft >> 2;
364 Complex *rtw = real_twiddles(ncfft2);
365 m_tmpBuf1.resize(ncfft);
366 m_tmpBuf1[0] = Complex(src[0].
real() + src[ncfft].
real(), src[0].
real() - src[ncfft].
real());
367 for (
int k = 1; k <= ncfft / 2; ++k) {
369 Complex fnkc =
conj(src[ncfft - k]);
370 Complex fek = fk + fnkc;
371 Complex tmp = fk - fnkc;
372 Complex fok = tmp *
conj(rtw[k - 1]);
373 m_tmpBuf1[k] = fek + fok;
374 m_tmpBuf1[ncfft - k] =
conj(fek - fok);
376 get_plan(ncfft,
true).work(0,
reinterpret_cast<Complex *
>(dst), &m_tmpBuf1[0], 1, 1);
381 typedef kiss_cpx_fft<Scalar> PlanData;
382 typedef std::map<int, PlanData> PlanMap;
385 std::map<int, std::vector<Complex> > m_realTwiddles;
386 std::vector<Complex> m_tmpBuf1;
387 std::vector<Complex> m_tmpBuf2;
389 inline int PlanKey(
int nfft,
bool isinverse)
const {
return (nfft << 1) | int(isinverse); }
391 inline PlanData &get_plan(
int nfft,
bool inverse) {
393 PlanData &pd = m_plans[PlanKey(nfft,
inverse)];
394 if (pd.m_twiddles.size() == 0) {
395 pd.make_twiddles(nfft,
inverse);
401 inline Complex *real_twiddles(
int ncfft2) {
403 std::vector<Complex> &twidref = m_realTwiddles[ncfft2];
404 if ((
int)twidref.size() != ncfft2) {
405 twidref.resize(ncfft2);
406 int ncfft = ncfft2 << 1;
407 Scalar pi =
acos(Scalar(-1));
408 for (
int k = 1; k <= ncfft2; ++k) twidref[k - 1] =
exp(Complex(0, -pi * (Scalar(k) / ncfft + Scalar(.5))));
Namespace containing all symbols from the Eigen library.
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_cos_op< typename Derived::Scalar >, const Derived > cos(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_inverse_op< typename Derived::Scalar >, const Derived > inverse(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_exp_op< typename Derived::Scalar >, const Derived > exp(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_imag_op< typename Derived::Scalar >, const Derived > imag(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sin_op< typename Derived::Scalar >, const Derived > sin(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_acos_op< typename Derived::Scalar >, const Derived > acos(const Eigen::ArrayBase< Derived > &x)