首页 > 解决方案 > 如何在 Python 中仅在特定点进行平滑样条插值设置导数?

问题描述

TL;博士

显然scipy没有提供类似于 MATLAB 的方法,该方法spapi允许仅在特定点设置导数,从而确保沿插值样条的平滑过渡。我想找到一种在 Python 中做到这一点的方法。

全面的

我的目标是使用 Python 3 进行样条插值,但仅在特定点设置所需的导数。例如,假设数组 X 定义了一个对象的位置,点对点,我想要一个样条曲线来表示一个可行的轨迹,但还要确保速度(一阶导数)在起点和终点都为零,其他点对衍生品没有限制。在此示例中,我还希望在相同点处使加速度(二阶导数)为零。

换句话说,我想要的是类似于 MATLABspapi函数的样条插值的实现,如下所示

spline = spapi(knots,x,y)返回顺序的样条f(如果有)

k = length(knots) - length(x)

带有结序列的结

(*) f(x(j)) = y(:,j), all j.

如果 的某些条目x是相同的,那么这是在接触意义上的,即在Dm(j)f(x(j)) = y(:, j)m(j) : = #{ i < j : x(i) = x(j) }fDmfmth导数的意义上。因此,位点in的 r 倍重复对应于值的规定和f at的一阶导数。zxr – 1z

我试过的

我知道 的 类的方法from_derivativesBPoly但这scipy.interpolate带来了一个关键问题,即当未在任何点指定导数时,该算法不能保证平滑过渡,如此所述。我也尝试了这里提出的建议,但正如预期的那样,出现了同样的问题。

所以,接下来我将简单复制我想要实现的目标,无论成功与否。

spapi没有衍生品

spapi这里是在 MATLAB 中使用方法的示例,没有设置任何导数。不是我想要的,因为导数在起点和终点都很高:

xi = linspace(0, 10, 6);
xnew = linspace(0, 10, 100);

yi = [0 2 1 4 2 0];

knots = optknt(xi, order);
ref_spline = spapi(knots, xi, yi);

spline = fnval(xnew, ref_spline);
der_spline = gradient(spline);

以及相应的参考点图以及插值样条曲线: 不设置导数的样条插值,使用 <code>spapi</code>

这里是该样条的一阶导数: 插值样条的一阶导数

spapi与衍生品

在这里,使用spapiMATLAB 中的方法的示例,将导数设置为0起点和终点。完全符合预期结果,沿样条曲线平滑过渡,导数等于0起点和终点:

xi = linspace(0, 10, 6);
xnew = linspace(0, 10, 100);
xder = [0 xi 10];

yi = [0 2 1 4 2 0];
ynew = [0 yi 0];

knots = optknt(xder, order);
ref_spline = spapi(knots, xder, ynew);

spline = fnval(xnew, ref_spline);
der_spline = gradient(spline);

参考点图和样条曲线: 样条插值在开始和结束时将导数设置为零,使用 <code>spapi</code>

这里是该样条的一阶导数: 插值样条的一阶导数

BPoly.from_derivatives与衍生品

在这里,使用BPoly.from_derivatives 将导数设置为0起点和终点的示例。不成功,即使导数0在起点和终点,也不能保证沿样条线平滑过渡:

ref_points = [0, 2, 1, 4, 2, 0]
time_vector = np.linspace(0, 10, 100)
time_points = np.linspace(0, 10, 6)

ref_complete = [[ref_points[j] if (i == 0) else 0 for i in range(2)] if (
    (j == 0) or (j == len(ref_points) - 1)) else [ref_points[j]] for j in range(len(ref_points))]

ref_spline = BPoly.from_derivatives(time_points, ref_complete)
spline = ref_spline(time_vector)

der_spline = ref_spline.derivative(1)
der_y = der_spline(time_vector)

澄清一下,定义的行ref_complete简单地将 的第一个和最后一个元素替换为ref_points一个数组,该数组包含 index 处的原始值和 index处0的 a :01

>>> ref_points
[0, 2, 1, 4, 2, 0]
>>> ref_complete
[[0, 0], [2], [1], [4], [2], [0, 0]]

参考点图和样条曲线: 样条插值在开始和结束时将导数设置为零,使用 <code>BPoly.from_derivatives</code>

这里是该样条的一阶导数: 插值样条的一阶导数

标签: pythonmatlabscipyinterpolationspline

解决方案


如果您只想在两端使用零导数进行三次样条插值,这就足够了(此处的文档

from scipy.interpolate import CubicSpline

CubicSpline(time_points, ref_points, bc_type="clamped")

推荐阅读