Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中计算数值导数的边界点?_Python_Arrays_Math_Numerical Methods - Fatal编程技术网

如何在python中计算数值导数的边界点?

如何在python中计算数值导数的边界点?,python,arrays,math,numerical-methods,Python,Arrays,Math,Numerical Methods,我试着写一个函数,求任意一般函数/数字数组的导数。具体来说,我使用的是一个。问题是,我无法计算导数的边界点,因为中心差分公式使用的是超出边界的指数。我的代码在下面 import numpy as np n = 20000 # number of points in array xs = np.linspace(start=-2*np.pi, stop=2*np.pi, num=n) # x values y = np.array([np.sin(i) for i in xs]) # our fu

我试着写一个函数,求任意一般函数/数字数组的导数。具体来说,我使用的是一个。问题是,我无法计算导数的边界点,因为中心差分公式使用的是超出边界的指数。我的代码在下面

import numpy as np
n = 20000 # number of points in array
xs = np.linspace(start=-2*np.pi, stop=2*np.pi, num=n) # x values
y = np.array([np.sin(i) for i in xs]) # our function, sine

def deriv(f, h):
    """
    Calauclate the numerical derivative of any function
    :param f: numpy.array(float), the array of numbers we differentiate
    :param h: step size
    :rtype d: numpy.array(float)
    """
    d = np.zeros_like(f)
    # this loop misses the first and last points in f
    for i in range(1, f.shape[0]-1):
        # 2-point formula
        d[i] = (f[i+1] - f[i-1])/(2*h)

    return d

h = abs(xs[0] - xs[1]) # step size
y1 = deriv(y, h) # first derivative
y2 = deriv(y1, h) # second derivative
y3 = deriv(y2, h) # third derivative
当我绘制y、y1、y2、y3时,你可以看到它在端点处爆炸

我试着在
deriv
中将端点设置为它们最近的邻居,如下所示。虽然这适用于低阶导数(第一阶和第二阶),但在高阶导数(第三阶和更高阶)时,它开始破裂

在中间,远离边界的导数计算得很好。问题在于边界

我应该如何处理这里的边界条件?不同的数值微分方案是否比中心差分方案更有效?


编辑:我正在寻找一种通用方法来解决这个问题,而不仅仅是一种可以应用于正弦函数或任何其他周期函数的方法,正如我在这里用来说明的那样。

这更多的是一个数值方法问题,而不是一个编程问题

无论如何,如果函数具有周期性边界条件(看起来是正弦波,所以在本例中具有周期性),只需创建一个包含2个附加元素的新数组:新数组的起始元素将是原始数组的最后一个元素,新数组的结束元素将是原始数组的起始元素。这里有一个方法

f_periodic = np.zeros(f.size+2)
f_periodic[1:-1], f_periodic[0], f_periodic[-1] = f, f[-1], f[0]
您现在可以在
f_periodic
上进行区分,
d[1]
d[-2]
将是边界上正确的导数值(忽略
d[0]
d[-1]

在OP的新要求后编辑…

对于更一般的边界条件,例如边界处的特定值,可以采用不同的方法:

  • 使用重影值:
  • 再次扩展新边界的函数和值。根据数值微分的顺序,需要更多的鬼细胞。对于当前方案,可以进行简单的线性外推(每个边界仅需要1个重影值):

    请注意,还必须扩展
    x
    。但是,由于具有恒定的间距,因此只需使用
    h
    而不是空间差,例如
    x[-2]-x[-3]
    。现在,您可以区分
    f_new
    ,并获得边界上导数的一阶近似值(因为您使用了线性外推来查找重影值)

  • 在边界上使用向前和向后方案

  • 我不会在这里显示代码,但基本上您需要分别使用边界值和左右边界的右(向前)或左(向后)值进行区分。这是一阶近似值。

    您可以对边界点使用2阶正向和反向微分方案。基本上,我们知道这一点

    (f(x+h)-f(x))/h = f'(x) + h/2*f''(x) + O(h²)                       (I)
    

    使用最后一个将一阶项替换为二阶导数,即计算
    (I)-h/2*(II)
    ,得到

    (-1/2*f(x+2h) + 2*f(x+h) -3/2*f(x))/h = f'(x) + O(h²)
    

    请注意,一阶导数中的O(h²)误差通常会导致除差的第二次迭代中的O(h)误差和第三次迭代中的O(1)。有人可能会认为误差项会适当地抵消,但这只会发生在内部点上,单侧导数会随着距离边界的增加而“破坏”该模式。

    忽略极端
    x
    值及其相应的奇异性。这不是通常的做法吗?或者至少是一种常用的方法?如果你不喜欢这样,在-ve和+ve方向上扩展
    x
    一步,忽略扩展的肢体。这不是一个真正的编程问题,它更多的是一个数值分析方法。谢谢,但我真的在寻找一个通用的解决方案,而不仅仅是周期性的b.c。我在这里的示例中使用正弦函数,因为它很容易绘制和验证计算的导数是否正确,但我想将其扩展到更一般的函数,即具有类似Dirichlet边界条件的函数(边界处的特定值)?你没有在你的问题中详细说明这一点,所以我回答了你的问题--不只是适用于ODE和PDE吗?我只是在这里讨论函数的高阶导数,它们对于微分非常有用。无论如何,我会更新我的答案,以获得更一般的边界条件。新的答案对你有帮助吗?
    (f(x+h)-f(x))/h = f'(x) + h/2*f''(x) + O(h²)                       (I)
    
    (f(x+2h) - 2f(x+h) + f(x))/h² = f''(x+h) + O(h²) = f''(x) + O(h)   (II)
    
    (-1/2*f(x+2h) + 2*f(x+h) -3/2*f(x))/h = f'(x) + O(h²)