为什么这个测试FFT程序给出的结果不正确?

时间:2013-12-14 16:38:38

标签: fortran fft fortran77

我正在编写需要FFT的Fortran代码。我正在使用Fortran 77中的Numerical Recipes的双精度版本four1(第501页)。以下是测试FFT的程序。下面是我从FFT获得的输出以及我期望获得的输出。变换的实部在舍入误差中是正确的,但虚部不是。然而,就我的目的而言,我甚至不需要想象中的部分,那么我是否应该抓住真实的部分并继续使用它?尽管如此输出不正确仍让我感到困扰,这让我觉得我对这个子程序的实现并不了解。

我理解它的方式,构造数组“data”时给出的值都是实数(1,1,1,1,0,0,0,0)。并且虚数值都为零。那是对的吗?我担心我没有以所需的形式将输入数组提供给FFT。当我在我的实际程序中使用这个子程序时,FFT的结果有点荒谬,并且在几个时间步之后整个事情都会转到NaNs。

program fftTest
    implicit none   
    complex(kind=8), dimension(8) :: data = (/1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0/)
    integer :: i

    do i=1,8
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i)
    end do
print *, '-----'

call dfour1(data,8,1)

    do i=1,8
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i)
    end do
print *, '-----'

call dfour1(data,8,-1)
data = data/8

do i=1,8
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i)
    end do

end program fftTest

    SUBROUTINE dfour1(data,nn,isign)
        INTEGER isign,nn
        DOUBLE PRECISION data(2*nn)
        INTEGER i,istep,j,m,mmax,n
        DOUBLE PRECISION tempi,tempr
        DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp 
        n=2*nn
        j=1
        do 11 i=1,n,2 !This is the bit reversal section of the routine.
            if(j.gt.i)then
            tempr=data(j) !Exchange the two complex numbers.
            tempi=data(j+1)
            data(j)=data(i)
            data(j+1)=data(i+1)
            data(i)=tempr
            data(i+1)=tempi
        endif
        m=n/2
1       if ((m.ge.2).and.(j.gt.m)) then
            j=j-m
            m=m/2
        goto 1
        endif
        j=j+m
11    continue
      mmax=2 !Here begins the Danielson-Lanczos section of the routine.
2     if (n.gt.mmax) then                   
          istep=2*mmax
          theta=6.28318530717959d0/(isign*mmax)
          wpr=-2.d0*sin(0.5d0*theta)**2
          wpi=sin(theta)
          wr=1.d0
          wi=0.d0
          do 13 m=1,mmax,2  !Here are the two nested inner loops.
              do 12 i=m,n,istep
                 j=i+mmax   !This is the Danielson-Lanczos formula:
                 tempr=wr*data(j)-wi*data(j+1)
                 tempi=wr*data(j+1)+wi*data(j)
                 data(j)=data(i)-tempr
                 data(j+1)=data(i+1)-tempi
                 data(i)=data(i)+tempr
                 data(i+1)=data(i+1)+tempi
12        continue
          wtemp=wr  !Trigonometric recurrence
          wr=wr*wpr-wi*wpi+wr
          wi=wi*wpr+wtemp*wpi+wi
13      continue
        mmax=istep
        goto 2  !Not yet done.
        endif   !All done.
        return 
    END

预期(正确)输出:
    (4.000000000000000,0.000000000000000i)
    (1.000000000000000,-2.414213562373095i)
    (0.000000000000000,0.000000000000000i)
    (1.000000000000000,-0.414213562373095i)
    (0.000000000000000,0.000000000000000i)
    (1.000000000000000,0.414213562373095i)
    (0.000000000000000,0.000000000000000i)
    (1.000000000000000,2.414213562373095i)

测试程序的实际输出:
    (1.000000000000000,0.000000000000000i)
    (1.000000000000000,0.000000000000000i)
    (1.000000000000000,0.000000000000000i)
    (1.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
     -----
    (4.000000000000000,0.000000000000000i)
    (0.999999999999998,2.414213562373094i)
    (0.000000000000000,0.000000000000000i)
    (0.999999999999999,0.414213562373096i)
    (0.000000000000000,0.000000000000000i)
    (1.000000000000000,-0.414213562373094i)
    (0.000000000000000,0.000000000000000i)
    (1.000000000000003,-2.414213562373096i)
     -----
    (1.000000000000000,0.000000000000000i)
    (1.000000000000000,-0.000000000000000i)
    (1.000000000000000,0.000000000000000i)
    (1.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
    (0.000000000000000,0.000000000000000i)
    (0.000000000000000,-0.000000000000000i)
    (0.000000000000000,-0.000000000000000i)

1 个答案:

答案 0 :(得分:0)

program fftTest
    use iso_fortran_env
    implicit none
    integer, parameter :: nn = 8
    real(real64), dimension(2*nn) :: data = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,   &
         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]
    integer :: i

    do i=1,2*nn,2
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
    end do
print *, '-----'

call dfour1(data,nn,-1)

    do i=1,2*nn,2
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
    end do
print *, '-----'

call dfour1(data,nn,+1)
data = data/8

do i=1,2*nn,2
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
    end do

end program fftTest

以及通过Forran的ISO C绑定使用GNU科学库(开源)的演示:

program fftTest
    use iso_c_binding
    implicit none
    integer (c_size_t), parameter :: nn = 8
    real(C_DOUBLE), dimension(2*nn) :: data = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,   &
         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]
    integer :: i
    integer :: result

    interface
    !  Adapted from Fortran GSL Library, FGSL,
    !  http://www.lrz.de/services/software/mathematik/gsl/fortran/
      function gsl_fft_complex_radix2_backward(data, stride, n) bind(c)
         import :: c_size_t, c_double, c_int
         integer(c_size_t), value :: stride, n
         real (c_double), dimension(*), intent (inout)  :: data
         integer(c_int) :: gsl_fft_complex_radix2_backward
      end function gsl_fft_complex_radix2_backward
      function gsl_fft_complex_radix2_forward(data, stride, n) bind(c)
         import :: c_size_t, c_double, c_int
         integer(c_size_t), value :: stride, n
         real (c_double), dimension(*), intent (inout)  :: data
         integer(c_int) :: gsl_fft_complex_radix2_forward
      end function gsl_fft_complex_radix2_forward
    end interface

    do i=1,2*nn,2
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
    end do
   print *, '-----'

   result = gsl_fft_complex_radix2_forward (data, 1_c_size_t, nn)
   write (*, '("GSL return code: ", I0)' )  result

    do i=1,2*nn,2
        write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
    end do
   print *, '-----'

   result = gsl_fft_complex_radix2_backward (data, 1_c_size_t, nn)
   write (*, '("GSL return code: ", I0)' )  result
   data = data/8

   do i=1,2*nn,2
      write(*,'("(", F20.15, ",", F20.15, "i )")') data(i),data(i+1)
   end do

end program fftTest