使用 SciPy 的样条的高阶导数

计算科学 Python 插值
2021-12-07 09:11:46

我创建了一个样条曲线来适应我在 python 中的数据,使用:

spline=scipy.interpolate.UnivariateSpline(energy, fpp, k=4)

我想使用的方程涉及 n=2 和 n=infinity 之间的总和,其中 n 是点 Eo 的微分阶数。但是,使用;

UnivariateSpline.__call__(spline, e0, nu=n)

要调用该值,我无法获得超过四阶微分的任何值。人们知道评估此功能的任何其他功能吗?在大约 8 阶以上有一个预乘数,它应该将值设置为零,但我仍然需要高于 4 阶。

4个回答

如果您需要高阶导数,则使用等距数据点不会得到好的结果。如果您可以在任意节点对函数进行采样,我建议您使用 Chebyshev 点,即用于多项式度数

xk=cos(πkn),k=0n
n

您可以使用Barycentric Interpolation稳定地评估多项式请注意,由于您在整个区间内使用高次多项式,因此您可能需要更少的数据点。另请注意,这假设您的数据可以用多项式表示,即它是连续且平滑的。

从插值中获得高阶导数有点棘手,并且不适用于高阶导数。然而,它可以使用切比雪夫多项式来完成。但是,在 Matlab/Octave 中(对不起,我的 Python 一点都不好),您可以执行以下操作:

% We will use the sine function as a test case
f = @(x) sin( 4*pi*x );

% Set the number of points and the interval
N = 40;
a = 0; b = 1;

% Create a Vandermonde-like matrix for the interpolation using the
% three-term recurrence relation for the Chebyshev polynomials.
x = cos( pi*[0:N-1]/(N-1) )';
V = ones( N ); V(:,2) = x;
for k=3:N, V(:,k) = 2*x.*V(:,k-1) - V(:,k-2); end;

% Compute the Chebyshev coefficients of the interpolation. Note that we
% map the points x to the interval [a,b]. Note also that the matrix inverse
% can be either computed explicitly or evaluated using a discrete cosine transform.
c = V \ f( (a+b)/2 + (b-a)/2*x );

% Compute the derivative: this is a bit trickier and relies on the relationship
% between Chebyshev polynomials of the first and second kind.
temp = [ 0 ; 0 ; 2*(N-1:-1:1)'.*c(end:-1:2) ];
cdiff = zeros( N+1 , 1 );
cdiff(1:2:end) = cumsum( temp(1:2:end) );
cdiff(2:2:end) = cumsum( temp(2:2:end) );
cdiff(end) = 0.5*cdiff(end);
cdiff = cdiff(end:-1:3);

% Evaluate the derivative fp at the nodes x. This is useful if you want
% to use Barycentric Interpolation to evaluate it anywhere in the interval.
fp = V(:,1:n-1) * cdiff;

% Evaluate the polynomial and its derivative at a set of points and plot them.
xx = linspace(-1,1,200)';
Vxx = ones( length(xx) , N ); Vxx(:,2) = xx;
for k=3:N, Vxx(:,k) = 2*xx.*Vxx(:,k-1) - Vxx(:,k-2); end;
plot( (a+b)/2 + (b-a)/2*xx , [ Vxx*c , Vxx(:,1:N-1)*cdiff ] );

计算导数的代码可以多次重新应用以计算更高的导数。

如果您使用 Matlab,您可能会对Chebfun项目感兴趣,该项目会自动完成大部分工作,并且上面的代码示例的部分内容取自。Chebfun 可以从字面上任何函数创建插值,例如连续、不连续、具有奇异性等......然后计算它的积分、导数,用它来解决 ODE 等......

检查该对象的文档UnivariateSpline,似乎您正在构建一个 4 阶样条曲线,这就是为什么您无法获得大于 4 阶导数的值的原因。(如您所知,所有这些导数都将为零。)

SciPy 将样条曲线的多项式次数限制为 5 阶或更小(即k <= 5)。如果您需要 8 阶多项式样条插值,您必须找到一个替代库,或者可能自己编写代码。

默认情况下,您使用三次样条,它是三阶分段多项式。如果对 3 阶多项式求四阶导数,最终会得到 0。如果你真的需要这些高阶微分,那么使用三次样条不会对你有任何好处。

在 Scipy 中,如果您尝试计算 k 阶样条的 n 阶导数,其中 n > k,那么您会得到ValueError

ValueError: 0<=der=5<=k=4 必须保持

你可以这样写:

def spline_der(spline, x, nu=0):
    sd = 0
    try:
        sd = spline(x, nu=nu)
    except ValueError:
        pass
    return sd

PS:如您所见,__call__您可以简单地编写,而不是使用

spline(e0, nu=n)