def central_diff_weights(Np,ndiv=1): """Return weights for an Np-point central derivative of order ndiv assuming equally-spaced function points. If weights are in the vector w, then derivative is w[0] * f(x-ho*dx) + ... + w[-1] * f(x+h0*dx) Can be inaccurate for large number of points. """ assert (Np >= ndiv+1), "Number of points must be at least the derivative order + 1." assert (Np % 2 == 1), "Odd-number of points only." ho = Np >> 1 x = arange(-ho,ho+1.0) x = x[:,NewAxis] X = x**0.0 for k in range(1,Np): X = hstack([X,x**k]) w = product(arange(1,ndiv+1))*linalg.inv(X)[ndiv] return w
def derivative(func,x0,dx=1.0,n=1,args=(),order=3): """Given a function, use a central difference formula with spacing dx to compute the nth derivative at x0. order is the number of points to use and must be odd. Warning: Decreasing the step size too small can result in round-off error. """ assert (order >= n+1), "Number of points must be at least the derivative order + 1." assert (order % 2 == 1), "Odd number of points only." # pre-computed for n=1 and 2 and low-order for speed. if n==1: if order == 3: weights = array([-1,0,1])/2.0 elif order == 5: weights = array([1,-8,0,8,-1])/12.0 elif order == 7: weights = array([-1,9,-45,0,45,-9,1])/60.0 elif order == 9: weights = array([3,-32,168,-672,0,672,-168,32,-3])/840.0 else: weights = central_diff_weights(order,1) elif n==2: if order == 3: weights = array([1,-2.0,1]) elif order == 5: weights = array([-1,16,-30,16,-1])/12.0 elif order == 7: weights = array([2,-27,270,-490,270,-27,2])/180.0 elif order == 9: weights = array([-9,128,-1008,8064,-14350,8064,-1008,128,-9])/5040.0 else: weights = central_diff_weights(order,2) else: weights = central_diff_weights(order, n) val = 0.0 ho = order >> 1 for k in range(order): val += weights[k]*func(x0+(k-ho)*dx,*args) return val / product((dx,)*n)