在 Fortran 混乱输出中使用 FFTW 对正弦 (x) 进行 DFT
DFT of sine(x) using FFTW in Fortran muddled output
以下是我编写的用于查找一段时间内正弦 (x) 的 DFT 的代码。
program fftw_test
implicit none
INTEGER FFTW_MEASURE
PARAMETER (FFTW_MEASURE=0)
INTEGER FFTW_ESTIMATE
PARAMETER (FFTW_ESTIMATE=64)
INTEGER FFTW_FORWARD
PARAMETER (FFTW_FORWARD=-1)
integer, parameter :: n = 8
integer :: i
double complex, dimension(0:n-1) :: input, output
double precision, parameter :: pi = 3.141592653, h = 2.0d0*pi/(n)
integer*8 :: plan
call dfftw_plan_dft_1d(plan, n, input, output, fftw_forward, fftw_measure)
do i = 0, n-1
input(i) = cmplx(sin(h*i), 0)
end do
call dfftw_execute_dft(plan, input, output)
output = output/n
output(0) = cmplx(0,0) ! setting oddball wavenumber to be 0
call dfftw_destroy_plan(plan)
do i = -n/2, n/2-1, 1
write(*, *) i, output(i+(n/2))
end do
end program
我知道 FFTW 库中的 r2c(实数到复数)函数。但有人建议我使用普通的 c2c 功能。所以我将输入函数定义为实部 = sine(x) 和复数部分 0 的复数。
sine(x) 的 DFT 应该是 fk(-1) = cmplx(0, -0.5) 和 fk(1) = cmplx(0, 0.5) 其中 fk(k) 表示傅里叶系数第 k 个波数
我收到的输出如下。
-4 ( 0.0000000000000000 , 0.0000000000000000 )
-3 ( 3.2001271327131496E-008,-0.49999998518472011 )
-2 ( -1.0927847071684482E-008, 1.4901161193847656E-008)
-1 ( -1.0145577183762535E-008, 1.4815279864022202E-008)
0 ( -1.0927847071684482E-008, 0.0000000000000000 )
1 ( -1.0145577183762535E-008, -1.4815279864022202E-008)
2 ( -1.0927847071684482E-008, -1.4901161193847656E-008)
3 ( 3.2001271327131496E-008, 0.49999998518472011 )
我得到 fk(-3) = cmplx(~0, -0.5) 和 fk(3) = cmplx(~0, 0.5)。如果我将网格大小增加到 16、32 左右,我会得到具有所需值的 -n/2 -1 和 n/2 -1 波数,而不是 -1 和 1 波数。
这与 FFTW 在输出数组中存储输出的方式有关吗?还是我哪里出错了?
此外,我似乎没有 'proper 0' 我应该去的地方。相反,它是 10^(-8) 数量级的数字,我认为这是我的数据类型 double 可以容纳的最小数字。这是我应该担心的事情吗?
就像@VladimirF 已经说过的,值的顺序与您预期的有点不同。数组的前半部分包含正频率,后半部分以相反的顺序包含负频率(参见 this link)。您可能需要检查 FFTW 使用的符号约定。
准确性问题源于 pi
的单精度值和使用 cmplx
生成单精度复数(使用关键字参数 kind
)。在这种情况下,您可以简单地将您的实际值分配给复杂变量。应用这两个更改会产生 ~1e-10
的精度。这可以通过为 pi 提供更好的近似值(即超过 10 位数字)来改进。
例如值 pi = 3.141592653589793d0
产生的结果精度为 1e-16
.
以下是我编写的用于查找一段时间内正弦 (x) 的 DFT 的代码。
program fftw_test
implicit none
INTEGER FFTW_MEASURE
PARAMETER (FFTW_MEASURE=0)
INTEGER FFTW_ESTIMATE
PARAMETER (FFTW_ESTIMATE=64)
INTEGER FFTW_FORWARD
PARAMETER (FFTW_FORWARD=-1)
integer, parameter :: n = 8
integer :: i
double complex, dimension(0:n-1) :: input, output
double precision, parameter :: pi = 3.141592653, h = 2.0d0*pi/(n)
integer*8 :: plan
call dfftw_plan_dft_1d(plan, n, input, output, fftw_forward, fftw_measure)
do i = 0, n-1
input(i) = cmplx(sin(h*i), 0)
end do
call dfftw_execute_dft(plan, input, output)
output = output/n
output(0) = cmplx(0,0) ! setting oddball wavenumber to be 0
call dfftw_destroy_plan(plan)
do i = -n/2, n/2-1, 1
write(*, *) i, output(i+(n/2))
end do
end program
我知道 FFTW 库中的 r2c(实数到复数)函数。但有人建议我使用普通的 c2c 功能。所以我将输入函数定义为实部 = sine(x) 和复数部分 0 的复数。
sine(x) 的 DFT 应该是 fk(-1) = cmplx(0, -0.5) 和 fk(1) = cmplx(0, 0.5) 其中 fk(k) 表示傅里叶系数第 k 个波数
我收到的输出如下。
-4 ( 0.0000000000000000 , 0.0000000000000000 )
-3 ( 3.2001271327131496E-008,-0.49999998518472011 )
-2 ( -1.0927847071684482E-008, 1.4901161193847656E-008)
-1 ( -1.0145577183762535E-008, 1.4815279864022202E-008)
0 ( -1.0927847071684482E-008, 0.0000000000000000 )
1 ( -1.0145577183762535E-008, -1.4815279864022202E-008)
2 ( -1.0927847071684482E-008, -1.4901161193847656E-008)
3 ( 3.2001271327131496E-008, 0.49999998518472011 )
我得到 fk(-3) = cmplx(~0, -0.5) 和 fk(3) = cmplx(~0, 0.5)。如果我将网格大小增加到 16、32 左右,我会得到具有所需值的 -n/2 -1 和 n/2 -1 波数,而不是 -1 和 1 波数。
这与 FFTW 在输出数组中存储输出的方式有关吗?还是我哪里出错了?
此外,我似乎没有 'proper 0' 我应该去的地方。相反,它是 10^(-8) 数量级的数字,我认为这是我的数据类型 double 可以容纳的最小数字。这是我应该担心的事情吗?
就像@VladimirF 已经说过的,值的顺序与您预期的有点不同。数组的前半部分包含正频率,后半部分以相反的顺序包含负频率(参见 this link)。您可能需要检查 FFTW 使用的符号约定。
准确性问题源于 pi
的单精度值和使用 cmplx
生成单精度复数(使用关键字参数 kind
)。在这种情况下,您可以简单地将您的实际值分配给复杂变量。应用这两个更改会产生 ~1e-10
的精度。这可以通过为 pi 提供更好的近似值(即超过 10 位数字)来改进。
例如值 pi = 3.141592653589793d0
产生的结果精度为 1e-16
.