使用带有零填充的英特尔MKL进行3D FFT

时间:2014-12-06 07:36:52

标签: c++ c 3d fft intel-mkl

我想使用 FFT元素的数组的Intel MKL来计算3D 300×200×200。此3D数组以列式方式存储为double类型的一维数组:

for( int k = 0; k < nk; k++ ) // Loop through the height.
    for( int j = 0; j < nj; j++ ) // Loop through the rows.
        for( int i = 0; i < ni; i++ ) // Loop through the columns.
        {
            ijk = i + ni * j + ni * nj * k;
            my3Darray[ ijk ] = 1.0;
        }

我想对输入数组执行not-in-place FFT并防止它被修改(我需要稍后在我的代码中使用它)然后执行反向计算in-place。我也希望零填充。

我的问题是:

  1. 如何执行零填充?
  2. 如果计算中包含零填充,我应该如何处理FFT函数使用的数组的大小?
  3. 如何取出零填充结果并获得实际结果?
  4. 以下是我对此问题的尝试,对于任何评论,建议或暗示,我都会非常感谢

    #include <stdio.h>
    #include "mkl.h"
    
    int max(int a, int b, int c)
    {
         int m = a;
         (m < b) && (m = b); 
         (m < c) && (m = c); 
         return m;
    }
    
    void FFT3D_R2C( // Real to Complex 3D FFT.
        double *in, int nRowsIn , int nColsIn , int nHeightsIn ,
        double *out )
    {    
        int n  = max( nRowsIn , nColsIn , nHeightsIn  );
        // Round up to the next highest power of 2.
        unsigned int N = (unsigned int) n; // compute the next highest power of 2 of 32-bit n.
        N--;
        N |= N >> 1;
        N |= N >> 2;
        N |= N >> 4;
        N |= N >> 8;
        N |= N >> 16;
        N++;
    
        /* Strides describe data layout in real and conjugate-even domain. */
        MKL_LONG rs[4], cs[4];
    
        // DFTI descriptor.
        DFTI_DESCRIPTOR_HANDLE fft_desc = 0;
    
        // Variables needed for out-of-place computations.
        MKL_Complex16 *in_fft  = new MKL_Complex16 [ N*N*N ];
        MKL_Complex16 *out_fft = new MKL_Complex16 [ N*N*N ];
        double *out_ZeroPadded = new double [ N*N*N ];
    
        /* Compute strides */
        rs[3] = 1;           cs[3] = 1;
        rs[2] = (N/2+1)*2;   cs[2] = (N/2+1);
        rs[1] = N*(N/2+1)*2; cs[1] = N*(N/2+1);
        rs[0] = 0;           cs[0] = 0;
    
        // Create DFTI descriptor.
        MKL_LONG sizes[] = { N, N, N };
        DftiCreateDescriptor( &fft_desc, DFTI_DOUBLE, DFTI_REAL, 3, sizes );
    
        // Configure DFTI descriptor.
        DftiSetValue( fft_desc, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX );
        DftiSetValue( fft_desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE  ); // Out-of-place transformation.
        DftiSetValue( fft_desc, DFTI_INPUT_STRIDES  , rs  );
        DftiSetValue( fft_desc, DFTI_OUTPUT_STRIDES , cs  );
    
        DftiCommitDescriptor( fft_desc );
        DftiComputeForward  ( fft_desc, in , in_fft  );
    
        // Change strides to compute backward transform.
        DftiSetValue        ( fft_desc, DFTI_INPUT_STRIDES , cs);
        DftiSetValue        ( fft_desc, DFTI_OUTPUT_STRIDES, rs);
        DftiCommitDescriptor( fft_desc );
        DftiComputeBackward ( fft_desc, out_fft, out_ZeroPadded );
    
        // Printing the zero padded 3D FFT result.
        for( long long i = 0; i < (long long)N*N*N; i++ )
            printf("%f\n", out_ZeroPadded[i] );
    
        /* I don't know how to take out the zero padded results and 
           save the actual result in the variable named "out" */
    
        DftiFreeDescriptor  ( &fft_desc );
    
        delete[] in_fft;
        delete[] out_ZeroPadded ;
    }
    
    int main()
    {
        int n = 10;
    
        double *a    = new double [n*n*n]; // This array is real.
        double *afft = new double [n*n*n]; 
    
        // Fill the array with some 'real' numbers.
        for( int i = 0; i < n*n*n; i++ )
            a[ i ] = 1.0;
    
        // Calculate FFT.
        FFT3D_R2C( a, n, n, n, afft );
    
        printf("FFT results:\n");
        for( int i = 0; i < n*n*n; i++ )
            printf( "%15.8f\n", afft[i] );
    
        delete[] a;
        delete[] afft;
    
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

只有几点提示:

  1. 2大小的力量

    • 我不喜欢你计算尺寸的方式
    • 所以让Nx,Ny,Nz为输入矩阵的大小
    • 填充矩阵的
    • nx,ny,nz大小

      for (nx=1;nx<Nx;nx<<=1);
      for (ny=1;ny<Ny;ny<<=1);
      for (nz=1;nz<Nz;nz<<=1);
      
    • 现在将memset零填充为零,然后复制矩阵线

    • 填充到N^3而不是nx*ny*nz会导致大幅减速
    • 如果nx,ny,nz彼此不相近
  2. 输出很复杂

    • 如果我做对了a是输入实矩阵
    • afft输出复杂矩阵
    • 那么为什么不正确分配空间?
    • double *afft = new double [2*nx*ny*nz];
    • 复数是实数+虚数部分,因此每个数字2个值
    • 也适用于结果的最终打印
    • 以及一些"\r\n"行之后可以查看
  3. 3D DFFT

    • 我不使用也不知道你的DFFT库
    • 我自己使用,但无论如何3D DFFT可以通过1D DFFT
    • 完成
    • 如果您按行进行...请参阅此2D DFCT by 1D DFFT
    • 3D中的
    • 是相同的,但您需要添加一个通道和不同的标准化常量
    • 这样你可以拥有单行缓冲区double lin[2*max(nx,ny,nz)];
    • 并在运行中进行零填充(因此无需在内存中使用更大的矩阵)...
    • 但这涉及应对每个1D DFFT的线路......