如何将FFTW与Eigen库一起使用



我正在尝试学习如何使用带有Eigen的FFTW库。我不想使用Eigen不受支持的模块,因为我最终希望将FFTW的智慧功能融入到我的代码中。然而,我正在努力实现一个非常基本的示例。这是我到目前为止的代码:

void fft(Eigen::Ref<Eigen::VectorXcd> inVec, int N) {
fftw_complex *in, *out;
fftw_plan p;
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
p = fftw_plan_dft_1d(N, in, in, FFTW_FORWARD, FFTW_ESTIMATE);
in = reinterpret_cast<fftw_complex*>(inVec.data());
fftw_execute(p);
fftw_destroy_plan(p);
// reassign input back to inVec here
fftw_free(in); fftw_free(out);
}

这基本上是从fftw文档的第2.1章中复制的。文档似乎说它的基本接口不能在不同的数据集上操作,但您也必须在创建计划后初始化数据。我不明白这一点。为什么不简单地用新数据覆盖第一次初始化的数据,然后再次执行计划?

此外,我曾尝试将特征向量转换为fftw_complex,但我怀疑我在这里犯了一个错误。在Eigen不支持的FFTW模块中,还有一个const_cast调用。为什么会出现这种情况?既然我的基础数据在这里不是常量,那么这有必要吗?

最后,如果in是指向fftw_complex数据的指针,我如何将其重新分配给我的inVec,然后释放in

我不明白这一点。为什么不简单地用新数据覆盖第一次初始化的数据,然后再次执行计划?

是的,这正是fftw希望你做的。in = reinterpret_cast<fftw_complex*>(inVec.data());行只是设置了一个指针。它不会复制数组。您需要记住内容,即memcpy(in, invec.data(), N * sizeof(fftw_complex));

你想要的(这在FFTW文档中有些隐藏(是";新数组执行函数";它允许您为调用指定不同的数组。但是,请注意文档中的这一行:

对齐问题尤其关键,因为如果不使用fftw_malloc,则可能无法控制内存中数组的对齐。例如,C++新函数和Fortran allocate语句都没有为数据对齐提供足够强的保证。因此,如果不使用fftw_malloc,则可能必须使用fftw_UNALIGNED(禁用大多数SIMD支持(。如果可能的话,您最好简单地创建多个计划(对于给定的大小,一旦存在一个新计划,就可以快速创建一个新的计划(,或者更好地为您的转换重复使用相同的数组。

当您使用Eigen时,这可能不是问题,因为Eigen还会对齐其数组。GCC也使用16字节对齐,所以即使在调用malloc时,您也可能很好,但这取决于您的平台。不过,函数接口不能保证对齐,因为Eigen::Ref可能是较大数组的一段。但您可以在运行时进行检查。类似这样的东西:

unsigned flags = FFTW_ESTIMATE;
if(reinterpret_cast<size_t>(invec.data()) % 16)
flags |=  FFTW_UNALIGNED;
p = fftw_plan_dft_1d(..., flags);

关于矢量化丢失的警告可能已经过时。正确的对齐在今天并不那么重要(尤其是在任何支持AVX的设备上(,我怀疑(但尚未验证(FFTW也会通过未对齐的内存访问进行矢量化。

旁注:在p = fftw_plan_dft_1d(N, in, in, FFTW_FORWARD, FFTW_ESTIMATE);行中,第三个参数应该是out,而不是In;除非您想要就地转换,在这种情况下,您不需要分配out数组。

编辑:对齐检查可能会中断。我刚刚检查了源代码,FFTW可能会根据编译标志定义不同的对齐方式。我看不出有什么好方法可以弄清楚它使用的对齐方式。它对于AVX可以是32字节,对于AVX-512可以是64字节。

另一方面,为检查这类内容而提供的fftw_alignment_of函数执行一个简单的模16,就像我上面的代码一样。所以我不知道。破损应该非常明显。它只会崩溃,而不会导致无效的结果。

最新更新