Fortran 如何在FFTW中以2个或更多维度进行规格化?

Fortran 如何在FFTW中以2个或更多维度进行规格化?,fortran,fft,fftw,Fortran,Fft,Fftw,我试图弄清楚如何使用FFTW正确地规范化DFT的结果。表示大小为n的一维复杂阵列X的正向(FFTW_正向)离散傅里叶变换计算阵列Y,其中 Y_k=\sum\limits_{j=0}{n-1}X_j e^{-2\pi j k\sqrt{-1}/n} 向后DFT计算: Y_k=\sum\limits_{j=0}{n-1}X_j e^{+2\pi j k\sqrt{-1}/n} 这些定义与实到复转换的定义相同 此外,本教程还规定“FFTW计算非规范化变换,因为DFT中的求和前面没有系数。换句话说,应用

我试图弄清楚如何使用FFTW正确地规范化DFT的结果。表示大小为n的一维复杂阵列X的正向(FFTW_正向)离散傅里叶变换计算阵列Y,其中

Y_k=\sum\limits_{j=0}{n-1}X_j e^{-2\pi j k\sqrt{-1}/n}

向后DFT计算:

Y_k=\sum\limits_{j=0}{n-1}X_j e^{+2\pi j k\sqrt{-1}/n}

这些定义与实到复转换的定义相同

此外,本教程还规定“FFTW计算非规范化变换,因为DFT中的求和前面没有系数。换句话说,应用前向变换和后向变换将使输入乘以n”。,它没有具体说明需要在何处进行重新缩放。我想这可能取决于应用程序,但不确定如何正确使用它。声明它应该在前进方向上正常化,但我有我的疑问,我将详细说明

我的目标是找出如何正确地规范化FFT结果,以获得我所期望的结果。所以我首先做了一个简单的1D变换,在这里我知道确切的期望是什么:当我变换时,使用与FFTW相同的约定(归一化因子=1,振荡因子=-2*pi,用于前向傅里叶变换)

1/2(δ(1+x)-δ(1-x))

δ是狄拉克δ函数,我希望得到:

整体的_(-∞)^∞ (1/2(δ(1+x)-δ(1-x)))e^(-2πiωx)dx=i sin(2πω)

当我对I sin(2πω)进行IFFT时也是如此,只是现在我需要通过除以n进行归一化

下面是我用来演示这种行为的代码:

program use_fftw

  use,intrinsic :: iso_c_binding
  implicit none
  include 'fftw3.f03'


  integer, parameter   :: N = 1000
  integer, parameter   :: dp = kind(1.d0)
  real(dp), parameter  :: pi = 3.1415926d0
  real(dp), parameter  :: physical_length = 500
  real(dp), parameter  :: dx = physical_length/real(N)
  real(dp), parameter  :: dk = 1.d0 / physical_length

  integer :: i, ind1, ind2


  ! for double precision: use double complex & call dfftw_plan_dft_1d
  complex(C_DOUBLE_COMPLEX), allocatable, dimension(:) :: arr_out
  real(C_DOUBLE),    allocatable, dimension(:)         :: arr_in
  type(C_PTR)                                          :: plan_forward, plan_backward


  allocate(arr_in(1:N))
  allocate(arr_out(1:N/2+1))

  plan_forward = fftw_plan_dft_r2c_1d(N, arr_in, arr_out, FFTW_ESTIMATE)
  plan_backward = fftw_plan_dft_c2r_1d(N, arr_out, arr_in, FFTW_ESTIMATE)


  !----------------------
  ! Setup
  !----------------------

  ! add +1: index = 1 corresponds to x=0
  ind1 = int(1.d0/dx)+1                   ! index where x=1
  ind2 = int((physical_length-1.d0)/dx)+1 ! index where x=-1

  arr_in = 0
  arr_in(ind1) = -0.5d0
  arr_in(ind2) = 0.5d0


  !----------------------
  ! Forward
  !----------------------
  call fftw_execute_dft_r2c(plan_forward, arr_in, arr_out)

  write(*,*) "Verification: Max real part of arr_out:", maxval(real(arr_out))

  open(unit=666,file='./fftw_output_norm1d_fft.txt', form='formatted')
  do i = 1, N/2+1
    write(666, '(2E14.5,x)') (i-1)*dk, aimag(arr_out(i))
  enddo
  close(666)

  write(*,*) "Finished! Written results to fftw_output_norm1d_fft.txt"


  !----------------------
  ! Backward
  !----------------------
  call fftw_execute_dft_c2r(plan_backward, arr_out, arr_in)

  arr_in = arr_in/N

  open(unit=666,file='./fftw_output_norm1d_real.txt', form='formatted')
  do i = 1, N
    write(666, '(2E14.5,x)') (i-1)*dx, arr_in(i)
  enddo
  close(666)

  write(*,*) "Finished! Written results to fftw_output_norm1d_real.txt"

  deallocate(arr_in, arr_out)
  call fftw_destroy_plan(plan_forward)
  call fftw_destroy_plan(plan_backward)

end program use_fftw
结果完全符合我的预期:

所以在这个例子中,当从傅里叶空间回到实空间时,我只归一化了(除以n),得到了我想要的

但当我尝试对多个维度做同样的事情时。 这一次,我试图改变

sqrt(π/2)((δ(-1+x)-δ(1+x))δ(y)+δ(x)(δ(-1+y)-δ(1+y)))

应该给谁

整体的_(-∞)^∞ (sqrt(π/2)((δ(-1+x)-δ(1+x))δ(y)+δ(x)(δ(-1+y)-δ(1+y)))e^(-2πi{x,y}{a,b})d{x,y}=+i sin(a)+i sin(b)

我绘制x=0(k_x=0)的结果:

这似乎是完全错误的,无论是在窦波的频率还是振幅上

但是,通过除以n^2进行反向变换和归一化,可以在x和y方向上得到预期的初始条件。以下是x=0的曲线图:

我不知道我做错了什么

以下是2d代码:

program use_fftw

  use,intrinsic :: iso_c_binding
  implicit none
  include 'fftw3.f03'


  integer, parameter   :: N = 1000
  integer, parameter   :: dp = kind(1.d0)
  real(dp), parameter  :: pi = 3.1415926d0
  real(dp), parameter  :: physical_length = 500
  real(dp), parameter  :: dx = physical_length/real(N)
  real(dp), parameter  :: dk = 1.d0 / physical_length

  integer :: i, ind1, ind2


  ! for double precision: use double complex & call dfftw_plan_dft_1d
  complex(C_DOUBLE_COMPLEX),  allocatable, dimension(:,:) :: arr_out
  real(C_DOUBLE),             allocatable, dimension(:,:) :: arr_in
  type(C_PTR)                              :: plan_forward, plan_backward


  allocate(arr_in(1:N, 1:N))
  allocate(arr_out(1:N/2+1, 1:N))


  plan_forward = fftw_plan_dft_r2c_2d(N, N, arr_in, arr_out, FFTW_ESTIMATE)
  plan_backward = fftw_plan_dft_c2r_2d(N, N, arr_out, arr_in, FFTW_ESTIMATE)


  !----------------------
  ! Setup
  !----------------------

  ! add +1: index = 1 corresponds to x=0
  ind1 = int(1.d0/dx)+1                     ! get index where x = 1
  ind2 = int((physical_length-1.d0)/dx)+1   ! get index where x = -1

  arr_in = 0
  ! y=0:
  arr_in(ind1, 1) =  sqrt(pi/2)
  arr_in(ind2, 1) =  -sqrt(pi/2)
  ! x=0:
  arr_in(1, ind1) =  sqrt(pi/2)
  arr_in(1, ind2) =  -sqrt(pi/2)


  !----------------------
  ! Forward
  !----------------------
  call fftw_execute_dft_r2c(plan_forward, arr_in, arr_out)

  write(*,*) "Verification: Max real part of arr_out:", maxval(real(arr_out))

  open(unit=666,file='./fftw_output_norm2d_fft_x=0.txt', form='formatted')
  open(unit=667,file='./fftw_output_norm2d_fft_y=0.txt', form='formatted')
  do i = 1, N
    write(666, '(2E14.5,x)') (i-1)*dk, aimag(arr_out(1,i))
  enddo
  do i = 1, N/2+1
    write(667, '(2E14.5,x)') (i-1)*dk, aimag(arr_out(i,1))
  enddo
  close(666)
  close(667)

  write(*,*) "Finished! Written results to fftw_output_normalisation_fft_x.txt and fftw_output_normalisation_fft_y.txt"


  !----------------------
  ! Backward
  !----------------------
  call fftw_execute_dft_c2r(plan_backward, arr_out, arr_in)

  ! Normalisation happens here!
  arr_in = arr_in/N**2

  open(unit=666,file='./fftw_output_norm2d_real_x=0.txt', form='formatted')
  open(unit=667,file='./fftw_output_norm2d_real_y=0.txt', form='formatted')
  do i = 1, N
    write(666, '(2E14.5,x)') (i-1)*dx, arr_in(1, i)
    write(667, '(2E14.5,x)') (i-1)*dx, arr_in(i, 1)
  enddo
  close(666)
  close(667)

  write(*,*) "Finished! Written results to fftw_output_norm2d_real_x=0.txt and fftw_output_norm2d_real_y=0.txt"

  deallocate(arr_in, arr_out)
  call fftw_destroy_plan(plan_forward)
  call fftw_destroy_plan( plan_backward)

end program use_fftw
以及python绘图工具:

#!/usr/bin/python3

#====================================
# Plots the results of the FFTW
# example programs.
#====================================

import numpy as np
import matplotlib.pyplot as plt
from sys import argv
from time import sleep

errormessage="""
I require an argument: Which output file to plot.
Usage: ./plot_fftw.py <case>
options for case:
    1   fftw_output_norm1d_fft.txt
    2   fftw_output_norm1d_real.txt
    3   fftw_output_norm2d_fft_x=0.txt
    4   fftw_output_norm2d_real_x=0.txt
    5   fftw_output_norm2d_fft_y=0.txt
    6   fftw_output_norm2d_real_y=0.txt


Please select a case: """

#----------------------
# Hardcoded stuff
#----------------------

file_dict={}
file_dict['1'] = ('fftw_output_norm1d_fft.txt', '1d Fourier transform')
file_dict['2'] = ('fftw_output_norm1d_real.txt', '1d Full circle')
file_dict['3'] = ('fftw_output_norm2d_fft_x=0.txt', '2d Fourier transform, x=0')
file_dict['4'] = ('fftw_output_norm2d_real_x=0.txt', '2d Full circle, x=0')
file_dict['5'] = ('fftw_output_norm2d_fft_y=0.txt', '2d Fourier transform, y=0')
file_dict['6'] = ('fftw_output_norm2d_real_y=0.txt', '2d Full circle, y=0')


#------------------------
# Get case from cmdline
#------------------------

case = ''

def enforce_integer():
    global case
    while True:
        case = input(errormessage)
        try:
            int(case)
            break
        except ValueError:
            print("\n\n!!! Error: Case must be an integer !!!\n\n")
            sleep(2)

if len(argv) != 2:
    enforce_integer()
else:
    try:
        int(argv[1])
        case = argv[1]
    except ValueError:
        enforce_integer()

filename,title=file_dict[case]


#-------------------------------
# Read and plot data
#-------------------------------

k, Pk = np.loadtxt(filename, dtype=float, unpack=True)

fig = plt.figure()

ax = fig.add_subplot(111)
#  ax.plot(k, Pk, label='power spectrum')
if case in ['1', '3', '5']:
    ax.plot(k, Pk, label='recovered wave', lw=3) # ignore negative k
    x = np.linspace(k.min(), k.max(), 1000)
    if case=='1':
        ax.plot(x, np.sin(2*np.pi*x), ':', label='expected wave', lw=3)
    if case in ['3', '5']:
        ax.plot(x, np.sin(x), ':', label='expected wave', lw=3)
    ax.set_title(title)
    ax.set_xlabel("k")
    ax.set_ylabel("F(k)")

if case in ['2', '4', '6']:
    # in this case: k=x, Pk=f(x)
    ax.plot(k, Pk, label='recovered original', lw=3) # ignore negative k
    N=1000
    plen=500
    dx=plen/N
    x = np.linspace(k.min(), k.max(), 1000)
    y = np.zeros(1000)
    ind = int(1.0/dx)

    if case=='2':
        y[ind] = -0.5
        y[-ind] = 0.5
    if case in ['4', '6']:
        y[ind] = np.sqrt(np.pi/2)
        y[-ind] = -np.sqrt(np.pi/2)

    ax.plot(x, y, ':', label='expected original', lw=3)
    ax.set_title(title)
    ax.set_xlabel("x")
    ax.set_ylabel("f(x)")

ax.legend()

plt.show()
!/usr/bin/python3
#====================================
#绘制FFTW的结果
#示例程序。
#====================================
将numpy作为np导入
将matplotlib.pyplot作为plt导入
从系统导入argv
从时间上导入睡眠
errormessage=“”
我需要一个参数:打印哪个输出文件。
用法:./plot\u fftw.py
案例选项:
1 fftw_输出_norm1d_fft.txt
2 fftw_output_norm1d_real.txt
3 fftw_输出_norm2d_fft_x=0.txt
4 fftw_输出_norm2d_real_x=0.txt
5 fftw_输出_norm2d_fft_y=0.txt
6 fftw_输出_norm2d_real_y=0.txt
请选择一个案例:“”
#----------------------
#硬编码的东西
#----------------------
文件_dict={}
文件dict['1']=('fftw\u output\u norm1d\u fft.txt','1d Fourier transform')
文件dict['2']=('fftw\u output\u norm1d\u real.txt','1d Full circle')
文件\u dict['3']=('fftw\u output\u norm2d\u fft\u x=0.txt','2d Fourier transform,x=0')
文件\u dict['4']=('fftw\u output\u norm2d\u real\u x=0.txt','2d Full circle,x=0')
文件_dict['5']=('fftw_output_norm2d_fft_y=0.txt','2d Fourier transform,y=0')
文件dict['6']=('fftw_output_norm2d_real_y=0.txt','2d Full circle,y=0')
#------------------------
#从cmdline获取案例
#------------------------
案例=“”
def enforce_integer():
全球案例
尽管如此:
案例=输入(错误消息)
尝试:
内部(案例)
打破
除值错误外:
打印(“\n\n!!!错误:大小写必须是整数!!!\n\n”)
睡眠(2)
如果len(argv)!=2:
强制执行_整数()
其他:
尝试:
int(argv[1])
case=argv[1]
除值错误外:
强制执行_整数()
文件名,title=file\u dict[大小写]
#-------------------------------
#读取和打印数据
#-------------------------------
k、 Pk=np.loadtxt(文件名,dtype=float,unpack=True)
图=plt.图()
ax=图添加_子批次(111)
#ax.图(k,Pk,label='power spectrum')
如果在['1','3','5']中出现大小写:
ax.plot(k,Pk,label='recovered wave',lw=3)#忽略负k
x=np.linspace(k.min(),k.max(),1000)
如果案例=='1':
ax.plot(x,np.sin(2*np.pi*x),“:”,label='expected wave',lw=3)
如果在['3','5']中出现大小写:
ax.plot(x,np.sin(x),“:”,label='expected wave',lw=3)
ax.设置标题(标题)
ax.集合标签(“k”)
ax.set_ylabel(“F(k)”)
如果在['2','4','6']中出现大小写:
#在这种情况下:k=x,Pk=f(x)
ax.plot(k,Pk,label='recovered original',lw=3)#忽略负k
N=1000
普兰=500
dx=正压/正压
x=np.linspace(k.min(),k.max(),1000)
y=np.零(1000)
ind=int(1.0/dx)
如果案例=='2':
y[ind]=-0.5
y[-ind]=0.5
如果在['4','6']中出现大小写:
y[ind]=np.sqrt(np.pi/2)
y[-ind]=-np.sqrt(np.pi/2)
ax.plot(x,y,,:',label='expected original',lw=3)
ax.设置标题(标题)
ax.集合标签(“x”)
ax.set_ylabel(“f(x)”)
ax.图例()
plt.show()

为什么你认为这是一个规范化问题?当波数错误时,这不仅仅是规范化问题。@VladimirF回答你所有的问题:主要是因为我在这方面是新手。我将函数更改为
fftw
,但结果保持不变。我能想到的另一件事是,我从根本上误解了fftw修道院离子,这就是为什么我