在fortran77中用fftw分解2D FFT(和逆fft)

时间:2016-05-23 17:48:34

标签: fortran fft fftw

[编辑1]添加了显示原始数据和获得数据的数据

[编辑2]我发现了我的错误,我在dfftw_plan_many_dft的调用中使用了fftw_measure而不是fftw_estimate

[编辑3]纠正了代码中的拼写错误(用dfftw_execute_dft_r2c中的u2d替换你)

我尝试使用多个1D fft执行数组的2D fft,而不是使用fftw库中已存在的2D fft函数。然后,我需要执行逆2D fft。 这样做的原因是(将来)我的数组太大而无法一次性加载以执行2D fft。

我的代码的第一稿当前或多或少看起来像这样:

  double precision u2d(nx,ny),u2d2(nx,ny)
  double complex qhat2d(nx/2+1,ny),qhat2d2(nx/2+1,ny)
  integer N(1)
  integer howmany, idist, odist, istride, ostride
  integer inembed(2), onembed(2)
  integer rank

  ! some function to read the data into u2d

  ! perform x-fft
  N(1) = NX
  howmany = NY
  inembed(1) = NX
  inembed(2) = NY
  istride = 1
  idist = NX
  ostride = 1
  odist = (NX/2+1)
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  write(*,*) 'u', u2d(1,1)
  CALL dfftw_plan_many_dft_r2c(PLAN,rank,N(1),howmany,
&                              u2d,inembed,
&                              istride,idist,
&                              qhat2d,onembed,
&                              ostride,odist,FFTW_ESTIMATE) ! 
  CALL dfftw_execute_dft_r2c(PLAN,u2d,qhat2d) ! x-fft
  CALL dfftw_destroy_plan(PLAN)


  ! perform y-fft
  N(1) = NY
  howmany = (NX/2+1)
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = (NX/2+1)
  idist = 1
  ostride = (NX/2+1)
  odist = 1
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft(PLAN,rank,N(1),howmany,
&                              qhat2d,inembed,
&                              istride,idist,
&                              qhat2d2,onembed,
&                              ostride,odist,FFTW_FORWARD,
&                              FFTW_MEASURE) ! 
  CALL dfftw_execute_dft(PLAN,qhat2d,qhat2d2) ! y-fft
  CALL dfftw_destroy_plan(PLAN)

  ! normally here, perform some filtering operation
  ! but at the moment, I do nothing

  ! perform inv-y-fft
  N(1) = NY
  howmany = (NX/2+1)
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = (NX/2+1)
  idist = 1
  ostride = (NX/2+1)
  odist = 1
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft(PLAN,rank,N(1),howmany,
 &                             qhat2d2,inembed,
 &                              istride,idist,
 &                              qhat2d,onembed,
 &                              ostride,odist,FFTW_BACKWARD,
 &                              FFTW_MEASURE) ! 
  CALL dfftw_execute_dft(PLAN,qhat2d2,qhat2d) ! inv-y-fft
  CALL dfftw_destroy_plan(PLAN)

  ! perform inv-x-fft
  N(1) = NX ! I'm not too sure about this value here
  howmany = NY
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = 1
  idist = (NX/2+1)
  ostride = 1
  odist = NX
  onembed(1) = NX
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft_c2r(PLAN,rank,N(1),howmany,
&                              qhat2d,inembed,
&                              istride,idist,
&                              u2d2,onembed,
&                              ostride,odist,FFTW_ESTIMATE) ! 
  CALL dfftw_execute_dft_c2r(PLAN,qhat2d,u2d2) ! x-fft
  CALL dfftw_destroy_plan(PLAN)
  write(*,*) 'u2d2', u2d2(1,1)

  do i=1,nx
   do j=1,ny
    u2d2(i,j) = u2d2(i,j) / (nx*ny)
   enddo
  enddo
  write(*,*) 'u2d2', u2d2(1,1) ! here the values u2d2(1,1) is different from u2d(1,1)

  ! some action to write u2d2 to file
  end

我期待u2d和u2d2相同,但我获得了相对不同的值。我在某个地方犯了错误吗?

原件和结果如下所示。形状看起来相似,但值相对不同(例如,最小值和最大值)。

Original field

Field obtained after fft and i-fft

2 个答案:

答案 0 :(得分:1)

我发现了我的错误,我在dfftw_plan_many_dft的调用中使用了fftw_measure而不是fftw_estimate。

更正为我提供了适当的原始字段。

答案 1 :(得分:1)

清除混乱。会发生什么是FFTW Sentc2r例程不能保证保留输入数组。他们可以用垃圾覆盖结果。

现在,您可以很幸运,只需使用r2c代替FFTW_ESTIMATE,但这不是一个好主意。FFTW_MEASURE会尝试很多算法,因此很可能会尝试一个不保留输入。 FFTW_MEASURE不会尝试计算任何内容,也不会覆盖输入。

问题是在执行转换(执行计划)时可以覆盖您的输入。只有在FFTW_ESTIMATE选择保留输入的算法时,您才会幸运。这是一个乐透。

为确保输入得到保留,除了FFT_ESTIMATEFFTW_INPUT_PRESERVE之外,您还应使用FFT_ESTIMATE

您也可以不使用它,而是在某处保存输入。我认为这通常更好,因为FFTW_MEASURE可以(很可能)选择较慢的算法。