我正在尝试使用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应该会有所不同。在我的情况下,我不做任何批量转换。我现在更加困惑。
答案 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(在这个简单的示例中,对于{{,您可以使用N
或nullptr
获得相同的结果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行)。当您从输入中填写此内容时,请记住填充位于每行的末尾,而不是缓冲区的末尾。