【问题标题】:FFTW output vector size is wrong after executing the FFT plan执行 FFT 计划后 FFTW 输出向量大小错误
【发布时间】:2016-11-29 14:32:16
【问题描述】:

我在使用 fftw 库执行 FFT 计划时遇到问题。我声明fftInfftOut 大小为2048 的向量,并用它们定义fftwf_plan_dft_1d

但是当我执行计划时,fftOut 向量突然全错了。在我的代码中,我可以在调试时看到它的大小从 2048 变为 0。当我编写下面的小型可执行示例时,我只是得到了错误的大小,例如 17293858104588369909。

当然,当我尝试访问向量的第一项时,会发生SIGSEGV

我的代码:

#include <complex>
#include <iostream>
#include <fftw3.h>
#include <vector>
using namespace std;

typedef std::vector<std::complex<float>> fft_vector;

int main() {
    const unsigned int VECTOR_SIZE = 2048;
    fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
    fft_vector* fftOut = new fft_vector(VECTOR_SIZE);

    fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE, reinterpret_cast<fftwf_complex*>(fftIn), reinterpret_cast<fftwf_complex*>(fftOut), FFTW_FORWARD, FFTW_ESTIMATE);

    fftwf_execute(fftPlan);

    std::cout << fftOut->size() << std::endl;
    std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;

    return 0;
}

当然,我知道在这个例子中fftIn 向量是空的,但是当它不是时输出会被破坏。在这种情况下,SIGSEGV 发生在第二个 cout 中,如前所述。

我的完整代码有线程(但 FFT 都发生在同一个线程中,因此不应该应用竞争条件),这就是在这个小示例中尝试隔离代码的原因之一,以防万一,但它反正好像有什么问题。

有什么想法吗?

【问题讨论】:

    标签: c++ fftw


    【解决方案1】:

    主要问题是您将向量传递给它,这是行不通的;您需要传递向量内容: &((*fftIn)[0]) 和 &((*fftOut)[0]) 或类似的东西。实际上,您是在告诉 fftw 踩踏矢量对象的元数据(包括长度,这解释了为什么它有时是 0 有时是乱码)。它实际上是写入向量结构的开头,因为这就是指针指向的内容。它还使用 fftIn 的元数据作为 fft 输入的一部分,这也不是您想要的。

    您可以考虑改用 fftw_complex 和 fftw_malloc,这将确保您的数据以 fftw 需要的方式存储:http://www.fftw.org/doc/SIMD-alignment-and-fftw_005fmalloc.html 如果你真的需要,你可以在之后将 fftOut 放入一个向量中。这将确保您获得 SIMD(如果可用)的优势,并避免任何具有复杂类型和内存分配的编译器或平台特定行为。使用 fftw 的类型和分配器意味着您的代码将始终按照您的预期以最佳方式运行,无论您在哪个平台上运行它以及使用哪个编译器。

    这是您从 fftw 文档 (http://www.fftw.org/doc/Complex-One_002dDimensional-DFTs.html) 中转换的示例:

    #include <fftw3.h>
    ...
    {
        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, out, FFTW_FORWARD, FFTW_ESTIMATE);
        ...
        fftw_execute(p); /* repeat as needed */
        ...
        fftw_destroy_plan(p);
        fftw_free(in); fftw_free(out);
    }
    

    尝试匹配此示例,您的代码应该符合您的预期。

    编辑: 如果您必须使用 C++ complex 和 vector,这应该可以工作:

    const unsigned int VECTOR_SIZE = 2048;
    fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
    fft_vector* fftOut = new fft_vector(VECTOR_SIZE);
    
    fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE, 
        reinterpret_cast<fftwf_complex*>(&(*fftIn)[0]),
        reinterpret_cast<fftwf_complex*>(&(*fftOut)[0]),
        FFTW_FORWARD, FFTW_ESTIMATE);
    
    fftwf_execute(fftPlan);
    
    std::cout << fftOut->size() << std::endl;
    std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;
    

    请注意,您必须取消对向量指针的引用才能使 [] 运算符起作用;获取索引 0 为您提供实际矢量数据的第一个元素,因此该元素的地址是您需要提供给 fftw_plan 的地址(指针)。

    【讨论】:

    • 它应该可以工作:fftw.org/doc/Complex-numbers.html#Complex-numbers 无论如何,我会按照你的建议尝试经典代码
    • @RomanRdgz 是的,应该。主要问题是您传递的是向量而不是向量的内容。使用 fftw 的类型和分配可以额外确保您从 fftw 中获得所需的行为和性能。还要注意该链接中“应该”一词的使用:可能无法保证(至少对于所有平台上的所有编译器)C++ complex 类型有效。
    • 只是好奇:如果可以用 C++ complex 来做,我应该如何重写代码?保持 fftIn 和 fftOut 作为动态向量,因为我需要它们的大小是可配置的。另一方面,我不清楚如何访问输出向量内容。 (&fftOut[0]).x ?
    • @RomanRdgz 您最后正确访问了输出;问题只是将向量交给 fftw
    【解决方案2】:

    你不能 reinterpret_cast 一个向量指向复杂元素上的指针:你访问的是向量内部变量(如大小),不一定是向量原始数据,这可能解释了为什么该对象在输出中被丢弃,并且接下来发生的所有坏事。

    另一方面,转换矢量数据的地址是可行的。

    只需这样做(也不需要new 向量,使用标准声明):

    fft_vector fftIn(VECTOR_SIZE);
    fft_vector fftOut(VECTOR_SIZE);
    // load your data in fftIn
    fftwf_plan_dft_1d(VECTOR_SIZE, static_cast<const fftwf_complex*>(&fftIn[0]), static_cast<fftwf_complex*>(&fftOut[0]), FFTW_FORWARD, FFTW_ESTIMATE);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 2012-06-19
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多