FFT algorithms (collection)
ver. 1
#include < complex >
#include < iostream >
#include < valarray >
const double PI = 3.141592653589793238460;
typedef std::complex Complex;
typedef std::valarray CArray;
// Cooley–Tukey FFT (in-place, divide-and-conquer)
// Higher memory requirements and redundancy although more intuitive
void fft(CArray& x)
{
const size_t N = x.size();
if (N <= 1) return;
// divide
CArray even = x[std::slice(0, N/2, 2)];
CArray odd = x[std::slice(1, N/2, 2)];
// conquer
fft(even);
fft(odd);
// combine
for (size_t k = 0; k < N/2; ++k)
{
Complex t = std::polar(1.0, -2 * PI * k / N) * odd[k];
x[k ] = even[k] + t;
x[k+N/2] = even[k] - t;
}
}
// inverse fft (in-place)
void ifft(CArray& x)
{
// conjugate the complex numbers
x = x.apply(std::conj);
// forward fft
fft( x );
// conjugate the complex numbers again
x = x.apply(std::conj);
// scale the numbers
x /= x.size();
}
int main()
{
const Complex test[] = { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 };
CArray data(test, 8);
// forward fft
fft(data);
std::cout << "fft" << std::endl;
for (int i = 0; i < 8; ++i)
{
std::cout << data[i] << std::endl;
}
// inverse fft
ifft(data);
std::cout << std::endl << "ifft" << std::endl;
for (int i = 0; i < 8; ++i)
{
std::cout << data[i] << std::endl;
}
return 0;
}
ver. 2
#include < complex >
#include < iostream >
#include < valarray >
const double PI = 3.141592653589793238460;
typedef std::complex Complex;
typedef std::valarray CArray;
// Cooley-Tukey FFT (in-place, breadth-first, decimation-in-frequency)
// Better optimized but less intuitive
// !!! Warning : in some cases this code make result different from not optimased version above (need to fix bug)
// The bug is now fixed @2017/05/30
void fft(CArray &x)
{
// DFT
unsigned int N = x.size(), k = N, n;
double thetaT = 3.14159265358979323846264338328L / N;
Complex phiT = Complex(cos(thetaT), -sin(thetaT)), T;
while (k > 1)
{
n = k;
k >>= 1;
phiT = phiT * phiT;
T = 1.0L;
for (unsigned int l = 0; l < k; l++)
{
for (unsigned int a = l; a < N; a += n)
{
unsigned int b = a + k;
Complex t = x[a] - x[b];
x[a] += x[b];
x[b] = t * T;
}
T *= phiT;
}
}
// Decimate
unsigned int m = (unsigned int)log2(N);
for (unsigned int a = 0; a < N; a++)
{
unsigned int b = a;
// Reverse bits
b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1));
b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2));
b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4));
b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8));
b = ((b >> 16) | (b << 16)) >> (32 - m);
if (b > a)
{
Complex t = x[a];
x[a] = x[b];
x[b] = t;
}
}
//// Normalize (This section make it not working correctly)
//Complex f = 1.0 / sqrt(N);
//for (unsigned int i = 0; i < N; i++)
// x[i] *= f;
}
// inverse fft (in-place)
void ifft(CArray& x)
{
// conjugate the complex numbers
x = x.apply(std::conj);
// forward fft
fft( x );
// conjugate the complex numbers again
x = x.apply(std::conj);
// scale the numbers
x /= x.size();
}
int main()
{
const Complex test[] = { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 };
CArray data(test, 8);
// forward fft
fft(data);
std::cout << "fft" << std::endl;
for (int i = 0; i < 8; ++i)
{
std::cout << data[i] << std::endl;
}
/*
// inverse fft
ifft(data);
std::cout << std::endl << "ifft" << std::endl;
for (int i = 0; i < 8; ++i)
{
std::cout << data[i] << std::endl;
}
*/
return 0;
}
ver. 3
#include < iostream >
#include < complex >
#define MAX 200
using namespace std;
#define M_PI 3.1415926535897932384
int log2(int N) /*function to calculate the log2(.) of int numbers*/
{
int k = N, i = 0;
while(k) {
k >>= 1;
i++;
}
return i - 1;
}
int check(int n) //checking if the number of element is a power of 2
{
return n > 0 && (n & (n - 1)) == 0;
}
int reverse(int N, int n) //calculating revers number
{
int j, p = 0;
for(j = 1; j <= log2(N); j++) {
if(n & (1 << (log2(N) - j)))
p |= 1 << (j - 1);
}
return p;
}
void ordina(complex* f1, int N) //using the reverse order in the array
{
complex f2[MAX];
for(int i = 0; i < N; i++)
f2[i] = f1[reverse(N, i)];
for(int j = 0; j < N; j++)
f1[j] = f2[j];
}
void transform(complex* f, int N) //
{
ordina(f, N); //first: reverse order
complex *W;
W = (complex *)malloc(N / 2 * sizeof(complex));
W[1] = polar(1., -2. * M_PI / N);
W[0] = 1;
for(int i = 2; i < N / 2; i++)
W[i] = pow(W[1], i);
int n = 1;
int a = N / 2;
for(int j = 0; j < log2(N); j++) {
for(int i = 0; i < N; i++) {
if(!(i & n)) {
complex temp = f[i];
complex Temp = W[(i * a) % (n * a)] * f[i + n];
f[i] = temp + Temp;
f[i + n] = temp - Temp;
}
}
n *= 2;
a = a / 2;
}
free(W);
}
void FFT(complex* f, int N, double d)
{
transform(f, N);
for(int i = 0; i < N; i++)
f[i] *= d; //multiplying by step
}
int main()
{
int n;
// do {
// cout << "specify array dimension (MUST be power of 2)" << endl;
// cin >> n;
// } while(!check(n));
double d;
// cout << "specify sampling step" << endl; //just write 1 in order to have the same results of matlab fft(.)
// cin >> d;
d = 1;
complex vec[MAX];
cout << "specify the array" << endl;
for(int i = 0; i < n; i++) {
cout << "specify element number: " << i << endl;
cin >> vec[i];
}
FFT(vec, n, d);
cout << "...printing the FFT of the array specified" << endl;
for(int j = 0; j < n; j++)
cout << vec[j] << endl;
return 0;
}