FFTW3,cuFFT和就地变换

时间:2014-03-23 17:01:59

标签: c++ fft fftw

我正在尝试使用FFTW3进行实际到复数的FFT变换。到目前为止,我已经设法使用异地转换来完成它,但是我无法实现它的就地版本。我的印象是,您必须为就地转换更改的唯一事项是:1)确保您的数据阵列有足够的空间来容纳操作的复杂部分,2)当您创建计划时使用相同的输入和输出数据的地址,3)执行计划时,对输入和输出数据使用相同的地址。我已经做了所有这些事情,但我一直得到错误的结果。我正在进行2x2数组的2D FFT,其值为[[1,1],[1,1]]。预期结果(根据Matlab)是2×2阵列,其值为[[4 + 0i,0 + 0i],[0 + 0i,0 + 0i]]。 当我进行不合适的转换时,我得到了这个结果。但是当我进行就地变换时,我得到以下[[2 + 0i,0 + 0i],[2 + 0i,0 + 0i]]。我选择了2x2尺寸的2D FFT,因为输入和输出数据的长度是相同的,它有助于调试。这是我的代码:

bool inplace = true; // true for in-place, false for out-of-place
int dim_size[] = {2,2};
int N[] = {2,2};
int data_length     = N[0]*(N[1]);      //  2 * (2)     = 4
int data_fft_length = N[0]*(N[1]/2+1);  //  2 * (2/2+1) = 4
float* h_data_r = nullptr;              //  fftw data array
fftwf_complex* h_data_c = nullptr;      //  fftw data array (only used in out-of-place tranforms)

//  allocate fftw memory
if(inplace) {
    h_data_r = (float*)fftwf_malloc(data_fft_length*sizeof(fftwf_complex));
    h_data_c = (fftwf_complex*)h_data_r;
} else {
    h_data_r = (float*)fftwf_malloc(data_length*sizeof(float));
    h_data_c = (fftwf_complex*)fftwf_malloc(data_fft_length*sizeof(fftwf_complex));
}

//  create plane
unsigned int flags = FFTW_MEASURE;
fftwf_plan m_plan = fftwf_plan_dft_r2c_2d(N[0],N[1],h_data_r,h_data_c,flags);

//  initialize data array
h_data_r[0] = 1;
h_data_r[1] = 1;
h_data_r[2] = 1;
h_data_r[3] = 1;

//  execute fft plan
fftwf_execute(m_plan);

std::cout << "result:" << std::endl;
for(int i = 0; i < data_fft_length; ++i)
    std::cout << "[" << i << "]: " << h_data_c[i][0] << " " << h_data_c[i][1]  << std::endl;

变量&#39; inplace&#39;如果FFT变换是就地,则需要。有人能告诉我我的代码有什么问题吗?代码非常简单。我没有做任何特别的事。我只想要一个就地FFT实数到复数变换。如果您无法检查我的代码,但是您有一个非常简单的fftw3的就地fft转换代码,请随意复制粘贴它。

谢谢。

编辑1:我进一步简化了代码,现在我使用fftwf_plan_dft_r2c_2d()进行计划创建,使用fftwf_execute()进行计划执行。问题仍然存在。

编辑2:我将代码翻译成了cufft,它应该与fftw3具有几乎相同的语法。我用袖口得到了同样的问题。但默认情况下,cuFFT启用了FFTW兼容模式(CUFFT_COMPATIBILITY_FFTW_PADDING)。如果我使用标志CUFFT_COMPATIBILITY_NATIVE禁用FFTW兼容模式,则就地转换与cuFFT一起工作正常。奇怪的是,根据cuFFT文档,当您进行批量转换时,CUFFT_COMPATIBILITY_FFTW_PADDING应该会有所不同。在我的情况下,我不做任何批量转换。我现在更加困惑。

4 个答案:

答案 0 :(得分:1)

几个月前,我设法解决了这个问题。事实证明我必须使用高级计划创建界面并手动设置inembed和onembed指针的值。

答案 1 :(得分:0)

@ user4120016 指出时,需要填充输入数据。

上面提供的代码使用基本界面打印出来:

  

[[4 + 0i,0 + 0i],[0 + 0i,0 + 0i]]

如果数据被填充,则

用于案例inplace = true

h_data_r[0] = 1;
h_data_r[1] = 1;
h_data_r[2] = 0;
h_data_r[3] = 0;
h_data_r[4] = 1;
h_data_r[5] = 1;
h_data_r[6] = 0;
h_data_r[7] = 0;

答案 2 :(得分:0)

在您的代码中定义fftwf_plan的地方,请改用此代码:

fftwf_plan m_plan;
if (inplace) {
    m_plan = fftwf_plan_many_dft_r2c(2, N, 1,
                                     h_data_r, N,
                                     1, 0,
                                     h_data_c, nullptr,
                                     1, 0,
                                     flags);
} else {
    m_plan = fftwf_plan_dft_r2c_2d(N[0],N[1],h_data_r,h_data_c,flags);
}

我花了一段时间才弄清楚这一点,但我仍然不清楚为什么基本界面无法正常工作。特别是,请阅读FFTW手册中的onembed参数。如果要对转换后的数组使用与基本接口相同的紧凑格式,则此字段必须为null(在这个简单的示例中,对于{{,您可以使用Nnullptr获得相同的结果1}},但总的来说很重要。

答案 3 :(得分:-1)

fftw3实数到复数就地变换需要在变换缓冲区中每行数据末尾填充(参见:http://www.fftw.org/doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data)。 您需要的缓冲区2x2的大小为2 *(2(2/2 + 1))= 2x4(即每行有4个浮点数的2行)。当您从输入中填写此内容时,请记住填充位于每行的末尾,而不是缓冲区的末尾。