多项式插值(数值计算方法)Python实现

一. 原理介绍

  1. 关于插值的定义及基本原理可以参照如下索引
    插值原理(数值计算方法)
  2. 前面已经介绍过插值原理的唯一性表述,对于分立的数据点,方程组:

P ( x 0 ) = y 0 ⇒ a 0 + a 1 x 0 + a 2 x 0 2 + ⋯ + a n x 0 n = y 0 , P ( x 1 ) = y 1 ⇒ a 0 + a 1 x 1 + a 2 x 1 2 + ⋯ + a n x 1 n = y 1 , ⋮ P ( x n ) = y n ⇒ a 0 + a 1 x n + a 2 x n 2 + ⋯ + a n x n n = y n . \begin{aligned} & P(x_0) = y_0 \quad \Rightarrow \quad a_0 + a_1 x_0 + a_2 x_0^2 + \cdots + a_n x_0^n = y_0, \\ & P(x_1) = y_1 \quad \Rightarrow \quad a_0 + a_1 x_1 + a_2 x_1^2 + \cdots + a_n x_1^n = y_1, \\ & \quad \vdots \\ & P(x_n) = y_n \quad \Rightarrow \quad a_0 + a_1 x_n + a_2 x_n^2 + \cdots + a_n x_n^n = y_n. \end{aligned} P(x0)=y0a0+a1x0+a2x02++anx0n=y0,P(x1)=y1a0+a1x1+a2x12++anx1n=y1,P(xn)=yna0+a1xn+a2xn2++anxnn=yn.

恒有解,多项式插值的目标即为在这一过程中求解系数 a 0 、 a 1 、 . . . 、 a n ⟺ [ a 0 a 1 a 2 ⋮ a n ] a_0、a_1、...、a_n\Longleftrightarrow\begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ \vdots \\ a_n \end{bmatrix} a0a1...an a0a1a2an

  1. 即解方程组:
    [ 1 x 0 x 0 2 ⋯ x 0 n 1 x 1 x 1 2 ⋯ x 1 n ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n x n 2 ⋯ x n n ] [ a 0 a 1 a 2 ⋮ a n ] = [ y 0 y 1 y 2 ⋮ y n ] . \begin{bmatrix} 1 & x_0 & x_0^2 & \cdots & x_0^n \\ 1 & x_1 & x_1^2 & \cdots & x_1^n \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & x_n & x_n^2 & \cdots & x_n^n \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ \vdots \\ a_n \end{bmatrix}= \begin{bmatrix} y_0 \\ y_1 \\ y_2 \\ \vdots \\ y_n \end{bmatrix}. 111x0x1xnx02x12xn2x0nx1nxnn a0a1a2an = y0y1y2yn .

关于该方程组的解法在线性代数中有多种,这里主要提及两种:
①高斯消元法
②克莱姆法则
程序设计过程中一般有封装好的库函数,如果为了考虑减少库依赖和提高程序运行效率及占用可能会用到上述方法(这里就不详细展开了)


二. 程序设计

1. 构建矩阵

A = np.zeros((n, n))
for i in range(n):
    for j in range(n):
        A[i, j] = x_data[i] ** j

Ⅰ 构建一个 ( n × n ) (n \times n) (n×n)的矩阵 A 来描述多项式矩阵:
[ 1 x 0 x 0 2 ⋯ x 0 n 1 x 1 x 1 2 ⋯ x 1 n ⋮ ⋮ ⋮ ⋱ ⋮ 1 x n x n 2 ⋯ x n n ] \begin{bmatrix} 1 & x_0 & x_0^2 & \cdots & x_0^n \\ 1 & x_1 & x_1^2 & \cdots & x_1^n \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & x_n & x_n^2 & \cdots & x_n^n \end{bmatrix} 111x0x1xnx02x12xn2x0nx1nxnn

其中:
A [ i ] [ j ] = x i j A[i][j] = x_{i}^{j} A[i][j]=xij

式中第一列的1是通过 x i 0 x_{i}^{0} xi0得到的。

B = np.array(y_data)

Ⅱ 构建系数矩阵 B,即原始数据对应的 y 值:

2. 求解矩阵方程

coefficients = np.linalg.solve(A, B)

使用Numpy自带函数linalg.solve()解矩阵方程

注释np.linalg.solve(A, B) 求解出的系数数组的顺序是 从低到高次项,即:

  • coefficients[0] 为常数项( x 0 x^0 x0 的系数)
  • coefficients[1] 为一次项( x 1 x^1 x1 的系数)
  • coefficients[2] 为二次项( x 2 x^2 x2 的系数)
    以此类推。

求解出矩阵形式形如
[ 6. -7.83333333 4.5 -0.66666667]
从左至右为最低次项到最高次项系数

3. 作出多项式函数

x_data, y_data = zip(*data)

Ⅰ 获取输入数据(方法不唯一)

x_vals = np.linspace(min(x_data) - 1, max(x_data) + 1, 500)

Ⅱ 在数据点区间内构造间隔点来使绘图更加平滑(matplotlib.pyplot的局限性)

y_vals = np.polyval(coefficients[::-1], x_vals)

Ⅲ 通过Numpy内置函数np.polyval()来构造多项式函数(需要指定多项式系数),实现输入 x 值,输出通过构造的多项式函数对应的函数值。

注释: 前面注释提到coefficients数组中的系数对应从左到右为最低到最高次项系数,而函数np.polyval()要求输入具有逆序的项系数:coefficients[::-1] 将变为从最高次到最低次项系数
np.polyval(coefficients[::-1], x_vals) 将计算每一个 x_val 对应的多项式值,并返回一个 y_vals 数组,包含每个 x_val 对应的 y 值。

4. 绘制插值曲线

	plt.rcParams['font.family'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False

通过替换显示字体('SimHei')和符号(False)来使图例正常显示中文和负号

    plt.plot(x_vals, y_vals, label="插值曲线", color='b')
    plt.scatter(x_data, y_data, color='r', label="数据点")
    plt.title("插值多项式")
    plt.xlabel("X轴")
    plt.ylabel("Y轴")
    plt.legend()
    plt.grid(True)
    plt.show()

5. 完整代码

import numpy as np
import matplotlib.pyplot as plt


def construct_interpolation_polynomial(data):
    # 提取x和y值
    x_data, y_data = zip(*data)
    n = len(data)

    # 构造矩阵A (n x n)
    A = np.zeros((n, n))

    # 构造矩阵A的每一列, A[i][j] = x_i^(j)
    for i in range(n):
        for j in range(n):
            A[i, j] = x_data[i] ** j

    # 构造常数向量B,B[i] = y_i
    B = np.array(y_data)

    # 解线性方程组 A * coefficients = B
    coefficients = np.linalg.solve(A, B)

    return coefficients


def plot_interpolation(data, coefficients):
    # 提取x和y值
    x_data, y_data = zip(*data)

    # 生成插值多项式的x和y值
    x_vals = np.linspace(min(x_data) - 1, max(x_data) + 1, 500)

    # 计算多项式的y值
    y_vals = np.polyval(coefficients[::-1], x_vals)

    # 绘图
    plt.rcParams['font.family'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    plt.plot(x_vals, y_vals, label="插值曲线", color='b')
    plt.scatter(x_data, y_data, color='r', label="数据点")
    plt.title("插值多项式")
    plt.xlabel("X轴")
    plt.ylabel("Y轴")
    plt.legend()
    plt.grid(True)
    plt.show()


# 定义输入数据 (xi, yi)
data = [
    [1, 2],
    [2, 3],
    [3, 5],
    [4, 4]
]

# 构造插值多项式的系数
coefficients = construct_interpolation_polynomial(data)

# 输出多项式的系数
print("插值多项式的系数:", coefficients)

# 绘制插值曲线
plot_interpolation(data, coefficients)


三. 图例

这要求我们的输入数据都具有上述形式:

data = [
    [x_1, y_1],
    [x_2, y_2],
    [x_3, y_3],
    [x_4, y_4],
    ...]

最后我们插值一组随机生成的测试数据

data = [
    [7.264384, 3.931292],
    [1.943873, 6.218903],
    [8.384019, 2.584103],
    [5.672210, 9.032674],
    [0.294315, 4.726018],
    [6.129531, 7.912846],
    [9.516347, 1.478264],
    [3.824679, 5.596042]
]

实际应用时应避免数据点过多导致的多项式次数过高


希望能够帮到迷途之中的你,知识有限,如有学术错误请及时指正,感谢大家的阅读

(^^)/▽ ▽\(^^)
### 五次多项式插值法在MATLAB中实现机械臂控制 为了实现在MATLAB中利用五次多项式插值法进行机械臂控制,可以采用如下方法: 定义起始位置、目标位置以及时间间隔作为输入变量。对于五次多项式而言,其一般形式为\[ q(t)=a_{0}+a_{1}t+a_{2}t^{2}+a_{3}t^{3}+a_{4}t^{4}+a_{5}t^{5}\] ,其中\(q\)表示关节角度或者末端执行器的位置,而系数\(\{a_i|i=0,...,5\}\)则由边界条件决定。 通过设定初始时刻的速度和加速度都等于零,并指定结束时刻的速度也为零来求解这些未知数。具体来说就是建立方程组并求得各个系数的具体数值[^1]。 下面给出一段简单的代码片段用于演示如何创建一个五阶多项式的轨迹规划函数,在此过程中假设已知起点坐标`startPos`, 终点坐标`endPos` 和总耗时 `T_total`. ```matlab function traj = fifthPoly(startPos,endPos,T_total,t) % 定义符号变量 syms a b c d e f t; eqns = [ startPos == a; endPos == a+b*T_total+c*(T_total^2)+d*(T_total^3)+e*(T_total^4)+f*(T_total^5); diff(a*t,'t',0)==diff(b*t,'t')+2*c*t+3*d*t^2+4*e*t^3+5*f*t^4|subs('t'=0); diff(endPos,'t')==diff(a+b*t+c*t^2+d*t^3+e*t^4+f*t^5,'t')|subs('t'=T_total); diff(diff(startPos,'t'),'t')==diff(diff(a*t,'t','t'), 't')+2*diff(c*t,'t')+6*d*t+12*e*t^2+20*f*t^3 | subs('t' = 0); diff(diff(endPos,'t'),'t')==diff(diff(a+b*t+c*t^2+d*t^3+e*t^4+f*t^5,'t','t'),'t') | subs('t'= T_total)]; sol = solve(eqns,[a,b,c,d,e,f]); A=[sol.a,sol.b,sol.c,sol.d,sol.e,sol.f]; p=A(1)*ones(size(t))+A(2).*t+A(3).*(t.^2)+A(4).*(t.^3)+A(5).*(t.^4)+A(6).*(t.^5); v=(A(2)+2*A(3).*t+3*A(4).*(t.^2)+4*A(5).*(t.^3)+5*A(6).*(t.^4)); a=(2*A(3)+6*A(4).*t+12*A(5).*(t.^2)+20*A(6).*(t.^3)); traj.Position=p'; traj.Velocity=v'; traj.Acceleration=a'; end ``` 上述代码实现了给定两个端点之间的平滑过渡路径计算过程,并返回了对应的时间序列上的位移、速度及加速度向量。需要注意的是实际应用时还需要考虑更多因素比如物理极限约束等[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是你呀星途

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值