C++ 使用FFTW仅转换到频域并返回,得到与源极不相同的结果
在我的测试用例中,我使用FFTW只是将图像转换为频域,然后再转换回空域。但我最终得到的结果与我最初得到的结果大不相同 要解决一些问题,请执行以下操作:C++ 使用FFTW仅转换到频域并返回,得到与源极不相同的结果,c++,signal-processing,fft,fftw,C++,Signal Processing,Fft,Fftw,在我的测试用例中,我使用FFTW只是将图像转换为频域,然后再转换回空域。但我最终得到的结果与我最初得到的结果大不相同 要解决一些问题,请执行以下操作: 我之所以在每次调用fft()和ifft()时创建FFTW计划,而不是缓存它们,是为了简单。这应该不是问题 为了简单起见,我在将实值数组传递给fftw之前将其转换为复数数组。我发现这种方法比使用实数到复数的DFT函数更难出错 我的代码(包括实用函数、宏和类)如下所示。它使用libcinder(its的一个旧版本)来表示向量类和图形,但即使您不知
- 我之所以在每次调用
和fft()
时创建FFTW计划,而不是缓存它们,是为了简单。这应该不是问题ifft()
- 为了简单起见,我在将实值数组传递给fftw之前将其转换为复数数组。我发现这种方法比使用实数到复数的DFT函数更难出错
backAndForthed=backAndForth(已加载)代码>行,结果是正确的(因此,结果只有第一次是错误的)。问题在于:
auto plan = fftwf_plan_dft_2d(in.h, in.w,
(fftwf_complex*)in_complex.data, (fftwf_complex*)result.data,
FFTW_FORWARD, FFTW_MEASURE);
fftwf_execute(plan);
在那里:
auto plan = fftwf_plan_dft_2d(in.h, in.w,
(fftwf_complex*)in.data, (fftwf_complex*)result.data,
FFTW_BACKWARD, FFTW_MEASURE);
fftwf_execute(plan);
使用标志FFTW\u MEASURE
意味着FFTW会尝试许多DFT算法来选择最快的算法。问题是.data
中的输入数组在传输过程中被覆盖。因此,在fftwf_执行(计划)之后代码>,结果.data
与创建计划之前不同,不是.data
中的的DFT。根据FFTW在以下方面的文件:
重要提示:计划器会在计划期间覆盖输入数组,除非已保存的计划(请参阅WITH)可用于解决该问题,因此您应该在创建计划后初始化输入数据。唯一的例外是FFTW\u估计值
和FFTW\u仅
标志,如下所述
该文档提供了一个解决方案:使用标志FFTW\u ESTIMATE
可确保在规划期间不会覆盖输入/输出数组。
在这种特殊情况下,使用FFTW_估计值
而不是FFTW_度量值
预计不会导致计算时间大幅增加。事实上,由于在计划创建过程中计算了许多DFT,因此使用fftw\u度量值创建fftw\u计划将比使用fftw\u估计值创建fftw\u计划慢得多。但是,如果要执行多个相同大小的DFT,则必须使用FFTW_MEASURE
一次性创建并存储计划。如有必要,可以使用
我的猜测是,您可能已经知道r2c和c2r转换,它们旨在将存储空间和计算时间减少近2。缓冲区结果的内存。如果未调用Init
,则不会分配数据。此外,使用标志FFTW\u MEASURE
可以修改complex.data
或.data
中的输入缓冲区:您是否可以尝试使用标志FFTW\u ESTIMATE
?见@francis:谢谢。不过,我在所有情况下都会调用Init——请查看我在初始化列表中传递给deleter
的构造函数的内容。使用FFTW\u ESTIMATE
确实解决了这个问题,但我认为这是一个随机(不太可靠)的解决方案,因为:即使FFTW\u MEASURE
覆盖了输入缓冲区,那也没关系-fft()
的输入缓冲区在最后被ifft()
的返回值覆盖,而ifft
的输入缓冲区是一个本地缓冲区,在传递到ifft
后会被丢弃。没错,Init()
在所有情况下都会被调用。对不起。。。但是,如果使用了FFTW\u MEASURE
,则在调用fftwf\u execute(plan)
之前,可以修改复杂数据中的输入数组。类似地,在ifft()
中也会发生同样的情况:in。在调用fftwf\u execute(plan)
之前,可以修改数据。因此,fftw\u执行(计划)
后的result.data
不是创建fftw\u计划之前存在的in.data
的DFT。我不知道这是否是这里唯一的问题,但这似乎是一个潜在的解释,说明ifft不是fft的逆。@francis:好吧,这很有道理。我还找到了你所说的参考资料。Quote:“除非保存的计划(请参阅WITH)可用于解决该问题,否则计划器将在计划期间覆盖输入数组,因此您应该在创建计划后初始化输入数据。唯一的例外是来自的FFTW_估计和FFTW_WITH_only标志[…]。我通过在创建计划时传递虚拟数组(具有正确的大小、类型、变换方向等)来解决这个问题,然后使用fftw的“新数组执行函数”。@francis:因此,即使使用fftw\u MEASURE
标志,我也能使它正常工作。请将您的解决方案作为答案发布,以便我可以接受。
array 'source' has sum 31397
array 'backAndForthed' has sum -0.110077
auto plan = fftwf_plan_dft_2d(in.h, in.w,
(fftwf_complex*)in_complex.data, (fftwf_complex*)result.data,
FFTW_FORWARD, FFTW_MEASURE);
fftwf_execute(plan);
auto plan = fftwf_plan_dft_2d(in.h, in.w,
(fftwf_complex*)in.data, (fftwf_complex*)result.data,
FFTW_BACKWARD, FFTW_MEASURE);
fftwf_execute(plan);