微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 R2R FFT 从 FFTW 移植到 cuFFT

如何解决将 R2R FFT 从 FFTW 移植到 cuFFT

我正在尝试将一些代码cpu 移植到 GPU,其中包括一些 FFT。因此,在 cpu 代码中,一些复杂的数组使用 fftw_plan_many_r2r 分别对其实部和图像部分进行转换。函数 foo 代表 R2R 变换例程,并为复数数组的每一部分调用两次。

void foo(vector_double  &evg) {    
    int nx = Dims[0],ny = Dims[1],nz = Dims[2];
    
    const int nxny[] = {ny,nx};
    const int n = nx*ny*nz;

    const fftw_r2r_kind kinds[] = {FFTW_RODFT00,FFTW_RODFT00};
    
    if (evg.size() != n)
        throw std::runtime_error ("*** weird size of evg");
    
    fftw_plan p;
    p =  fftw_plan_many_r2r(2,nxny,nz,&evg[0],1,nx*ny,kinds,FFTW_ESTIMATE);                         

    // actual FFT
    fftw_execute(p);
}

void bar(vector_complex &evg) {
    vector_double tmp;
    tmp = evg.real();
    foo(tmp);
    evg.real() = tmp;
    tmp = evg.imag();
    foo(tmp);
    evg.imag() = tmp;
}

那么,由于没有从 FFTW R2R 到 cuFFT 的直接转换,我如何在 CUDA 上获得相同的结果? 附注如果有帮助,vector_double 和 vector_complex 是特征向量

解决方法

我无法提供解决方案,但评论有大小限制,所以我把它放在这里:

  1. 在 FFTW 中,您使用原位变换,但您没有使用 FFTW_IN_PLACE。我不知道这是否正确,我自己从未使用过原位变换。

  2. 确实 cuFFT 没有 R2R,因此我们必须进行调查。根据 fftw 文档,FFTW_RODFT00 表示 DST-I。根据维基百科,DST-I 是正弦变换,如果你制作一个大小为 2*(N+1) 的向量并反向复制值,它具有等效的傅立叶变换,如右图标记为 DST-I:{ {3}}。因此,如果您对该“扩展向量”进行 r2c(或 c2c)变换并从变换向量中删除一些值,则您将完全进行 R2R 变换。请参阅 https://en.wikipedia.org/wiki/Discrete_sine_transform:“DST-I 完全等同于实数序列的 DFT,它在第零点和中间点周围是奇数,按 1/2 缩放”。

不过有两个问题:

  1. 你必须自己推导出哪些索引必须被删除(即复制到结果向量),当场接近它有点复杂。

  2. 如果你在 c2r 的情况下使用额外的复制,GPU 必须比 fftw 在 r2r 的情况下进行更多的计算(2(N+1)-size 变换而不是仅仅 N),并且必须完成更多的内存分配,因此它不会像 r2c 或 c2c 情况一样快。但根据我的经验,即使是较旧的主流 GPU 也比带 FFT 的 CPU 快很多(比如一个数量级),因此您至少可以获得一些加速。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。