这个傅里叶变换有什么问题?(python语言)

这个傅里叶变换有什么问题?(python语言),python,numpy,fft,pyfftw,Python,Numpy,Fft,Pyfftw,读过我以前在这个网站上的文章的人都知道,我一直在尝试在Python中实现一个使用FFT的PDE解算器。编程部分大部分都已完成,但程序会产生一个(非常适合此站点)溢出错误(基本上,它会增长很多,直到变成一个NaN) 排除所有其他可能性后,我将问题锁定在FFT和我尝试进行导数的方式上,因此我决定用以下代码测试两个不同的FFT(numpyFFT模块和pyFFTW包): import pyfftw import numpy as np import matplotlib.pyplot as plt

读过我以前在这个网站上的文章的人都知道,我一直在尝试在Python中实现一个使用FFT的PDE解算器。编程部分大部分都已完成,但程序会产生一个(非常适合此站点)溢出错误(基本上,它会增长很多,直到变成一个
NaN

排除所有其他可能性后,我将问题锁定在FFT和我尝试进行导数的方式上,因此我决定用以下代码测试两个不同的FFT(
numpy
FFT
模块和
pyFFTW
包):

import pyfftw
import numpy as np
import matplotlib.pyplot as plt


def fftw_(y: np.ndarray) -> np.ndarray:
    a = pyfftw.empty_aligned((N, N), dtype=np.float64)
    b = pyfftw.empty_aligned((N, N//2+1), dtype=np.complex128)
    fft_object = pyfftw.FFTW(a, b, axes=(0, 1), direction='FFTW_FORWARD', flags=('FFTW_MEASURE',), threads=12)
    y_hat = fft_object(y)
    return y_hat


def ifftw_(y_hat: np.ndarray) -> np.ndarray:
    a = pyfftw.empty_aligned((N, N//2+1), dtype=np.complex128)
    b = pyfftw.empty_aligned((N, N), dtype=np.float64)
    fft_object = pyfftw.FFTW(a, b, axes=(0, 1), direction='FFTW_BACKWARD', flags=('FFTW_MEASURE',), threads=12)
    y = fft_object(y_hat)
    return y


def func(x: np.ndarray, y: np.ndarray) -> np.ndarray:
    return np.exp(x)*np.sin(y)

dx = 0.02

x = np.arange(-1, 1, dx)
y = np.arange(-1, 1, dx)
X, Y = np.meshgrid(x, y)

N = len(x)

kxw, kyw = np.meshgrid(np.fft.rfftfreq(N, dx), np.fft.fftfreq(N, dx))
Lapw = -4*np.pi**2*(kxw**2+kyw**2)

kxnp, kynp = np.meshgrid(np.fft.fftfreq(N, dx), np.fft.fftfreq(N, dx))
Lapnp = -4*np.pi**2*(kxnp**2+kynp**2)



z = func(X, Y)

lap_z_w = ifftw_(Lapw*fftw_(z))
lap_z_np = np.fft.ifft2(Lapnp*np.fft.fft2(z))

lap_z_np_mag = np.abs(lap_z_np)
lap_z_np_ang = np.angle(lap_z_np)

plt.imshow(z, cmap='plasma')
plt.colorbar()
plt.savefig("f.png", dpi=200)
plt.clf()

plt.imshow(lap_z_w, cmap='plasma')
plt.colorbar()
plt.savefig("Lap_fftw.png", dpi=200)
plt.clf()

plt.imshow(lap_z_np_mag, cmap='plasma')
plt.colorbar()
plt.savefig("Lap_np_mag.png", dpi=200)
plt.clf()

plt.imshow(lap_z_np_ang, cmap='plasma')
plt.colorbar()
plt.savefig("Lap_np_ang.png", dpi=200)
plt.clf()
这里的
np.ndarray
命名为
Lapw
Lapnp
我认为应该做的离散拉普拉斯算子。我选择的函数eˣsin(y)是一个调和函数,所以它的拉普拉斯函数应该为零

但该计划的结果与预期值相差甚远。我特别得到:

原始函数f

f与pyFFTW的“拉普拉斯式”

带Numpy的f的“拉普拉斯”的大小和相位


查看这些图的值(请注意颜色栏中的范围,20000不是0的任何适当近似值)可以清楚地说明为什么我制作的程序会产生溢出,但我不知道如何纠正这一点。非常感谢您的帮助。

这里的错误在于您对功能的假设不正确。e^x sin(y)可能看起来是调和的,但您只计算了-1fft将定期隐式地继续它,即在函数的所有边上都会出现间断。如果函数不是连续的,它就不是调和的,尤其是在傅里叶变换中,你会得到发散。这就是FFT在边缘发散的原因。除此之外,“远离”边缘,结果看起来和预期的一样。

这里的错误在于你对函数的假设是不正确的。e^x sin(y)可能看起来是调和的,但您只计算了-1fft将定期隐式地继续它,即在函数的所有边上都会出现间断。如果函数不是连续的,它就不是调和的,尤其是在傅里叶变换中,你会得到发散。这就是FFT在边缘发散的原因。除此之外,“远离”边缘,结果看起来和预期的一样。

绘图对我来说似乎很好。你期望一个零拉普拉斯。你得到一个零拉普拉斯算子。角度由浮点舍入误差给出(当然,复数+i*的角度是任意的)。还有一些边缘效果,这在DFT中是预期的。你需要意识到你的数值计算产生了一个你希望得到的结果的近似值,它不是零。侧面的颜色条是自动生成的,如您所见,它会根据所进行的变换而增加到20000-25000。这是不正确的。如果误差是1/100甚至1/10,我会说这是一个很好的近似值。即使是函数的一阶偏导数也应该限制在2-4左右,达到20000意味着一定有一个错误,那就是边缘效应。获取输入数据的多个副本,假装它们是平铺,然后将平铺彼此相邻。您将看到两块瓷砖之间有一个非常尖锐的过渡。基于DFT的过滤对这种转换作出反应。要么(1)忽略域边缘附近的输出,要么(2)对输入数据应用窗口功能,然后也忽略域边缘附近的输出。你不能期望在边缘附近得到有意义的结果,那里没有数据来计算导数。是的,如果你通过傅里叶域进行过滤,你的过滤器就有无限的定义支持。所有输出都受边缘效果的影响。只有少数靠近边缘的样本才是明显的。如果以不同的方式缩放数据,您可能会注意到更多受影响的示例。如果效果太强,请使用窗口功能。或者用一个有限差分近似来代替导数。这些图对我来说很好。你期望一个零拉普拉斯。你得到一个零拉普拉斯算子。角度由浮点舍入误差给出(当然,复数+i*的角度是任意的)。还有一些边缘效果,这在DFT中是预期的。你需要意识到你的数值计算产生了一个你希望得到的结果的近似值,它不是零。侧面的颜色条是自动生成的,如您所见,它会根据所进行的变换而增加到20000-25000。这是不正确的。如果误差是1/100甚至1/10,我会说这是一个很好的近似值。即使是函数的一阶偏导数也应该限制在2-4左右,达到20000意味着一定有一个错误,那就是边缘效应。获取输入数据的多个副本,假装它们是平铺,然后将平铺彼此相邻。您将看到两块瓷砖之间有一个非常尖锐的过渡。基于DFT的过滤对这种转换作出反应。要么(1)忽略域边缘附近的输出,要么(2)对输入数据应用窗口功能,然后也忽略域边缘附近的输出。你不能期望在边缘附近得到有意义的结果,那里没有数据来计算导数。是的,如果你通过傅里叶域进行过滤,你的过滤器就有无限的定义支持。所有输出都受边缘效果的影响。只有少数靠近边缘的样本才是明显的。如果以不同的方式缩放数据,您可能会注意到更多受影响的示例。如果效果太强,请使用窗口功能。或者使用导数的有限差分近似。