3D阵列的1D实数FFT和IFFT

时间:2019-04-03 06:52:54

标签: c fftw

我有一个3D数组,其尺寸为(Nx,Ny,Nz)。

我想使用FFTW3库在z轴上应用实数FFT和IFFT。

在这里,“ z”是变化最快的索引。

我已经使用python使用

编写了相同的功能代码

numpy.fft.rfft和numpy.fft.irfft。完全符合我的预期。

但是太慢了。所以我试图用C语言编写代码。

我试图比较IFFT(FFT(f))和f的结果,其中f是一个任意数组。

我将fft_plan_many_dft_r2c / fft_plan_many_dft_c2r用于前向/后向FFT。

这是我的代码。

(在具有gcc和-lfftw3 -lm选项的Ubuntu 16.04中编译)

#include <stdio.h>
#include <stdlib.h>
#include <fftw3.h>

void rfft_1d_of_3d(int Nx, int Ny, int Nz, double* input, double* output);

int main(){

    double* input;
    double* output;

    int Nx=2, Ny=4, Nz=8;
    int i,j,k,idx;

    input  = (double*) malloc(Nx*Ny*Nz*sizeof(double));
    output = (double*) malloc(Nx*Ny*Nz*sizeof(double));

    for(i=0; i<Nx; i++){
        for(j=0; j<Ny; j++){
            for(k=0; k<Nz; k++){

                idx = k + j*Nz + i*Nz*Ny;
                input[idx] = idx;
                output[idx] = 0.;
            }
        }   
    }   

    rfft_1d_of_3d(Nx, Ny, Nz, input, output);

    for(i=0; i<Nx; i++){
        for(j=0; j<Ny; j++){
            for(k=0; k<Nz; k++){
                idx = k + j*Nz + i*Nz*Ny;
                printf("%f, %f\n", input[idx], output[idx]);
            }
        }
    }   

    return 0;
}

void rfft_1d_of_3d(int Nx, int Ny, int Nz, double* input, double* output){

    int i,j,k,idx;

    // Allocate memory space.
    fftw_complex *FFTz = fftw_alloc_complex(Nx*Ny*(Nz/2+1));

    // Set forward FFTz parameters
    int rankz = 1;
    int nz[] = {Nz};
    const int *inembedz = NULL, *onembedz = NULL;
    int istridez = 1, ostridez = 1;
    int idistz = Nz, odistz= (Nz+2)/2;
    int howmanyz = (Nx*Ny);

    // Setup Forward plans.
    fftw_plan FFTz_for_plan = fftw_plan_many_dft_r2c(rankz, nz, howmanyz, input, inembedz, istridez, idistz, FFTz, onembedz, ostridez, odistz, FFTW_ESTIMATE);

    // Set backward FFTz parameters
    int rankbz = 1;
    int nbz[] = {(Nz+2)/2};
    const int *inembedbz = NULL, *onembedbz = NULL;
    int istridebz = 1, ostridebz = 1;
    int idistbz = (Nz+2)/2, odistbz = Nz;
    int howmanybz = (Nx*Ny);

    // Setup Backward plans.
    fftw_plan FFTz_bak_plan = fftw_plan_many_dft_c2r(rankbz, nbz, howmanybz, FFTz, inembedbz, istridebz, idistbz, output, onembedbz, ostridebz, odistbz, FFTW_ESTIMATE);

    fftw_execute(FFTz_for_plan);
    fftw_execute(FFTz_bak_plan);
    fftw_free(FFTz);

    return;
}

输入和输出结果应该是相同的,但事实并非如此。

输入数组是一个3D数组(Nx = 2,Ny = 4,Nz = 8),

[[[  0.   1.   2.   3.   4.   5.   6.   7.]
  [  8.   9.  10.  11.  12.  13.  14.  15.]
  [ 16.  17.  18.  19.  20.  21.  22.  23.]
  [ 24.  25.  26.  27.  28.  29.  30.  31.]]

 [[ 32.  33.  34.  35.  36.  37.  38.  39.]
  [ 40.  41.  42.  43.  44.  45.  46.  47.]
  [ 48.  49.  50.  51.  52.  53.  54.  55.]
  [ 56.  57.  58.  59.  60.  61.  62.  63.]]]

我将其展平为

[  0.   1.   2.   3.   4.   5.   6.   7.  8.   9.  10.  11.  12.  13.  14.  15. 16.  17.  18.  19.  20.  21.  22.  23. 24.  25.  26.  27.  28.  29.  30.  31. 32.  33.  34.  35.  36.  37.  38.  39. 40.  41.  42.  43.  44.  45.  46.  47. 48.  49.  50.  51.  52.  53.  54.  55. 56.  57.  58.  59.  60.  61.  62.  63.]

我希望输出与输入相同,但实际结果是

0.000000, 12.000000
1.000000, 8.929290
2.000000, 28.256139
3.000000, 35.743861
4.000000, 55.070710
5.000000, 0.000000
6.000000, 0.000000
7.000000, 0.000000
8.000000, 76.000000
9.000000, 72.929290
10.000000, 92.256139
11.000000, 99.743861
12.000000, 119.070710
13.000000, 0.000000
14.000000, 0.000000
15.000000, 0.000000
16.000000, 140.000000
17.000000, 136.929290
18.000000, 156.256139
19.000000, 163.743861
20.000000, 183.070710
21.000000, 0.000000
22.000000, 0.000000
23.000000, 0.000000
24.000000, 204.000000
25.000000, 200.929290
26.000000, 220.256139
27.000000, 227.743861
28.000000, 247.070710
29.000000, 0.000000
30.000000, 0.000000
31.000000, 0.000000
32.000000, 268.000000
33.000000, 264.929290
34.000000, 284.256139
35.000000, 291.743861
36.000000, 311.070710
37.000000, 0.000000
38.000000, 0.000000
39.000000, 0.000000
40.000000, 332.000000
41.000000, 328.929290
42.000000, 348.256139
43.000000, 355.743861
44.000000, 375.070710
45.000000, 0.000000
46.000000, 0.000000
47.000000, 0.000000
48.000000, 396.000000
49.000000, 392.929290
50.000000, 412.256139
51.000000, 419.743861
52.000000, 439.070710
53.000000, 0.000000
54.000000, 0.000000
55.000000, 0.000000
56.000000, 460.000000
57.000000, 456.929290
58.000000, 476.256139
59.000000, 483.743861
60.000000, 503.070710
61.000000, 0.000000
62.000000, 0.000000
63.000000, 0.000000

左边的是输入数组的元素,右边的是输出数组的元素。

我在哪里弄错了?

1 个答案:

答案 0 :(得分:1)

对于angular.min.jsfftw_plan_many_dft_c2r(),将转换的大小设置为nbz,即实际输出数组的大小。 Nz可能与此类似。

fftw_plan_dft_c2r_1d()

由于FFTW变换使用// Set backward FFTz parameters int rankbz = 1; int nbz[1] = {(Nz)}; // here !!! const int *inembedbz = NULL, *onembedbz = NULL; //int inembedbz[1]={Nz/2+1}; //int onembedbz[1]={Nz}; int istridebz = 1, ostridebz = 1; int idistbz = (Nz/2+1), odistbz = (Nz); int howmanybz = (Nx*Ny); // Setup Backward plans. fftw_plan FFTz_bak_plan = fftw_plan_many_dft_c2r(rankbz, nbz, howmanybz, FFTz, inembedbz, istridebz, idistbz, output, onembedbz, ostridebz, odistbz, FFTW_ESTIMATE); input数组,因此建议使用output或类似的函数来分配它们,就像您对fftw_malloc()所做的那样。这些功能可确保满足有关内存对齐的要求。请参阅fftw-3.3.6-pl2 / kernel / kalloc.c中的函数FFTz。它会调用诸如memalign()_aligned_malloc()之类的函数。发生故障时,这两个都像*X(kernel_malloc)(size_t n)一样返回NULL

存在规模差异。实际上,链接长度为malloc()的前向和后向FFTW变换会导致缩放比例为Nz

最后,某些FFTW转换(例如c2r)被允许覆盖其输入数组,除非添加了flag FFTW_PRESERVE_INPUT

  

FFTW_PRESERVE_INPUT指定不适当的变换不得更改其输入数组。除c2r和hc2r(即复数到实数)转换的默认值是FFTW_DESTROY_INPUT之外,这通常是默认值。在后一种情况下,传递FFTW_PRESERVE_INPUT将尝试使用不会破坏输入的算法,但代价是性能会变差。但是,对于多维c2r转换,未实现任何保留输入的算法,如果请求一个,计划器将返回NULL。