11#ifndef EIGEN_FFT_KISSFFT_IMPL_H
12#define EIGEN_FFT_KISSFFT_IMPL_H
15#include "./InternalHeaderCheck.h"
24template <
typename Scalar_>
26 typedef Scalar_ Scalar;
27 typedef std::complex<Scalar> Complex;
28 std::vector<Complex> m_twiddles;
29 std::vector<int> m_stageRadix;
30 std::vector<int> m_stageRemainder;
31 std::vector<Complex> m_scratchBuf;
34 static const Scalar m_pi4;
36 inline void make_twiddles(
int nfft,
bool inverse) {
40 m_twiddles.resize(nfft);
41 Scalar phinc = m_pi4 / nfft;
42 Scalar flip = inverse ? Scalar(1) : Scalar(-1);
43 m_twiddles[0] = Complex(Scalar(1), Scalar(0));
44 if ((nfft & 1) == 0) m_twiddles[nfft / 2] = Complex(Scalar(-1), Scalar(0));
46 for (; i * 8 < nfft; ++i) {
47 Scalar c = Scalar(cos(i * 8 * phinc));
48 Scalar s = Scalar(sin(i * 8 * phinc));
49 m_twiddles[i] = Complex(c, s * flip);
50 m_twiddles[nfft - i] = Complex(c, -s * flip);
52 for (; i * 4 < nfft; ++i) {
53 Scalar c = Scalar(cos((2 * nfft - 8 * i) * phinc));
54 Scalar s = Scalar(sin((2 * nfft - 8 * i) * phinc));
55 m_twiddles[i] = Complex(s, c * flip);
56 m_twiddles[nfft - i] = Complex(s, -c * flip);
58 for (; i * 8 < 3 * nfft; ++i) {
59 Scalar c = Scalar(cos((8 * i - 2 * nfft) * phinc));
60 Scalar s = Scalar(sin((8 * i - 2 * nfft) * phinc));
61 m_twiddles[i] = Complex(-s, c * flip);
62 m_twiddles[nfft - i] = Complex(-s, -c * flip);
64 for (; i * 2 < nfft; ++i) {
65 Scalar c = Scalar(cos((4 * nfft - 8 * i) * phinc));
66 Scalar s = Scalar(sin((4 * nfft - 8 * i) * phinc));
67 m_twiddles[i] = Complex(-c, s * flip);
68 m_twiddles[nfft - i] = Complex(-c, -s * flip);
72 void factorize(
int nfft) {
92 m_stageRadix.push_back(p);
93 m_stageRemainder.push_back(n);
94 if (p > 5) m_scratchBuf.resize(p);
98 template <
typename Src_>
99 inline void work(
int stage, Complex *xout,
const Src_ *xin,
size_t fstride,
size_t in_stride) {
100 int p = m_stageRadix[stage];
101 int m = m_stageRemainder[stage];
102 Complex *Fout_beg = xout;
103 Complex *Fout_end = xout + p * m;
111 work(stage + 1, xout, xin, fstride * p, in_stride);
112 xin += fstride * in_stride;
113 }
while ((xout += m) != Fout_end);
117 xin += fstride * in_stride;
118 }
while (++xout != Fout_end);
125 bfly2(xout, fstride, m);
128 bfly3(xout, fstride, m);
131 bfly4(xout, fstride, m);
134 bfly5(xout, fstride, m);
137 bfly_generic(xout, fstride, m, p);
142 inline void bfly2(Complex *Fout,
const size_t fstride,
int m) {
143 for (
int k = 0; k < m; ++k) {
144 Complex t = Fout[m + k] * m_twiddles[k * fstride];
145 Fout[m + k] = Fout[k] - t;
150 inline void bfly4(Complex *Fout,
const size_t fstride,
const size_t m) {
152 int negative_if_inverse = m_inverse * -2 + 1;
153 for (
size_t k = 0; k < m; ++k) {
154 scratch[0] = Fout[k + m] * m_twiddles[k * fstride];
155 scratch[1] = Fout[k + 2 * m] * m_twiddles[k * fstride * 2];
156 scratch[2] = Fout[k + 3 * m] * m_twiddles[k * fstride * 3];
157 scratch[5] = Fout[k] - scratch[1];
159 Fout[k] += scratch[1];
160 scratch[3] = scratch[0] + scratch[2];
161 scratch[4] = scratch[0] - scratch[2];
162 scratch[4] = Complex(scratch[4].imag() * negative_if_inverse, -scratch[4].real() * negative_if_inverse);
164 Fout[k + 2 * m] = Fout[k] - scratch[3];
165 Fout[k] += scratch[3];
166 Fout[k + m] = scratch[5] + scratch[4];
167 Fout[k + 3 * m] = scratch[5] - scratch[4];
171 inline void bfly3(Complex *Fout,
const size_t fstride,
const size_t m) {
173 const size_t m2 = 2 * m;
177 epi3 = m_twiddles[fstride * m];
179 tw1 = tw2 = &m_twiddles[0];
182 scratch[1] = Fout[m] * *tw1;
183 scratch[2] = Fout[m2] * *tw2;
185 scratch[3] = scratch[1] + scratch[2];
186 scratch[0] = scratch[1] - scratch[2];
189 Fout[m] = Complex(Fout->real() - Scalar(.5) * scratch[3].real(), Fout->imag() - Scalar(.5) * scratch[3].imag());
190 scratch[0] *= epi3.imag();
192 Fout[m2] = Complex(Fout[m].real() + scratch[0].imag(), Fout[m].imag() - scratch[0].real());
193 Fout[m] += Complex(-scratch[0].imag(), scratch[0].real());
198 inline void bfly5(Complex *Fout,
const size_t fstride,
const size_t m) {
199 Complex *Fout0, *Fout1, *Fout2, *Fout3, *Fout4;
202 Complex *twiddles = &m_twiddles[0];
205 ya = twiddles[fstride * m];
206 yb = twiddles[fstride * 2 * m];
210 Fout2 = Fout0 + 2 * m;
211 Fout3 = Fout0 + 3 * m;
212 Fout4 = Fout0 + 4 * m;
215 for (u = 0; u < m; ++u) {
218 scratch[1] = *Fout1 * tw[u * fstride];
219 scratch[2] = *Fout2 * tw[2 * u * fstride];
220 scratch[3] = *Fout3 * tw[3 * u * fstride];
221 scratch[4] = *Fout4 * tw[4 * u * fstride];
223 scratch[7] = scratch[1] + scratch[4];
224 scratch[10] = scratch[1] - scratch[4];
225 scratch[8] = scratch[2] + scratch[3];
226 scratch[9] = scratch[2] - scratch[3];
228 *Fout0 += scratch[7];
229 *Fout0 += scratch[8];
231 scratch[5] = scratch[0] + Complex((scratch[7].real() * ya.real()) + (scratch[8].real() * yb.real()),
232 (scratch[7].imag() * ya.real()) + (scratch[8].imag() * yb.real()));
234 scratch[6] = Complex((scratch[10].imag() * ya.imag()) + (scratch[9].imag() * yb.imag()),
235 -(scratch[10].real() * ya.imag()) - (scratch[9].real() * yb.imag()));
237 *Fout1 = scratch[5] - scratch[6];
238 *Fout4 = scratch[5] + scratch[6];
240 scratch[11] = scratch[0] + Complex((scratch[7].real() * yb.real()) + (scratch[8].real() * ya.real()),
241 (scratch[7].imag() * yb.real()) + (scratch[8].imag() * ya.real()));
243 scratch[12] = Complex(-(scratch[10].imag() * yb.imag()) + (scratch[9].imag() * ya.imag()),
244 (scratch[10].real() * yb.imag()) - (scratch[9].real() * ya.imag()));
246 *Fout2 = scratch[11] + scratch[12];
247 *Fout3 = scratch[11] - scratch[12];
258 inline void bfly_generic(Complex *Fout,
const size_t fstride,
int m,
int p) {
260 Complex *twiddles = &m_twiddles[0];
262 int Norig =
static_cast<int>(m_twiddles.size());
263 Complex *scratchbuf = &m_scratchBuf[0];
265 for (u = 0; u < m; ++u) {
267 for (q1 = 0; q1 < p; ++q1) {
268 scratchbuf[q1] = Fout[k];
273 for (q1 = 0; q1 < p; ++q1) {
275 Fout[k] = scratchbuf[0];
276 for (q = 1; q < p; ++q) {
277 twidx +=
static_cast<int>(fstride) * k;
278 if (twidx >= Norig) twidx -= Norig;
279 t = scratchbuf[q] * twiddles[twidx];
288template <
typename _Scalar>
289const typename kiss_cpx_fft<_Scalar>::Scalar kiss_cpx_fft<_Scalar>::m_pi4 =
290 numext::atan(kiss_cpx_fft<_Scalar>::Scalar(1));
292template <
typename Scalar_>
294 typedef Scalar_ Scalar;
295 typedef std::complex<Scalar> Complex;
299 m_realTwiddles.clear();
302 inline void fwd(Complex *dst,
const Complex *src,
int nfft) { run_c2c(dst, src, nfft,
false); }
304 inline void fwd2(Complex *dst,
const Complex *src,
int n0,
int n1) {
305 EIGEN_UNUSED_VARIABLE(dst);
306 EIGEN_UNUSED_VARIABLE(src);
307 EIGEN_UNUSED_VARIABLE(n0);
308 EIGEN_UNUSED_VARIABLE(n1);
311 inline void inv2(Complex *dst,
const Complex *src,
int n0,
int n1) {
312 EIGEN_UNUSED_VARIABLE(dst);
313 EIGEN_UNUSED_VARIABLE(src);
314 EIGEN_UNUSED_VARIABLE(n0);
315 EIGEN_UNUSED_VARIABLE(n1);
322 inline void fwd(Complex *dst,
const Scalar *src,
int nfft) {
325 m_tmpBuf1.resize(nfft);
326 get_plan(nfft,
false).work(0, &m_tmpBuf1[0], src, 1, 1);
327 std::copy(m_tmpBuf1.begin(), m_tmpBuf1.begin() + (nfft >> 1) + 1, dst);
329 int ncfft = nfft >> 1;
330 int ncfft2 = nfft >> 2;
331 Complex *rtw = real_twiddles(ncfft2);
334 fwd(dst,
reinterpret_cast<const Complex *
>(src), ncfft);
335 Complex dc(dst[0].real() + dst[0].imag());
336 Complex nyquist(dst[0].real() - dst[0].imag());
338 for (k = 1; k <= ncfft2; ++k) {
339 Complex fpk = dst[k];
340 Complex fpnk = conj(dst[ncfft - k]);
341 Complex f1k = fpk + fpnk;
342 Complex f2k = fpk - fpnk;
343 Complex tw = f2k * rtw[k - 1];
344 dst[k] = (f1k + tw) * Scalar(.5);
345 dst[ncfft - k] = conj(f1k - tw) * Scalar(.5);
348 dst[ncfft] = nyquist;
353 inline void inv(Complex *dst,
const Complex *src,
int nfft) { run_c2c(dst, src, nfft,
true); }
356 inline void inv(Scalar *dst,
const Complex *src,
int nfft) {
358 m_tmpBuf1.resize(nfft);
359 m_tmpBuf2.resize(nfft);
360 std::copy(src, src + (nfft >> 1) + 1, m_tmpBuf1.begin());
361 for (
int k = 1; k < (nfft >> 1) + 1; ++k) m_tmpBuf1[nfft - k] = conj(m_tmpBuf1[k]);
362 inv(&m_tmpBuf2[0], &m_tmpBuf1[0], nfft);
363 for (
int k = 0; k < nfft; ++k) dst[k] = m_tmpBuf2[k].real();
366 int ncfft = nfft >> 1;
367 int ncfft2 = nfft >> 2;
368 Complex *rtw = real_twiddles(ncfft2);
369 m_tmpBuf1.resize(ncfft);
370 m_tmpBuf1[0] = Complex(src[0].real() + src[ncfft].real(), src[0].real() - src[ncfft].real());
371 for (
int k = 1; k <= ncfft / 2; ++k) {
373 Complex fnkc = conj(src[ncfft - k]);
374 Complex fek = fk + fnkc;
375 Complex tmp = fk - fnkc;
376 Complex fok = tmp * conj(rtw[k - 1]);
377 m_tmpBuf1[k] = fek + fok;
378 m_tmpBuf1[ncfft - k] = conj(fek - fok);
380 get_plan(ncfft,
true).work(0,
reinterpret_cast<Complex *
>(dst), &m_tmpBuf1[0], 1, 1);
385 typedef kiss_cpx_fft<Scalar> PlanData;
386 typedef std::map<int, PlanData> PlanMap;
389 std::map<int, std::vector<Complex> > m_realTwiddles;
390 std::vector<Complex> m_tmpBuf1;
391 std::vector<Complex> m_tmpBuf2;
393 inline int PlanKey(
int nfft,
bool isinverse)
const {
return (nfft << 1) | int(isinverse); }
395 inline PlanData &get_plan(
int nfft,
bool inverse) {
397 PlanData &pd = m_plans[PlanKey(nfft, inverse)];
398 if (pd.m_twiddles.size() == 0) {
399 pd.make_twiddles(nfft, inverse);
407 inline void run_c2c(Complex *dst,
const Complex *src,
int nfft,
bool inverse) {
409 ei_declare_aligned_stack_constructed_variable(Complex, scratch, nfft, 0);
410 std::copy(src, src + nfft, scratch);
411 get_plan(nfft, inverse).work(0, dst, scratch, 1, 1);
414 get_plan(nfft, inverse).work(0, dst, src, 1, 1);
417 inline Complex *real_twiddles(
int ncfft2) {
419 std::vector<Complex> &twidref = m_realTwiddles[ncfft2];
420 if ((
int)twidref.size() != ncfft2) {
421 twidref.resize(ncfft2);
422 int ncfft = ncfft2 << 1;
423 Scalar pi = acos(Scalar(-1));
424 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.