20 #if defined(ARDUINO) && !defined(ESP32)
21 #define CTFFT_MINIMAL 1
23 #define CTFFT_MAXBITS 8
28 #define READ_COS(x) pgm_read_float(&(x))
32 #define CTFFT_MINIMAL 0
40 #ifndef HAVE_TYPE_TRAITS
42 #define HAVE_TYPE_TRAITS 1
47 #include <type_traits>
50 #if defined(__GNUC__) && defined(ESP32)
51 #if !__GNUC_PREREQ(8,4)
52 #define GCC_OPTIMIZER_BUG
58 #ifndef CTFFT_COMPILETIME
59 #if defined(__GNUC__) && __cplusplus >= 201300
60 #define CTFFT_COMPILETIME
72 #define CTFFT_MAXBITS 19
77 constexpr
long double pi = 3.1415926535897932384626433832795028841972L;
78 constexpr
long double sqrt1_2 = 1.4142135623730950488016887242096980785697L/2;
80 constexpr
unsigned log2(
unsigned x)
82 return (x == 1) ? 0 :
log2(x >> 1) + 1;
85 #ifdef CTFFT_COMPILETIME
86 #define CTFFT_COSTABLE_CONSTRUCTOR constexpr Data():sample
87 #define CTFFT_COSTABLE_CONSTEXPR constexpr
89 #define CTFFT_COSTABLE_CONSTRUCTOR Data
90 #define CTFFT_COSTABLE_CONSTEXPR
93 template<
typename T,
unsigned nbits>
97 static_assert(std::is_floating_point<T>(),
"Only floating point supported");
99 static_assert(nbits >= 4 && nbits <=
CTFFT_MAXBITS,
"Number of bits not supported");
101 template<
unsigned NUMBITS>
104 static constexpr
unsigned size = 1<<NUMBITS;
109 constexpr
long double freq = 2*
pi/
size;
110 for (
unsigned i = 0; i <=
size / 4; i++)
112 for (
unsigned i = 1; i <
size / 4; i++)
118 static const T*
get(
unsigned i)
121 #if CTFFT_MAXBITS >= 4
122 static const T costable4[16]
PROGMEM = {
123 1, 0.92388, 0.707107, 0.382683, -2.50828e-20, 0.382683, 0.707107, 0.92388
126 #if CTFFT_MAXBITS >= 5
127 static const T costable5[32]
PROGMEM = {
128 1, 0.980785, 0.92388, 0.83147, 0.707107, 0.55557, 0.382683, 0.19509, -2.50828e-20,
129 0.19509, 0.382683, 0.55557, 0.707107, 0.83147, 0.92388, 0.980785
132 #if CTFFT_MAXBITS >= 6
133 static const T costable6[64]
PROGMEM = {
134 1, 0.995185, 0.980785, 0.95694, 0.92388, 0.881921, 0.83147, 0.77301, 0.707107,
135 0.634393, 0.55557, 0.471397, 0.382683, 0.290285, 0.19509, 0.0980171, -2.50828e-20,
136 0.0980171, 0.19509, 0.290285, 0.382683, 0.471397, 0.55557, 0.634393, 0.707107,
137 0.77301, 0.83147, 0.881921, 0.92388, 0.95694, 0.980785, 0.995185
140 #if CTFFT_MAXBITS >= 7
141 static const T costable7[128]
PROGMEM = {
142 1, 0.998795, 0.995185, 0.989177, 0.980785, 0.970031, 0.95694, 0.941544, 0.92388,
143 0.903989, 0.881921, 0.857729, 0.83147, 0.803208, 0.77301, 0.740951, 0.707107,
144 0.671559, 0.634393, 0.595699, 0.55557, 0.514103, 0.471397, 0.427555, 0.382683,
145 0.33689, 0.290285, 0.24298, 0.19509, 0.14673, 0.0980171, 0.0490677, -2.50828e-20,
146 0.0490677, 0.0980171, 0.14673, 0.19509, 0.24298, 0.290285, 0.33689, 0.382683,
147 0.427555, 0.471397, 0.514103, 0.55557, 0.595699, 0.634393, 0.671559, 0.707107,
148 0.740951, 0.77301, 0.803208, 0.83147, 0.857729, 0.881921, 0.903989, 0.92388,
149 0.941544, 0.95694, 0.970031, 0.980785, 0.989177, 0.995185, 0.998795
152 #if CTFFT_MAXBITS >= 8
153 static const T costable8[256]
PROGMEM = {
154 1, 0.999699, 0.998795, 0.99729, 0.995185, 0.99248, 0.989177, 0.985278, 0.980785,
155 0.975702, 0.970031, 0.963776, 0.95694, 0.949528, 0.941544, 0.932993, 0.92388,
156 0.91421, 0.903989, 0.893224, 0.881921, 0.870087, 0.857729, 0.844854, 0.83147,
157 0.817585, 0.803208, 0.788346, 0.77301, 0.757209, 0.740951, 0.724247, 0.707107,
158 0.689541, 0.671559, 0.653173, 0.634393, 0.615232, 0.595699, 0.575808, 0.55557,
159 0.534998, 0.514103, 0.492898, 0.471397, 0.449611, 0.427555, 0.405241, 0.382683,
160 0.359895, 0.33689, 0.313682, 0.290285, 0.266713, 0.24298, 0.219101, 0.19509,
161 0.170962, 0.14673, 0.122411, 0.0980171, 0.0735646, 0.0490677, 0.0245412,
162 -2.50828e-20, 0.0245412, 0.0490677, 0.0735646, 0.0980171, 0.122411, 0.14673,
163 0.170962, 0.19509, 0.219101, 0.24298, 0.266713, 0.290285, 0.313682, 0.33689,
164 0.359895, 0.382683, 0.405241, 0.427555, 0.449611, 0.471397, 0.492898, 0.514103,
165 0.534998, 0.55557, 0.575808, 0.595699, 0.615232, 0.634393, 0.653173, 0.671559,
166 0.689541, 0.707107, 0.724247, 0.740951, 0.757209, 0.77301, 0.788346, 0.803208,
167 0.817585, 0.83147, 0.844854, 0.857729, 0.870087, 0.881921, 0.893224, 0.903989,
168 0.91421, 0.92388, 0.932993, 0.941544, 0.949528, 0.95694, 0.963776, 0.970031,
169 0.975702, 0.980785, 0.985278, 0.989177, 0.99248, 0.995185, 0.99729, 0.998795, 0.999699
174 #if CTFFT_MAXBITS >= 4
178 #if CTFFT_MAXBITS >= 5
182 #if CTFFT_MAXBITS >= 6
186 #if CTFFT_MAXBITS >= 7
190 #if CTFFT_MAXBITS >= 8
198 static const T* tables[nbits-3];
199 if (i-4 >=
sizeof(tables)/
sizeof(tables[0]))
201 #define DECLARE_COSTABLE(nb) \
202 if (nbits >= nb && !tables[nb-4]) \
204 static const CTFFT_COSTABLE_CONSTEXPR Data<nb> table_ = Data<nb>(); \
205 tables[nb-4] = table_.sample; \
208 #if CTFFT_MAXBITS >= 5
211 #if CTFFT_MAXBITS >= 7
214 #if CTFFT_MAXBITS >= 7
217 #if CTFFT_MAXBITS >= 8
220 #if CTFFT_MAXBITS >= 9
223 #if CTFFT_MAXBITS >= 10
226 #if CTFFT_MAXBITS >= 11
229 #if CTFFT_MAXBITS >= 12
232 #if CTFFT_MAXBITS >= 13
235 #if CTFFT_MAXBITS >= 14
238 #if CTFFT_MAXBITS >= 15
241 #if CTFFT_MAXBITS >= 16
244 #if CTFFT_MAXBITS >= 17
247 #if CTFFT_MAXBITS >= 18
250 #if CTFFT_MAXBITS >= 19
253 #if CTFFT_MAXBITS >= 20
256 #if CTFFT_MAXBITS >= 21
259 #if CTFFT_MAXBITS >= 22
262 #if CTFFT_MAXBITS >= 23
265 #if CTFFT_MAXBITS >= 24
268 #undef DECLARE_COSTABLE
274 #undef CTFFT_COSTABLE_CONSTRUCTOR
275 #undef CTFFT_COSTABLE_CONSTEXPR
284 template<
typename T,
unsigned SIZE,
typename CT>
289 inverse(inverseTransform)
291 unsigned n = 1 << nbits;
292 for (
unsigned i = 0; i < n; i++)
293 rev[-split_radix_permutation(i, n, inverse) & (n - 1)] = i;
298 unsigned np = 1 << nbits;
299 for (
unsigned i = 0; i < np; i++)
300 tmp[rev[i]] = data[i];
301 for (
unsigned i = 0; i < np; i++)
307 dispatch(nbits)(data, nbits);
311 typedef void (*FFT)(
Complex<T>* data,
unsigned nbits);
312 static constexpr
int nbits =
log2(SIZE);
318 const T* tcos = CT::get(nbits);
319 const T* tsin = tcos + (SIZE >> 2);
321 static int split_radix_permutation(
int i,
int n,
int inverse)
328 return split_radix_permutation(i, m, inverse) * 2;
330 if (inverse == !(i&m))
331 return split_radix_permutation(i, m, inverse) * 4 + 1;
332 return split_radix_permutation(i, m, inverse) * 4 - 1;
335 #define BF(x, y, a, b) do { \
340 #define CMUL(dre, dim, are, aim, bre, bim) do { \
341 (dre) = (are) * (bre) - (aim) * (bim); \
342 (dim) = (are) * (bim) + (aim) * (bre); \
345 #define BUTTERFLIES(a0,a1,a2,a3) {\
347 BF(a2.real, a0.real, a0.real, t5);\
348 BF(a3.img, a1.img, a1.img, t3);\
350 BF(a3.real, a1.real, a1.real, t4);\
351 BF(a2.img, a0.img, a0.img, t6);\
357 #define BUTTERFLIES_BIG(a0,a1,a2,a3) {\
358 T r0=a0.real, i0=a0.img, r1=a1.real, i1=a1.img;\
360 BF(a2.real, a0.real, r0, t5);\
361 BF(a3.img, a1.img, i1, t3);\
363 BF(a3.real, a1.real, r1, t4);\
364 BF(a2.img, a0.img, i0, t6);\
367 #define TRANSFORM(a0,a1,a2,a3,wre,wim) {\
368 CMUL(t1, t2, a2.real, a2.img, wre, -wim);\
369 CMUL(t5, t6, a3.real, a3.img, wre, wim);\
370 BUTTERFLIES(a0,a1,a2,a3)\
373 #define TRANSFORM_ZERO(a0,a1,a2,a3) {\
378 BUTTERFLIES(a0,a1,a2,a3)\
381 static void fft4(Complex<T>* z,
unsigned n)
386 T t1, t2, t3, t4, t5, t6, t7, t8;
388 BF(t3, t1, z[0].real, z[1].real);
389 BF(t8, t6, z[3].real, z[2].real);
390 BF(z[2].real, z[0].real, t1, t6);
391 BF(t4, t2, z[0].img, z[1].img);
392 BF(t7, t5, z[2].img, z[3].img);
393 BF(z[3].img, z[1].img, t4, t8);
394 BF(z[3].real, z[1].real, t3, t7);
395 BF(z[2].img, z[0].img, t2, t5);
398 static void fft8(Complex<T>* z,
unsigned n)
403 T t1, t2, t3, t4, t5, t6;
407 BF(t1, z[5].real, z[4].real, -z[5].real);
408 BF(t2, z[5].img, z[4].img, -z[5].img);
409 BF(t5, z[7].real, z[6].real, -z[7].real);
410 BF(t6, z[7].img, z[6].img, -z[7].img);
416 static void fft16(Complex<T>* z,
unsigned n)
421 T t1, t2, t3, t4, t5, t6;
422 const T* cos16 = CT::get(4);
432 TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3);
433 TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1);
435 #ifdef GCC_OPTIMIZER_BUG
436 #pragma GCC optimize ("O0")
438 static void pass(Complex<T> *z,
const T* wre,
unsigned int n)
440 T t1, t2, t3, t4, t5, t6;
444 const T* wim = wre+o1;
459 #ifdef GCC_OPTIMIZER_BUG
460 #pragma GCC optimize ("Os")
463 #ifndef CTFFT_MINIMAL
465 #define BUTTERFLIES BUTTERFLIES_BIG
467 static void passBig(Complex<T> *z,
const T* wre,
unsigned int n)
469 T t1, t2, t3, t4, t5, t6;
473 const T* wim = wre+o1;
477 TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);
483 TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);
484 TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);
490 static void fft(Complex<T>* z,
unsigned n)
492 unsigned n4 = (1<<(n-2));
493 dispatch(n-1)(z, n-1);
494 dispatch(n-2)(z+n4*2, n-2);
495 dispatch(n-2)(z+n4*3, n-2);
496 #ifndef CTFFT_MINIMAL
498 passBig(z, CT::get(n), n4/2);
501 pass(z, CT::get(n), n4/2);
504 static FFT dispatch(
unsigned n)
511 return (n-2 <
sizeof(opt)/
sizeof(opt[0])) ? opt[n-2] : fft;
517 #undef BUTTERFLIES_BIG
519 #undef TRANSFORM_ZERO
522 template<
typename T,
unsigned SIZE>
545 const int n = 1 <<
nbits;
546 const float k1 = 0.5;
547 const float k2 = 0.5 -
inverse;
560 data[0] = ev.
real + data[1];
561 data[1] = ev.
real - data[1];
564 #define RDFT_UNMANGLE(sign0, sign1) \
565 for (i = 1; i < (n>>2); i++) \
570 ev.real = k1*(data[i1 ]+data[i2 ]); \
571 od.img = k2*(data[i2 ]-data[i1 ]); \
572 ev.img = k1*(data[i1+1]-data[i2+1]); \
573 od.real = k2*(data[i1+1]+data[i2+1]); \
575 odsum.real = od.real* READ_COS(tcos[i]) sign0 od.img * READ_COS(tsin[i]);\
576 odsum.img = od.img * READ_COS(tcos[i]) sign1 od.real* READ_COS(tsin[i]);\
577 data[i1 ] = ev.real + odsum.real; \
578 data[i1+1] = ev.img + odsum.img; \
579 data[i2 ] = ev.real - odsum.real; \
580 data[i2+1] = odsum.img - ev.img; \