简体   繁体   中英

How to perform an in-place FFT using the FFTW3 library?

I would like to perform both r2c and c2r in-place FFT's of a 3D array using the FFTW3 library. The array is of size (Nx,Ny,Nz+2) just enough to store Nx Ny (Nz/2+1) complex numbers. I would like the real (Re) and imaginary (Im) parts of the resulting complex numbers to be stored contiguously in the array, ie Re, Im, Re, Im, Re, Im,..., and so on.

Following the FFTW manual, I guess inefficiently, I came up with the following code:

#include <iostream>
#include <fftw3.h>

int main()
{
    const int Nx {4};
    const int Ny {4};
    const int Nz {4};

    const int n[] = {Nx, Ny, Nz};
    const int inembed[] = {Nx, Ny, Nz+2};
    const int onembed[] = {Nx, Ny, Nz/2+1};

    double tmp[] {0, 1, 2, 3}; // Some garbage input
    double* in = (double*) fftw_malloc( sizeof(double) * Nx*Ny*(Nz+2));
    fftw_complex* out = reinterpret_cast<fftw_complex*>(in);

    fftw_plan r2c_3D_a = fftw_plan_many_dft_r2c(3, n, 1, in, inembed, 1, 0, out, onembed, 1, 0, FFTW_MEASURE);
    fftw_plan c2r_3D_a = fftw_plan_many_dft_c2r(3, n, 1, out, onembed, 1, 0, in, inembed, 1, 0, FFTW_MEASURE);

    // Input array 
    for (int i = 0; i < Nx; i++){
        for (int j = 0; j < Ny; j++){
            for (int k = 0; k < Nz+2; k++){
                unsigned int offset;
                offset = k + (Nz+2) * (j + i * Ny);
                in[offset] = k < Nz ? tmp[k] : 0;
                std::cout << in[offset] << " ";
            }
            std::cout << std::endl;
        }
    }

    // R2C FFT
    fftw_execute_dft_r2c(r2c_3D_a, in, out);

    // Normalization
    for (int i = 0; i < Nx*Ny*(Nz+2); i++){
        in[i] = in[i] / (Nx*Ny*Nz);
    }
    
    // C2R FFT
    //fftw_execute_dft_c2r(c2r_3D_a, out, in);
    

    std::cout << std::endl;
    for (int i = 0; i < Nx; i++){
        for (int j = 0; j < Ny; j++){
            for (int k = 0; k < Nz+2; k++){
                unsigned int offset;
                offset = k + (Nz+2) * (j + i * Ny);
                std::cout << in[offset] << " ";
            }
            std::cout << std::endl;
        }
    }

    fftw_destroy_plan(r2c_3D_a);
    fftw_destroy_plan(c2r_3D_a);
    free(in);

    return 0;
}

Which gives me the expected input:

0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0 
0 1 2 3 0 0

After the r2c FFT each row should contain Nz/2+1 = 3 complex numbers stored as Re, Im, Re, Im, Re, Im. Insted, I get this unexpected output:

1.5 0 -0.5 0.5 -0.5 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0

However, the FFT pair, ie the r2c followed by the c2r transform reconstructs the initial data:

0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0 
0 1 2 3 -0.5 0

Note that the last 2 columns are just the padding and are unused after the transform. Honestly, I'm stuck, can anyone give me a hand with that?

Your “unexpected output” is expected. Your input data is constant in two dimensions, so the output frequencies are zero in those dimensions, except for the DC component. If you change to varying data, you will get non-zero results.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM