3

I'm trying to fix a program that I found so it takes diferent values than the ones it has as a test to itself. The program should be able to take an array of values that respresent a mathematical function as a signal and the output should be the Fast Fourier Transform to that signal. Here is what I already have fixed in the code:

#include <complex>
#include <iostream>
#include <valarray>

#define fnc(x) (x)

const double PI = 3.141592653589793238460;

typedef std::valarray<double> CArray;

union{
    double d;
    int i;
}num,i;


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)
    {
        double t = std::polar(1.0, -2 * PI * k / N) * odd[k];
        x[k    ] = even[k] + t;
        x[k+N/2] = even[k] - t;
    }
}
    //Complex f = 1.0 / sqrt(N);
    //for (unsigned int i = 0; i < N; i++)
    //  x[i] *= f;

int main()
{
    num.d=513;
    double test[num.i];
    for(i.i=1; i.i < num.i;++i.i)
        test[i.i] = (double)fnc(i.i);
    CArray data(test, num.d);

    // forward fft
    fft(data);

    std::cout << "fft" << std::endl;
    for (i.i = 0; i.i < num.i; ++i.i)
    {
        std::cout << data[i.i] << std::endl;
    }
    return 0;
}

When I try to compile it ti shows me the nect

error: cannot convert 'std::complex' to 'double' in initialization|

on the 34th line, on the line marked in this part:

    for (size_t k = 0; k < N/2; ++k)
    {
        double t = std::polar(1.0, -2 * PI * k / N) * odd[k];
        x[k    ] = even[k] + t;
        x[k+N/2] = even[k] - t;
    }

pesizaly this one:

        double t = std::polar(1.0, -2 * PI * k / N) * odd[k];

If anyone could tell me how to fix it I would be very thakfully. For better references this is the original code, in case anyone could tell me a better way to fix it so it mekes what I want.

#include <complex>
#include <iostream>
#include <valarray>
 
const double PI = 3.141592653589793238460;
 
typedef std::complex<double> Complex;
typedef std::valarray<Complex> 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;
    }
}
 
// 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;
}

Ps. If anyone knows a better code for what I need I could also use it.

  • 1
    use [`M_PI` in math.h](https://stackoverflow.com/q/1727881/995714) instead of defining your own – phuclv Jun 09 '17 at 01:33
  • @phuclv: `math.h` is not part of the C++ standard. The C++ standard library doesn't define a *pi* constant. If including `math.h` leads to an `M_PI` macro defined, you are relying on compiler-specific behaviour. – Cris Luengo Jul 11 '18 at 15:08

2 Answers2

1

std::complex<double> and double are incompatible types.

Change this:

double t = std::polar(1.0, -2 * PI * k / N) * odd[k];

to this:

std::complex<double> t = std::polar(1.0, -2 * PI * k / N) * odd[k];

since std::polar returns:

The complex cartesian equivalent to the polar format formed by rho and theta.

Paul R
  • 208,748
  • 37
  • 389
  • 560
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • thank you, it actualy worked, but now it shows me a new error on the two lines that follow that one: `error: cannot convert 'std::complex' to 'double' in assignment|`. – Felipe Tafoya Loeza Jun 09 '17 at 01:40
  • @FelipeTafoyaLoeza because you used `typedef std::valarray CArray;`, and not something compatible, as using `Complex` instead of `double` for example. Hope that helps! =) – gsamaras Jun 09 '17 at 01:46
0

The error message is pretty explicit: std::polar returns a std::complex, not a double. Looking at the rest of the code, maybe just change the type of t?

Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111