fftw库与matlab进行傅里叶变换结果不一致 - 小众知识

fftw库与matlab进行傅里叶变换结果不一致

2023-06-29 02:04:53 苏内容
  标签: matlab
阅读:2644

我用fftw库对一维数组double array[ ] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }进行FFT变换,但是得到的结果与matlab的结果不一样,两种fft结果前六个数据是一样的,后三个数据就很奇怪。原代码如下:

  1. #include "fftw3.h"  
  2. #include<stdio.h>
  3. #include<iostream>
  4. #include<vector>
  5. using namespace std;
  6. int main()
  7. {
  8. //****************************ifft********************************
  9. double array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  10. double* out;
  11. double* err;
  12. int i, size = 10;
  13. fftw_complex* out_cpx;
  14. fftw_plan fft;
  15. fftw_plan ifft;
  16. out_cpx = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * size);
  17. out = (double*)malloc(size * sizeof(double));
  18. err = (double*)malloc(size * sizeof(double));
  19. fft = fftw_plan_dft_r2c_1d(size, array, out_cpx, FFTW_ESTIMATE);  //Setup fftw plan for fft
  20. fftw_execute(fft);
  21. cout << "fft输出结果" << endl;
  22. for (int k = 0; k < size; k++)
  23. {
  24. cout << "(" << out_cpx[k][0] << "," << out_cpx[k][1] << ") ";
  25. }
  26. cout << endl;
  27. ifft = fftw_plan_dft_c2r_1d(size, out_cpx, out, FFTW_ESTIMATE);   //Setup fftw plan for ifft
  28. fftw_execute(ifft);
  29. for (i = 0; i < size; i++)
  30. {
  31. err[i] = (array[i] - out[i]);
  32. printf("%f\t%f\n", (array[i]), out[i] / size);//需要做归一化处理
  33. }
  34. fftw_destroy_plan(fft);
  35. fftw_destroy_plan(ifft);
  36. fftw_free(out_cpx);
  37. free(err);
  38. free(out);
  39. //***************************************ifft*********************
  40. system("pause");//暂停
  41. return 0;
  42. }

c++运行结果

img

matlab运行结果

img


matlab代码:

img



因为fftw将实数fft具有对称性,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. }


扩展阅读
相关阅读
© CopyRight 2010-2021, PREDREAM.ORG, Inc.All Rights Reserved. 京ICP备13045924号-1