I have a small and weak microcontroller. I also don't have access to the complex library. I wrote this iterative version of the FFT to hopefully get better performance than the recursive version, and also just to learn how the FFT works, and brush up on C.
I'd like to know if the code itself is understandable, and if there are some performance improvements I can make.
#include <stdio.h>
#include <math.h>
#define FALSE 0
#define TRUE 1
#if !defined(M_PI)
# define M_PI 3.14159265358979323846
#endif
struct complex {
double real;
double imaj;
};
typedef struct complex complex_t;
complex_t complex_init(const double real, const double imaj) {
complex_t temp;
temp.real = real;
temp.imaj = imaj;
return temp;
}
complex_t complex_add(const complex_t a, const complex_t b)
{
return complex_init(a.real + b.real, a.imaj + b.imaj);
}
complex_t complex_subtract(const complex_t a, const complex_t b) {
return complex_init(a.real - b.real, a.imaj - b.imaj);
}
complex_t complex_multiply(const complex_t a, const complex_t b) {
return complex_init(a.real * b.real - a.imaj * b.imaj, a.real * b.imaj + a.imaj * b.real);
}
_Bool is_power_of_2(const unsigned int x) {
return x != 0 && (x & (x - 1)) == 0;
}
_Bool fft(complex_t* input, complex_t* output, const unsigned int size) {
if (!is_power_of_2(size))
return FALSE;
if (size == 1) {
output[0] = input[0];
return TRUE;
}
const unsigned int half_size = size / 2;
// Initial loop. Do the input shuffle and first butterfly at the same time.
// shuffle is the bit reversed representation of i. If i is 11000, then shuffle is 00011.
for (unsigned int skip = size, i = 0, shuffle = 0; i < half_size; ++i) {
const complex_t even = input[shuffle];
const complex_t odd = input[shuffle + half_size];
output[i * 2] = complex_add(even, odd);
output[i * 2 + 1] = complex_subtract(even, odd);
if (i == 0 || is_power_of_2(i + 1)) {
skip /= 2;
shuffle = skip / 2;
} else
shuffle += skip;
}
// Do the rest of the butterfly operations
for (unsigned int even_to_odd = 2; even_to_odd < size; even_to_odd *= 2) {
const double angle = -M_PI / even_to_odd;
const complex_t partial_rotation = complex_init(cos(angle), sin(angle));
complex_t current_rotation = complex_init(1, 0);
for (unsigned int i = 0, to_even = 0; i < half_size; ++i, ++ to_even) {
if (i % even_to_odd == 0) {
to_even = 2 * i;
current_rotation = complex_init(1, 0);
}
complex_t* even = output + to_even;
complex_t* odd = even + even_to_odd;
const complex_t odd_rotated = complex_multiply(*odd, current_rotation);
*odd = complex_subtract(*even, odd_rotated);
*even = complex_add(*even, odd_rotated);
current_rotation = complex_multiply(current_rotation, partial_rotation);
}
}
return TRUE;
}
stdbool.h
\$\endgroup\$