【问题标题】:Armadillo 2D FFTW real to complex DFT Hermetian symmetryArmadillo 2D FFTW 实到复 DFT Hermetian 对称
【发布时间】:2018-05-02 11:10:53
【问题描述】:

我正在尝试对一些真实数据进行二维傅里叶变换。 我正在使用 FFTW 库来执行此操作,因为它比犰狳的库要快得多。

给定一个简单的 (4x4) 起始矩阵: AAA:

    0        0        0        0
    0   1.0000   2.0000   3.0000
    0   2.0000   4.0000   6.0000
    0   3.0000   6.0000   9.0000

`

如果我在犰狳中使用内置的 FFT,输出如下所示:

BBB: (+3.600e+01,+0.000e+00) (-1.200e+01,+1.200e+01) (-1.200e+01,+0.000e+00) (-1.200e+01,-1.200e+01) (-1.200e+01,+1.200e+01) (+0.000e+00,-8.000e+00) (+4.000e+00,-4.000e+00) (+8.000e+00,+0.000e+00) (-1.200e+01,+0.000e+00) (+4.000e+00,-4.000e+00) (+4.000e+00,+0.000e+00) (+4.000e+00,+4.000e+00) (-1.200e+01,-1.200e+01) (+8.000e+00,+0.000e+00) (+4.000e+00,+4.000e+00) (+0.000e+00,+8.000e+00)

但如果我使用 FFTW,我会得到:

CCC: (+3.600e+01,+0.000e+00) (+0.000e+00,-8.000e+00) (+4.000e+00,+0.000e+00) (0,0) (-1.200e+01,+1.200e+01) (+4.000e+00,-4.000e+00) (-1.200e+01,-1.200e+01) (0,0) (-1.200e+01,+0.000e+00) (-1.200e+01,+0.000e+00) (+8.000e+00,+0.000e+00) (0,0) (-1.200e+01,+1.200e+01) (+4.000e+00,-4.000e+00) (+4.000e+00,+4.000e+00) (0,0

对矩阵 BBB 和 CCC 执行各自的 IFFT 可以准确地得到起始矩阵 AAA。

根据文档:(http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data): “在许多实际应用中,输入数据 in[i] 是纯实数,在这种情况下,DFT 输出满足“厄米”冗余:out[i] 是 out[n-i] 的共轭。可以利用这些情况,在速度和内存使用方面实现大约两倍的改进。”

因此,矩阵 CCC 需要某种操作来检索 Hermetian 冗余,但我在数学上太菜鸟了,无法理解该操作是什么。 谁能帮我解决这个问题?

此外,犰狳以 col 主要格式存储数据,FFTW 以行主要格式存储,根据文档,只要您以相反的顺序将行/列维度传递给计划函数,这并不重要?

感谢收看。

附上我的代码:

#include <iostream>
#include <fftw3.h>
#include "armadillo"

using namespace arma;
using namespace std;


int main(int argc, char** argv)
{

    mat AAA=zeros(4,4);
    mat IBB=zeros(4,4);
    cx_mat BBB(4,4);



    for (int xx=0;xx<=3;xx++){
        for ( int yy=0;yy<=3;yy++){

    AAA(xx,yy)= xx*yy;
        }
    }


    cx_mat CCC (4,4);
    cx_mat CCCC(4,4);
    mat ICC =zeros(4,4);



     fftw_plan plan=fftw_plan_dft_r2c_2d(4, 4,(double(*))&AAA(0,0), (double(*)[2])&CCC(0,0), FFTW_ESTIMATE);
     fftw_plan plan2=fftw_plan_dft_c2r_2d(4, 4,(double(*)[2])&CCCC(0,0), (double(*))&ICC(0,0), FFTW_ESTIMATE);

     //Perform Armadillo FFT (Correct output)
     BBB=fft2(AAA);
     //Perform armadillo IFFT
     IBB=real(ifft2(BBB));




    //Perform FFTW- FFT
    fftw_execute(plan);
    //Allocate fourier array to another array as imput array is destroyed
    CCCC=CCC;

    //Perform FFTW- IFFT on newly allocated array
    fftw_execute(plan2);
    //Must re-normalise the array by the number of elements
    ICC=ICC/(4*4);

    //myst rescale by the number of elements in the array

BBB.print("BBB:");
CCC.print("CCC:");  

IBB.print("IBB:");
ICC.print("ICC:");




    return 0;
}
`

【问题讨论】:

标签: 2d armadillo fftw symmetry


【解决方案1】:

你有一个真正的函数A:

0        0        0        0
0   1.0000   2.0000   3.0000
0   2.0000   4.0000   6.0000
0   3.0000   6.0000   9.0000 

实函数的傅里叶变换是厄米特变换。这意味着频谱的实部是偶数,X(iw) = X(-iw),而频谱的虚部是奇数,X(iw)=-X(-iw)。换句话说

imag(BBB) == -imag(BBB') && real(BBB) == real(BBB')

但在这种情况下,我知道仅从上对角线上的系数,例如,我就能够重建 BBB 以进行逆变换。

fftw_plan_dft_r2c_2d 还解释了这就是为什么CCC 需要 nd/2+1 x nd(1 列填充)来存储输出。所以你可以像这样声明 CCC 和 CCCC 是安全的:

cx_mat CCC (4,3);
cx_mat CCCC(4,3);

但是当您提到自己 FFTW 不同于犰狳行专业时,您还应该在代码中反映其后果:

cx_mat CCC (3,4);
cx_mat CCCC(3,4);

突然你的结果看起来完全不同了:

BBB:
(+3.600e+01,+0.000e+00) (-1.200e+01,+1.200e+01) (-1.200e+01,+0.000e+00) (-1.200e+01,-1.200e+01)
(-1.200e+01,+1.200e+01) (+0.000e+00,-8.000e+00) (+4.000e+00,-4.000e+00) (+8.000e+00,+0.000e+00)
(-1.200e+01,+0.000e+00) (+4.000e+00,-4.000e+00) (+4.000e+00,+0.000e+00) (+4.000e+00,+4.000e+00)
(-1.200e+01,-1.200e+01) (+8.000e+00,+0.000e+00) (+4.000e+00,+4.000e+00) (+0.000e+00,+8.000e+00)
CCC:
(+3.600e+01,+0.000e+00) (-1.200e+01,+1.200e+01) (-1.200e+01,+0.000e+00) (-1.200e+01,-1.200e+01)
(-1.200e+01,+1.200e+01) (+0.000e+00,-8.000e+00) (+4.000e+00,-4.000e+00) (+8.000e+00,+0.000e+00)
(-1.200e+01,+0.000e+00) (+4.000e+00,-4.000e+00) (+4.000e+00,+0.000e+00) (+4.000e+00,+4.000e+00)
IBB:
    0        0        0        0
    0   1.0000   2.0000   3.0000
    0   2.0000   4.0000   6.0000
    0   3.0000   6.0000   9.0000
ICC:
    0        0        0        0
    0   1.0000   2.0000   3.0000
    0   2.0000   4.0000   6.0000
    0   3.0000   6.0000   9.0000

根据 CCC 中的内容,您可以重建剩余的系数,并且您的逆变换是正确的。如果还有什么不清楚的地方请联系我。

重构可以如下进行:

(+3.6e+01,+0.0e+00) (-1.2e+01,+1.2e+01) (-1.2e+01,+0.0e+00 (-1.2e+01,-1.2e+01)
(-1.2e+01,+1.2e+01) (+0.0e+00,-8.0e+00) (+4.0e+00,-4.0e+00 (+8.0e+00,+0.0e+00)
(-1.2e+01,+0.0e+00) (+4.0e+00,-4.0e+00) (+4.0e+00,+0.0e+00 (+4.0e+00,+4.0e+00)
conj(CCC(1,2))      conj(CCC(4,2))      conj(CCC(4,3))     conj(CCC(2,2))

CCCC 已完成逆变换为实数。

【讨论】:

  • 非常感谢您的回答!您能否详细说明重建过程,因为我似乎无法正确处理。
  • 我会编辑答案。给我一点时间。但请不要忘记投票/接受。
  • 嗯..重建似乎不适用于其他矩阵(更大尺寸)..?
  • 是的,任意大小的随机实矩阵
  • 嗯。调查应该会在几分钟内得到答案。
【解决方案2】:

只是添加到 Kaveh 的答案(已接受的答案),为了完全恢复 Hermetian 冗余,有必要按照他的答案中所述执行 DFT,然后选择忽略零频率的子矩阵。进行从左到右翻转,上下翻转,然后对结果矩阵进行复共轭。希望这对其他人有帮助。这是代码

#include <iostream>
#include <fftw3.h>
#include "armadillo"

using namespace arma;
using namespace std;


int main(int argc, char** argv)
{

    mat AAA=zeros(6,6);
    mat IBB=zeros(6,6);
    cx_mat ccgin(6,6);
    cx_mat ccgout(6,6);
    cx_mat BBB(6,6);



    for (int xx=0;xx<=5;xx++){
        for ( int yy=0;yy<=5;yy++){

    AAA(xx,yy)= xx*(xx+yy);
        }
    }


    cx_mat CCC (4,6);
    cx_mat CCCC(4,6);
    mat ICC =zeros(6,6);

    cx_mat con(3,5);



     fftw_plan plan=fftw_plan_dft_r2c_2d(6, 6,(double(*))&AAA(0,0), (double(*)[2])&CCC(0,0), FFTW_ESTIMATE);
     fftw_plan plan2=fftw_plan_dft_c2r_2d(6, 6,(double(*)[2])&CCCC(0,0), (double(*))&ICC(0,0), FFTW_ESTIMATE);

     //Perform Armadillo FFT (Correct output)
     BBB=fft2(AAA);

     //Perform armadillo IFFT
     IBB=real(ifft2(BBB));




    //Perform FFTW- FFT
    fftw_execute(plan);
    //Allocate fourier array to another array as imput array is destroyed
    CCCC=CCC;

    //Perform FFTW- IFFT on newly allocated array
    fftw_execute(plan2);
    //Must re-normalise the array by the number of elements
    ICC=ICC/(6*6);

    //must rescale by the number of elements in the array

BBB.print("BBB:");
CCC.print("CCC:");  

IBB.print("IBB:");
ICC.print("ICC:");


//Recover Hermetian redundancy
con=fliplr(flipud(conj(CCC(span(1,3),span(1,5)))));
con.print("fliplr(flipud(conj(CCC(span(1,3),span(1,5)))));:");


    return 0;
}

【讨论】:

  • 我已经为各种尺寸制作了一个通用版本nxn。我没有发布的原因是我没有足够的时间将其推广到 mxn 矩阵。
  • 再次感谢,您帮了很多忙!我现在遇到的问题是完全恢复的 IFFT 会产生垃圾:(
  • FFTW 是一个高度优化的库。我相信他们会做一些事情,你只会在大约 100 种出版物中找到这些东西,这些出版物结合在一起打赌他们在成群的不同硬件架构中实现的速度。但我很好奇:你上面调查的目的是什么?如果实现之间存在差异,您如何关心?只要你坚持 FFTW 进行逆变换,你就很好。
  • 我正在为相场模型编写一个谱求解器。已经让它在 Matlab 中运行良好,但现在是时候加快速度了(parralalise)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多