当前位置:   article > 正文

C++ FFTW3的fftw_plan_dft_r2c_2d()和Eigen::MatrixXd的傅里叶正变换_eigen fftw

eigen fftw

项目场景:

C++中,对含有较多数据的二维实数矩阵Eigen::MatrixXd进行傅里叶变换时,ftw_plan_dft_r2c_2d()会比fftw_plan_dft_2d()快一些,但在使用ftw_plan_dft_r2c_2d()时,发现要输出与输入同等大小的矩阵时会缺失一些值(共轭值)。


问题描述

C++中,对含有较多数据的二维实数矩阵Eigen::MatrixXd进行傅里叶变换的时候,ftw_plan_dft_r2c_2d()如果输出与输入同等大小的矩阵时会缺失一些值(共轭值)。

1、C++使用fftw_plan_dft_2d()对实数矩阵进行傅里叶变换:先将MatrixXd赋值给MatrixXcd,然后再使用fftw_plan_dft_2d()。其输出结果和Matlab的结果相同。

  1. #include <iostream>
  2. #include <cmath>
  3. #include "Eigen/Dense"
  4. #include <opencv2/core/eigen.hpp>
  5. #include "fftw3.h"
  6. using namespace std;
  7. using namespace Eigen;
  8. int main() {
  9. MatrixXd a(5, 6); //奇数行
  10. a << 11, 18, 20, 16, 10, 14,
  11. 4, 1, 8, 29, 19, 21,
  12. 17, 27, 15, 9, 25, 5,
  13. 22, 7, 2, 24, 30, 23,
  14. 3, 6, 28, 13, 12, 26;
  15. MatrixXcd A = a;
  16. MatrixXcd FTa(a.rows(), a.cols());
  17. fftw_plan P;
  18. P = fftw_plan_dft_2d(a.cols(), a.rows(), (fftw_complex*)A.data(), (fftw_complex*)FTa.data(), FFTW_FORWARD, FFTW_ESTIMATE);
  19. fftw_execute(P);
  20. cout << FTa << endl;
  21. fftw_destroy_plan(P);
  22. return 0;
  23. };

2、Matlab的fft2输出结果:

3、但是,在C++使用fftw_plan_dft_r2c_2d()对实数矩阵进行傅里叶变换的时候,其输出结果其实只有Matlab/fftw_plan_dft_2d()结果的前 int(实矩阵行数 / 2) + 1 的数据。

  1. #include <iostream>
  2. #include <cmath>
  3. #include "Eigen/Dense"
  4. #include <opencv2/core/eigen.hpp>
  5. #include "fftw3.h"
  6. using namespace std;
  7. using namespace Eigen;
  8. int main() {
  9. MatrixXd a(5, 6); //奇数行实矩阵
  10. a << 11, 18, 20, 16, 10, 14,
  11. 4, 1, 8, 29, 19, 21,
  12. 17, 27, 15, 9, 25, 5,
  13. 22, 7, 2, 24, 30, 23,
  14. 3, 6, 28, 13, 12, 26;
  15. MatrixXcd FTa(a.rows(), a.cols());
  16. fftw_plan P;
  17. P = fftw_plan_dft_r2c_2d(a.cols(), a.rows(), a.data(), (fftw_complex*)FTa.data(), FFTW_ESTIMATE);
  18. fftw_execute(P);
  19. cout << FTa << endl; //输出只有matlab/fftw_plan_dft_2d()输出的前3行数据
  20. return 0;
  21. };

上图C++输出的红框数据对应下图Matlab输出的红框数据。

4、补充:偶数行实矩阵的情况

  1. int main() {
  2. MatrixXd aa(4, 6); //偶数行实矩阵
  3. aa << 11, 18, 20, 16, 10, 14,
  4. 4, 1, 8, 29, 19, 21,
  5. 17, 27, 15, 9, 25, 5,
  6. 22, 7, 2, 24, 30, 23;
  7. MatrixXcd FTaa(aa.rows(), aa.cols());
  8. fftw_plan PP;
  9. PP = fftw_plan_dft_r2c_2d(aa.cols(), aa.rows(), aa.data(), (fftw_complex*)FTaa.data(), FFTW_ESTIMATE);
  10. fftw_execute(PP);
  11. cout << FTaa << endl;
  12. return 0;
  13. };


解决方案:

实际上,fftw_plan_dft_r2c_2d()输出缺少的 ceil(double(实矩阵行数) / 2) - 1 行的数据对应的共轭部分已经全部包含在它的输出里

以Matlab的输出展示,黄框为fftw_plan_dft_r2c_2d()输出的缺失行,红框为缺失行对应的共轭区域。 因此,只需要对红框的数据取共轭并排列得当获得黄框数据,就能补全fftw_plan_dft_r2c_2d()的输出。

偶数行实矩阵的傅里叶变换的共轭区域与上述奇数行实矩阵的傅里叶变换的共轭区域略有不同,如图所示:

 观察可以发现,互为共轭的数据分为两部分,如蓝框所示:第1列部分与其余列部分。

 第一部分的元素在列方向上共轭对称;第二部分中红框的元素取共轭,并使红框区域翻转180°即为黄框区域

  1. #include <iostream>
  2. #include <cmath>
  3. #include "Eigen/Dense"
  4. #include <opencv2/core/eigen.hpp>
  5. #include "fftw3.h"
  6. using namespace std;
  7. using namespace Eigen;
  8. int main(){
  9. MatrixXd a(5, 6); //奇数行实矩阵
  10. a << 11, 18, 20, 16, 10, 14,
  11. 4, 1, 8, 29, 19, 21,
  12. 17, 27, 15, 9, 25, 5,
  13. 22, 7, 2, 24, 30, 23,
  14. 3, 6, 28, 13, 12, 26;
  15. /*
  16. MatrixXd a(4, 6); //偶数行实矩阵
  17. a << 11, 18, 20, 16, 10, 14,
  18. 4, 1, 8, 29, 19, 21,
  19. 17, 27, 15, 9, 25, 5,
  20. 22, 7, 2, 24, 30, 23;
  21. */
  22. MatrixXcd temp(a.rows()/2 + 1, a.cols());
  23. fftw_plan P;
  24. P = fftw_plan_dft_r2c_2d(a.cols(), a.rows(), a.data(), (fftw_complex*)temp.data(), FFTW_ESTIMATE);
  25. fftw_execute(P);
  26. int ConjRows = ceil(double(a.rows()) / 2) - 1;
  27. MatrixXcd FTa(a.rows(), a.cols());
  28. FTa.topRows(temp.rows()) = temp;
  29. FTa.bottomLeftCorner(ConjRows, 1) = ((temp.block(1, 0, ConjRows, 1)).conjugate()).colwise().reverse();
  30. FTa.bottomRightCorner(ConjRows, a.cols() - 1) = (((temp.block(1, 1, ConjRows, a.cols() - 1)).conjugate()).rowwise().reverse()).colwise().reverse();
  31. cout << FTa << endl;
  32. fftw_destroy_plan(P);
  33. }

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/105025
推荐阅读
相关标签
  

闽ICP备14008679号