求解微分方程时的高频噪声

时间:2014-04-23 15:25:29

标签: python numpy physics scientific-computing differential-equations

我正在尝试模拟基于Fick's 2nd law的简单扩散。

from pylab import *
import numpy as np
gridpoints = 128

def profile(x):
    range = 2.
    straggle = .1576
    dose = 1 
    return dose/(sqrt(2*pi)*straggle)*exp(-(x-range)**2/2/straggle**2)

x = linspace(0,4,gridpoints)
nx = profile(x)
dx = x[1] - x[0] # use np.diff(x) if x is not uniform
dxdx = dx**2

figure(figsize=(12,8))

plot(x,nx)
timestep = 0.5
steps = 21
diffusion_coefficient = 0.002
for i in range(steps):
    coefficients = [-1.785714e-3, 2.539683e-2, -0.2e0, 1.6e0,
                    -2.847222e0,
                    1.6e0, -0.2e0, 2.539683e-2, -1.785714e-3]
    ccf = (np.convolve(nx, coefficients) / dxdx)[4:-4] # second order derivative
    nx = timestep*diffusion_coefficient*ccf + nx
    plot(x,nx)

output with noise

对于前几个步骤,一切看起来都很好,但随后我开始得到高频噪声,从数值误差中积累,这些误差通过二阶导数放大。由于似乎很难增加浮点精度,我希望我能做些什么来抑制它?我已经增加了用于构建二阶导数的点数。

1 个答案:

答案 0 :(得分:4)

我没有时间详细研究您的解决方案,但似乎您正在用forward Euler scheme解决偏微分方程。正如您所示,这很容易实现,但如果您的时间步长太小,这可能会变得数值不稳定。您唯一的解决方案是缩短时间步长或提高空间分辨率。

最简单的解释方法是针对1-D案例:假设您的注意力是空间坐标x和时间步长i的函数。如果你做了所有的数学运算(写下你的方程,用finite differences代替偏导数,应该很简单),你可能会得到这样的结果:

C(x, i+1) = [1 - 2 * k] * C(x, i) + k * [C(x - 1, i) + C(x + 1, i)]

所以下一步的一个点的浓度取决于它的先前值和它的两个邻居的值。当k = 0.5,每个点被其两个邻居的平均值取代时,不难看出,[...,0,1,0,1,0,...]的浓度曲线将在下一步变为[...,1,0,1,0,1,...]。如果k > 0.5,此类个人资料将呈指数级增长。你用较长的卷积计算你的二阶导数(我有效地使用[1,-2,1]),但我想这对于不稳定性问题没有任何改变。

我不了解正常扩散,但根据热扩散的经验,我猜测kdt * diffusion_coeff / dx^2成比例。因此,您必须选择足够小的时间步长,以便模拟不会变得不稳定。为了使模拟稳定,但仍然尽可能快,请选择参数,使k略小于0.5。对于2-D和3-D情况,可以得出类似的东西。实现此目标的最简单方法是增加dx,因为对于线性问题,您的总计算时间将缩放1/dx^3,对于二维问题,1/dx^4甚至会1/dx^5。对于三维问题。

有更好的方法来解决扩散方程,我相信Crank Nicolson至少是求解热方程的标准(这也是一个扩散问题)。问题'这是一个implicit方法,这意味着您必须解决一组方程式来计算您的浓度'在下一个时间步,实施起来有点痛苦。但是这种方法保证数值稳定,即使对于大的时间步也是如此。