数值分析——三次样条插值

news2024/11/16 5:27:13

系列文章目录

数值分析——拉格朗日插值
数值分析——牛顿插值多项式
数值分析——埃尔米特(Hermit)插值
数值分析——分段低次插值


文章目录

  • 系列文章目录
  • 前言
  • 一、理论推导
    • 1.三次样条函数
    • 2.三次样条插值函数的求解条件
    • 3.三次样条插值函数的建立
  • 二、MATLAB实现
    • 1.一阶导数边界条件
    • 2.二阶导数边界条件
    • 3.测试程序
  • 总结
  • 参考文献


前言

  在之前的博文中接受少了分段低次插值函数,该插值函数具有一致的收敛性,但是光滑性较差,对于像高速飞机的机翼形线,船体放样等型值线往往要求有二阶光滑度,即二阶导数连续。样条曲线是由分段三次曲线并接而成,在连接点上二阶导数连续。本文将介绍以此为理念设计的三次样条插值函数。

本文对一些复杂的流程与概念进行了简化与省略,如果想详细了解的小伙伴可以参考李庆扬老师的《数值分析 -第5版》的第2章(需要电子版请私戳)


一、理论推导

1.三次样条函数

  设计一个函数 S ( x ) S\left( x \right) S(x)属于在区间 [ a , b ] [a,b] [a,b]上二阶导数连续的函数空间,即 S ( x ) ∈ C 2 [ a , b ] S\left( x \right) \in C^2 \left[ a,b \right] S(x)C2[a,b]。该函数在每个小区间 [ x j , x j + 1 ] \left[ x_{j},x_{j+1} \right] [xj,xj+1]上是三次多项式,其中 a = x 0 < x 1 < ⋯ < x n = b a=x_0<x_1<\cdots<x_n=b a=x0<x1<<xn=b,则称该 S ( x ) S\left( x \right) S(x)是节点 x 0 , x 1 , ⋯   , x n − 1 , x n x_0,x_1,\cdots,x_{n-1},x_{n} x0,x1,,xn1,xn上的三次样条函数。如果在插值点上的函数值 f 0 , f 1 , f 2 , ⋯   , f n − 1 , f n f_0,f_1,f_2,\cdots,f_{n-1},f_n f0,f1,f2,,fn1,fn是已知的,且:
S ( x j ) = f ( x j ) = y j j = 0 , 1 , ⋯   , n − 1 , n (1) S\left( x_j \right)=f\left( x_j \right)=y_j \quad j=0,1,\cdots,n-1,n \tag{1} S(xj)=f(xj)=yjj=0,1,,n1,n(1)则称函数 S ( x ) S\left( x \right) S(x)为三次样条插值函数。

2.三次样条插值函数的求解条件

  由三次样条插值函数的定义可知,在每个区间上函数有四个未知量,共有n个小区间,故共需要求4n个未知量。现已知:

  • 函数在区间分割点上的二阶导数连续:
    S ( x j − 0 ) = S ( x j + 0 ) 、 S ′ ( x j − 0 ) = S ′ ( x j + 0 ) 、 S ′ ′ ( x j − 0 ) = S ′ ′ ( x j + 0 ) (2) S\left( x_j-0 \right)=S\left( x_j+0 \right)、S^{'}\left( x_j-0 \right)=S^{'}\left( x_j+0 \right)、S^{''}\left( x_j-0 \right)=S^{''}\left( x_j+0 \right) \tag{2} S(xj0)=S(xj+0)S(xj0)=S(xj+0)S′′(xj0)=S′′(xj+0)(2)
  • 插值函数在插值点上与原函数相等:
    S ( x j ) = f ( x j ) (3) S\left( x_j\right)=f\left( x_j\right) \tag{3} S(xj)=f(xj)(3)

上述总共给出了 3 ( n − 1 ) + ( n + 1 ) = 4 n − 2 3\left(n-1\right)+\left(n+1\right)=4n-2 3(n1)+(n+1)=4n2个条件,还需要两个边界条件:

  • 已知两端的一阶导数值:
    S ′ ( x 0 ) = f ′ ( x 0 ) 、 S ′ ( x n ) = f ′ ( x n ) (4) S^{'}\left( x_0\right)=f^{'}\left( x_0\right)、S^{'}\left( x_n\right)=f^{'}\left( x_n\right) \tag{4} S(x0)=f(x0)S(xn)=f(xn)(4)
  • 已知两端的二阶导数值:
    S ′ ′ ( x 0 ) = f ′ ′ ( x 0 ) 、 S ′ ′ ( x n ) = f ′ ′ ( x n ) (5) S^{''}\left( x_0\right)=f^{''}\left( x_0\right)、S^{''}\left( x_n\right)=f^{''}\left( x_n\right )\tag{5} S′′(x0)=f′′(x0)S′′(xn)=f′′(xn)(5)
  • 原函数为以 [ x 0 , x n ] \left[x_0,x_n\right] [x0,xn]为周期的周期函数:
    S ( x 0 + 0 ) = S ( x n − 0 ) 、 S ′ ( x 0 + 0 ) = S ′ ( x n − 0 ) 、 S ′ ′ ( x 0 + 0 ) = S ′ ′ ( x n − 0 ) (6) S\left( x_0+0 \right)=S\left( x_n-0 \right)、S^{'}\left( x_0+0 \right)=S^{'}\left( x_n-0 \right)、S^{''}\left( x_0+0 \right)=S^{''}\left( x_n-0 \right) \tag{6} S(x0+0)=S(xn0)S(x0+0)=S(xn0)S′′(x0+0)=S′′(xn0)(6)如此确定的样条函数被称为周期样条函数。

3.三次样条插值函数的建立

  满足上述条件的插值函数可以有多种形式,这里介绍只介绍一种由二阶导数进行推导得出的插值函数。首先由于插值函数 S ( x ) S\left( x \right) S(x)在区间 [ x j , x j + 1 ] \left[ x_j,x_{j+1} \right] [xj,xj+1]中是三次多项式 ,可知二阶导数 S ′ ′ ( x ) S^{''}\left( x \right) S′′(x)在区间 [ x j , x j + 1 ] \left[ x_j,x_{j+1} \right] [xj,xj+1]中是一次函数,故可设:
S ′ ′ ( x ) = M j x j + 1 − x h j + M j + 1 x − x j h j (7) S^{''}\left( x \right)=M_j\frac{x_{j+1}-x}{h_j}+M_{j+1}\frac{x-x_j}{h_j} \tag{7} S′′(x)=Mjhjxj+1x+Mj+1hjxxj(7)对上述公式进行积分:
S ( x ) = M j ( x j + 1 − x ) 3 6 h j + M j + 1 ( x − x j ) 3 6 h j + C 1 x + C 2 (8) S\left( x \right)=M_j\frac{\left(x_{j+1}-x\right)^3}{6h_j}+M_{j+1}\frac{\left(x-x_{j}\right)^3}{6h_j}+C_1x+C_2 \tag{8} S(x)=Mj6hj(xj+1x)3+Mj+16hj(xxj)3+C1x+C2(8)其中 C 1 、 C 2 C_1、C_2 C1C2分别是两个待定的常数。根据 S ( x j ) = y j S\left( x_j \right)=y_j S(xj)=yj S ( x j + 1 ) = y j + 1 S\left( x_{j+1} \right)=y_{j+1} S(xj+1)=yj+1可求得:
S ( x ) = M j ( x j + 1 − x ) 3 6 h j + M j + 1 ( x − x j ) 3 6 h j + ( y j − M j h j 2 6 ) x j + 1 − x h j + ( y j + 1 − M j + 1 h j 2 6 ) x − x j h j (9) \begin{align} S\left( x \right)=&M_j\frac{\left(x_{j+1}-x\right)^3}{6h_j}+M_{j+1}\frac{\left(x-x_{j}\right)^3}{6h_j} \\ &+\left( y_j-\frac{M_jh^2_j}{6} \right)\frac{x_{j+1}-x}{h_j}+\left( y_{j+1}-\frac{M_{j+1}h^2_j}{6} \right)\frac{x-x_{j}}{h_j} \end{align} \tag{9} S(x)=Mj6hj(xj+1x)3+Mj+16hj(xxj)3+(yj6Mjhj2)hjxj+1x+(yj+16Mj+1hj2)hjxxj(9)其中 M j ( j = 0 , 1 , ⋯   , n − 1 , n ) M_j\left( j=0,1,\cdots,n-1,n \right) Mj(j=0,1,,n1,n)是未知的。对 S ( x ) S\left( x \right) S(x)求导可得:
S ′ ( x ) = − M j ( x j + 1 − x ) 2 2 h j + M j + 1 ( x − x j ) 2 2 h j + y j + 1 − y j h j − M j + 1 − M j 6 h j (10) S^{'}\left( x \right)=-M_j\frac{\left( x_{j+1}-x \right)^2}{2h_j}+M_{j+1}\frac{\left( x-x_j \right)^2}{2h_j}+\frac{y_{j+1}-y_j}{h_j}-\frac{M_{j+1}-M_j}{6}h_j \tag{10} S(x)=Mj2hj(xj+1x)2+Mj+12hj(xxj)2+hjyj+1yj6Mj+1Mjhj(10) S ′ ( x j − 0 ) = S ′ ( x j + 0 ) S^{'}\left( x_j-0 \right)=S^{'}\left( x_j+0 \right) S(xj0)=S(xj+0)可得:
μ j M j − 1 + 2 M j + λ j M j + 1 = d j , j = 1 , 2 , ⋯   , n − 2 , n − 1 (11) \mu_jM_{j-1}+2M_j+\lambda_jM_{j+1}=d_j,\quad j=1,2,\cdots,n-2,n-1 \tag{11} μjMj1+2Mj+λjMj+1=dj,j=1,2,,n2,n1(11)其中
μ j = h j − 1 h j − 1 + h j λ j = h j h j − 1 + h j d j = 6 f [ x j , x j + 1 ] − f [ x j − 1 , x j ] h j − 1 + h j = 6 f [ x j − 1 , x j , x j + 1 ] j = 1 , 2 , ⋯   , n − 2 , n − 1 (12) \begin{align} \mu_j &=\frac{h_{j-1}}{h_{j-1}+h_{j}} \\ \lambda_j &=\frac{h_{j}}{h_{j-1}+h_{j}} \\ d_j &=6\frac{f\left[ x_j,x_{j+1} \right]-f\left[ x_{j-1},x_{j} \right]}{h_{j-1}+h_{j}}=6f\left[ x_{j-1},x_j,x_{j+1} \right] \\ j &=1,2,\cdots,n-2,n-1 \end{align} \tag{12} μjλjdjj=hj1+hjhj1=hj1+hjhj=6hj1+hjf[xj,xj+1]f[xj1,xj]=6f[xj1,xj,xj+1]=1,2,,n2,n1(12)针对边界条件公式(4)可得:
[ 2 λ 0 μ 1 2 λ 1 ⋯ ⋯ ⋯ μ n − 1 2 λ n − 1 μ n 2 ] [ M 0 M 1  ⁣ : M n − 1 M n ] = [ d 0 d 1  ⁣ : d n − 1 d n ] (13) \begin{bmatrix} 2 & \lambda_0 & & & \\ \mu_1 & 2 & \lambda_1 & & \\ & \cdots & \cdots & \cdots & \\ & & \mu_{n-1} & 2 & \lambda_{n-1}\\ & & & \mu_n & 2\\ \end{bmatrix} \begin{bmatrix} M_0\\ M_1\\ \colon\\ M_{n-1}\\ M_n\\ \end{bmatrix}= \begin{bmatrix} d_0\\ d_1\\ \colon\\ d_{n-1}\\ d_n\\ \end{bmatrix} \tag{13} 2μ1λ02λ1μn12μnλn12 M0M1:Mn1Mn = d0d1:dn1dn (13)其中
λ 0 = 1 d 0 = 6 h 0 ( f [ x 0 , x 1 ] − f 0 ′ ) μ n = 1 d n = 6 h n − 1 ( f n ′ − f [ x n − 1 , x n ] ) (14) \begin{align} \lambda_0 &=1 \\ d_0 &=\frac{6}{h_0}\left( f\left[ x_0,x_1 \right]-f^{'}_0 \right) \\ \mu_n &=1 \\ d_n &=\frac{6}{h_{n-1}}\left( f^{'}_n-f\left[ x_{n-1},x_n \right] \right) \end{align} \tag{14} λ0d0μndn=1=h06(f[x0,x1]f0)=1=hn16(fnf[xn1,xn])(14)针对边界条件公式(5)可得:
[ 2 λ 1 μ 1 μ 2 2 λ 2 ⋯ ⋯ ⋯ μ n − 1 2 λ n − 1 λ n μ n 2 ] [ M 1 M 2  ⁣ : M n − 1 M n ] = [ d 1 d 2  ⁣ : d n − 1 d n ] (15) \begin{bmatrix} 2 & \lambda_1 & & & \mu_1\\ \mu_2 & 2 & \lambda_2 & & \\ & \cdots & \cdots & \cdots & \\ & & \mu_{n-1} & 2 & \lambda_{n-1}\\ \lambda_n & & & \mu_n & 2\\ \end{bmatrix} \begin{bmatrix} M_1\\ M_2\\ \colon\\ M_{n-1}\\ M_n\\ \end{bmatrix}= \begin{bmatrix} d_1\\ d_2\\ \colon\\ d_{n-1}\\ d_n\\ \end{bmatrix} \tag{15} 2μ2λnλ12λ2μn12μnμ1λn12 M1M2:Mn1Mn = d1d2:dn1dn (15)其中
λ n = h 0 h n − 1 + h 0 μ n = h n − 1 h n − 1 + h 0 d n = 6 f [ x 0 , x 1 ] − f [ x n − 1 , x n ] h 0 + h n − 1 (16) \begin{align} \lambda_n &=\frac{h_{0}}{h_{n-1}+h_{0}} \\ \mu_n &=\frac{h_{n-1}}{h_{n-1}+h_{0}} \\ d_n &=6\frac{f\left[ x_0,x_1 \right]-f\left[ x_{n-1},x_n \right]}{h_{0}+h_{n-1}} \end{align} \tag{16} λnμndn=hn1+h0h0=hn1+h0hn1=6h0+hn1f[x0,x1]f[xn1,xn](16)求解上述矩阵方程公式(13)或公式(15)即可得到插值函数公式(9)。

二、MATLAB实现

1.一阶导数边界条件

  基于一阶导数已知的边界条件:

% 三次样条插值
function [yOutArr]=func_CubicSplineInterpolation1(xInArr,yInArr,dyInArr,xQuery)
    % ************************************************************
    % 识别误差
    % ************************************************************
    xInLength=length(xInArr);
    yInLength=length(yInArr);
    dyInLength=length(dyInArr);
    xQueryLength=length(xQuery);
    % 插值数组不匹配
    if xInLength~=yInLength
        error('Error:The xInArr=%d and the yInArr=%d are not equal in length.',xInLength,yInLength);
    end
    % 插值数组不匹配
    if xInLength~=dyInLength
        error('Error:The xInArr=%d and the dyInArr=%d are not equal in length.',xInLength,dyInLength);
    end
    % 插值数组不为递增数组
    for i=1:1:xInLength-1
        if xInArr(i)>xInArr(i+1)
            error('Error:The xInArr should be a incremental array.');
        end
    end
    % 查询数组不为递增数组
    for i=1:1:xQueryLength-1
        if xQuery(i)>xQuery(i+1)
            error('Error:The xQuerry should be a incremental array.');
        end
    end
    % 查询数组中的点超出插值数组的范围——查询数组有为一个点
    if xQueryLength==1
        % 查询数组中的点超出插值数组的范围
        if xQuery(xQueryLength)>xInArr(xInLength)||xQuery(xQueryLength)<xInArr(1)
            error('Error:The num of the query array xQuery should gainer than %d and lesser than %d.',xInArr(1),xInArr(xInLength));
        end
    % 查询数组中的点超出插值数组的范围——查询数组有多个点
    else
        % 查询数组中的点超出插值数组的范围
        if xQuery(xQueryLength)>xInArr(xInLength)||xQuery(1)<xInArr(1)
            error('Error:The num of the xQuery should gainer than %d and lesser than %d.',xInArr(1),xInArr(xInLength));
        end
    end
    % ************************************************************
    % 插值数组只有单个值时不存在区间
    % ************************************************************
    if xInLength==1
        yOutArr=yInArr;
        return;
    end
    % ************************************************************
    % 插值数组只有两个点时直接使用三次Hermit插值
    % ************************************************************
    if xInLength==2
        yOutArr=func_PiecewiseCubeHermitInterpolation(xInArr,yInArr,dyInArr,xQuery);
        return;
    end
    % ************************************************************
    % 插值数组至少有三个点时
    % ************************************************************
    prev=0;pros=0;
    % 识别xQuerry查询数组在插值数组中的范围
    for i=1:1:xInLength-1
        % 查询数组为一个点
        if xQueryLength==1
            if (xQuery(xQueryLength)>xInArr(i)&&xQuery(xQueryLength)<xInArr(i+1))||...
                    (xQuery(xQueryLength)==xInArr(i))
                prev=i;pros=i+1;
                break;
            end
        % 查询数组有多个点
        else
            if(prev~=0&&pros~=0)
                break;
            end
            if(prev==0)
                if (xQuery(1)>xInArr(i)&&xQuery(1)<xInArr(i+1))||(xQuery(1)==xInArr(i))
                    prev=i;
                end
            end
            if(pros==0)
                if (xQuery(xQueryLength)>xInArr(xInLength-i)&&xQuery(xQueryLength)<xInArr(xInLength+1-i))||(xQuery(xQueryLength)==xInArr(xInLength+1-i))
                    pros=xInLength+1-i;
                end
            end
        end
    end
    % ************************************************************
    % 查询数组为一个点直接使用三次Hermit插值
    % ************************************************************
    if pros-prev==1
        yOutArr=func_PiecewiseCubeHermitInterpolation(xInArr,yInArr,dyInArr,xQuery);
        return;
    end
    % ************************************************************
    % 查询数组有多个点使用三次样条插值
    % ************************************************************
    miu=zeros(1,pros-prev+1);
    lambda=zeros(1,pros-prev+1);
    M=zeros(pros-prev+1,1);
    D=zeros(pros-prev+1,1);
    h=zeros(1,pros-prev);
    K=zeros(pros-prev+1,pros-prev+1);
    % 计算λ、μ、d、h
    for i=1:1:pros-prev+1
        if i<=pros-prev
            h(i)=xInArr(prev+i)-xInArr(prev-1+i);
        end
        if i==1
            miu(i)=0;
            lambda(i)=1;
            D(i)=(6/h(i))*(func_DifferenceQuotient1(xInArr(prev-1+i:1:prev+i),yInArr(prev-1+i:1:prev+i),2)-dyInArr(prev-1+i));
            K(i,i)=2;K(i,i+1)=lambda(i);
        elseif i>1&&i<pros-prev+1
            miu(i)=h(prev+i-2)/(h(prev+i-2)+h(prev-1+i));
            lambda(i)=h(prev-1+i)/(h(prev+i-2)+h(prev-1+i));
            D(i)=6*func_DifferenceQuotient1(xInArr(prev+i-2:1:prev+i),yInArr(prev+i-2:1:prev+i),3);
            K(i,i-1)=miu(i);K(i,i)=2;K(i,i+1)=lambda(i);
        elseif i==pros-prev+1
            miu(i)=1;
            lambda(i)=0;
            D(i)=(6/h(i-1))*(dyInArr(prev-1+i)-func_DifferenceQuotient1(xInArr(prev+i-2:1:prev-1+i),yInArr(prev+i-2:1:prev-1+i),2));
            K(i,i-1)=miu(i);K(i,i)=2;
        end
    end
    % 计算M
    M=K^(-1)*D;
    % 计算yOutArr
    syms x;
    yOutArr=zeros(1,xQueryLength);
    for i=1:1:xQueryLength
        if i==1
            S=M(1)*(xInArr(prev+1)-x)^3/(6*h(1))+...
                M(2)*(x-xInArr(prev))^3/(6*h(1))+...
                (yInArr(prev)-(M(1)*h(1)^2)/6)*(xInArr(prev+1)-x)/h(1)+...
                (yInArr(prev+1)-(M(2)*h(1)^2)/6)*(x-xInArr(prev))/h(1);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        elseif i>1&&i<xQueryLength
            for j=prev:1:pros-1
                if (xQuery(i)>xInArr(j)&&xQuery(i)<=xInArr(j+1))||xQuery(i)==xInArr(j)
                    pos=j;
                    break;
                end
            end
            S=M(pos-prev+1)*(xInArr(pos+1)-x)^3/(6*h(pos-prev+1))+...
                M(pos-prev+2)*(x-xInArr(pos))^3/(6*h(pos-prev+1))+...
                (yInArr(pos)-(M(pos-prev+1)*h(pos-prev+1)^2)/6)*(xInArr(pos+1)-x)/h(pos-prev+1)+...
                (yInArr(pos+1)-(M(pos-prev+2)*h(pos-prev+1)^2)/6)*(x-xInArr(pos))/h(pos-prev+1);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        elseif i==xQueryLength
            S=M(pros-prev)*(xInArr(pros)-x)^3/(6*h(pros-prev))+...
                M(pros-prev+1)*(x-xInArr(pros-1))^3/(6*h(pros-prev))+...
                (yInArr(pros-1)-(M(pros-prev+1)*h(pros-prev)^2)/6)*(xInArr(pros)-x)/h(pros-prev)+...
                (yInArr(pros)-(M(pros-prev+1)*h(pros-prev)^2)/6)*(x-xInArr(pros-1))/h(pros-prev);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        end
    end
end

2.二阶导数边界条件

  基于二阶导数已知的边界条件:

% 三次样条插值
function [yOutArr]=func_CubicSplineInterpolation2(xInArr,yInArr,ddy1,ddy2,xQuery)
    % ************************************************************
    % 识别误差
    % ************************************************************
    xInLength=length(xInArr);
    yInLength=length(yInArr);
    xQueryLength=length(xQuery);
    % 插值数组不匹配
    if xInLength~=yInLength
        error('Error:The xInArr=%d and the yInArr=%d are not equal in length.',xInLength,yInLength);
    end
    % 插值数组不为递增数组
    for i=1:1:xInLength-1
        if xInArr(i)>xInArr(i+1)
            error('Error:The xInArr should be a incremental array.');
        end
    end
    % 查询数组不为递增数组
    for i=1:1:xQueryLength-1
        if xQuery(i)>xQuery(i+1)
            error('Error:The xQuerry should be a incremental array.');
        end
    end
    % 查询数组中的点超出插值数组的范围——查询数组有为一个点
    if xQueryLength==1
        % 查询数组中的点超出插值数组的范围
        if xQuery(xQueryLength)>xInArr(xInLength)||xQuery(xQueryLength)<xInArr(1)
            error('Error:The num of the query array xQuery should gainer than %d and lesser than %d.',xInArr(1),xInArr(xInLength));
        end
    % 查询数组中的点超出插值数组的范围——查询数组有多个点
    else
        % 查询数组中的点超出插值数组的范围
        if xQuery(xQueryLength)>xInArr(xInLength)||xQuery(1)<xInArr(1)
            error('Error:The num of the xQuery should gainer than %d and lesser than %d.',xInArr(1),xInArr(xInLength));
        end
    end
    % ************************************************************
    % 插值数组只有单个值时不存在区间
    % ************************************************************
    if xInLength==1
        yOutArr=yInArr;
        return;
    end
    % ************************************************************
    % 插值数组只有两个点时直接使用三次Hermit插值
    % ************************************************************
    if xInLength==2
        yOutArr=func_PiecewiseCubeHermitInterpolation(xInArr,yInArr,dyInArr,xQuery);
        return;
    end
    % ************************************************************
    % 插值数组至少有三个点时
    % ************************************************************
    prev=0;pros=0;
    % 识别xQuerry查询数组在插值数组中的范围
    for i=1:1:xInLength-1
        % 查询数组为一个点
        if xQueryLength==1
            if (xQuery(xQueryLength)>xInArr(i)&&xQuery(xQueryLength)<xInArr(i+1))||...
                    (xQuery(xQueryLength)==xInArr(i))
                prev=i;pros=i+1;
                break;
            end
        % 查询数组有多个点
        else
            if(prev~=0&&pros~=0)
                break;
            end
            if(prev==0)
                if (xQuery(1)>xInArr(i)&&xQuery(1)<xInArr(i+1))||(xQuery(1)==xInArr(i))
                    prev=i;
                end
            end
            if(pros==0)
                if (xQuery(xQueryLength)>xInArr(xInLength-i)&&xQuery(xQueryLength)<xInArr(xInLength+1-i))||(xQuery(xQueryLength)==xInArr(xInLength+1-i))
                    pros=xInLength+1-i;
                end
            end
        end
    end
    % ************************************************************
    % 查询数组在插值数组的一个区间中时直接使用三次Hermit插值
    % ************************************************************
    if pros-prev==1
        yOutArr=func_PiecewiseCubeHermitInterpolation(xInArr,yInArr,dyInArr,xQuery);
        return;
    end
    % ************************************************************
    %  查询数组在插值数组的多个区间中时使用三次样条插值
    % ************************************************************
    miu=zeros(1,pros-prev);
    lambda=zeros(1,pros-prev);
    M=zeros(pros-prev+1,1);
    D=zeros(pros-prev,1);
    h=zeros(1,pros-prev);
    K=zeros(pros-prev,pros-prev);
    % 计算λ、μ、d、h
    for i=1:1:pros-prev
        h(i)=xInArr(prev+i)-xInArr(prev-1+i);
        lambda(i)=h(1)/(h(i)+h(1));
        miu(i)=1-lambda(i);
        d(i)=6*(func_DifferenceQuotient1(xInArr(prev:1:prev+1),yInArr(prev:1:prev+1),2)-...
            func_DifferenceQuotient1(xInArr(prev-1+i:1:prev+i),yInArr(prev-1+i:1:prev+i),2))/...
            (h(i)+h(1));
        K(i,i)=2;
        K(i,max(1,mod(i+1,pros-prev+1)))=lambda(i);
        K(i,max(1,mod(pros-prev-1+i,pros-prev+1)))=miu(i);
    end
    % 计算M
    M(2:1:pros-prev+1)=K^(-1)*D;
    M(1)=ddy1;
    M(pros-prev+1)=ddy2;
    % 计算yOutArr
    syms x;
    yOutArr=zeros(1,xQueryLength);
    for i=1:1:xQueryLength
        if i==1
            S=M(1)*(xInArr(prev+1)-x)^3/(6*h(1))+...
                M(2)*(x-xInArr(prev))^3/(6*h(1))+...
                (yInArr(prev)-(M(1)*h(1)^2)/6)*(xInArr(prev+1)-x)/h(1)+...
                (yInArr(prev+1)-(M(2)*h(1)^2)/6)*(x-xInArr(prev))/h(1);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        elseif i>1&&i<xQueryLength
            for j=prev:1:pros-1
                if (xQuery(i)>xInArr(j)&&xQuery(i)<=xInArr(j+1))||xQuery(i)==xInArr(j)
                    pos=j;
                    break;
                end
            end
            S=M(pos-prev+1)*(xInArr(pos+1)-x)^3/(6*h(pos-prev+1))+...
                M(pos-prev+2)*(x-xInArr(pos))^3/(6*h(pos-prev+1))+...
                (yInArr(pos)-(M(pos-prev+1)*h(pos-prev+1)^2)/6)*(xInArr(pos+1)-x)/h(pos-prev+1)+...
                (yInArr(pos+1)-(M(pos-prev+2)*h(pos-prev+1)^2)/6)*(x-xInArr(pos))/h(pos-prev+1);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        elseif i==xQueryLength
            S=M(pros-prev)*(xInArr(pros)-x)^3/(6*h(pros-prev))+...
                M(pros-prev+1)*(x-xInArr(pros-1))^3/(6*h(pros-prev))+...
                (yInArr(pros-1)-(M(pros-prev+1)*h(pros-prev)^2)/6)*(xInArr(pros)-x)/h(pros-prev)+...
                (yInArr(pros)-(M(pros-prev+1)*h(pros-prev)^2)/6)*(x-xInArr(pros-1))/h(pros-prev);
            yOutArr(i)=polyval(sym2poly(S),xQuery(i));
        end
    end
end

3.测试程序

  测试程序如下:

% 测试三次样条插值函数——func_CubicSplineInterpolation1、func_CubicSplineInterpolation2
clc;
clear;
close all;

x=-5.0:0.2:5.0;
y=zeros(1,length(x));
dy=zeros(1,length(x));
ddy=zeros(1,length(x));
for i=1:1:length(x)
    y(i)=1/(1+x(i)^2);
    dy(i)=-(2*x(i))/(x(i)^2 + 1)^2;
    ddy(i)=(8*x(i)^2)/(x(i)^2 + 1)^3 - 2/(x(i)^2 + 1)^2;
end
xq=-5.0:0.05:5.0;

yq1=func_CubicSplineInterpolation1(x,y,dy,xq);
yq2=func_CubicSplineInterpolation2(x,y,ddy(1),ddy(length(x)),xq);
figure(1)
plot(x,y,'k*',xq,yq1,'r-');
xlabel('x');ylabel('y');
legend('原函数','插值函数')
figure(2)
plot(x,y,'k*',xq,yq2,'b-');
xlabel('x');ylabel('y');
legend('原函数','插值函数')

得到结果:
Alt

图2.1 一阶导数边界条件下的三次样条插值结果

Alt

图2.2 二阶导数边界条件下的三次样条插值结果

可以看到的是一阶导数已知的条件下插值函数曲线较为光滑,而二阶导数边界条件下的插值函数曲线稍有曲折,但不能确定是否是普遍现象。


总结

  以上在本文中对三次样条插值插值两种形式的推导进行了简单的介绍,并提供了MATLAB的实现代码与测试用例。

参考文献

[1]李庆扬,王能超,易大义. 数值分析.第5版[M]. 清华大学出版社, 2008.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1984232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简单反射型XSS的复现

xss反射型攻击&#xff1a; 1.最简单的漏洞复现&#xff1a; 这里我们有一个最简单的网页&#xff1a;由于地址不存在&#xff0c;所以图片加载不出来。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta…

FP8量化

https://arxiv.org/html/2402.16363v5 LLama3.1用了FP8量化&#xff1a; FP8也可以用scaling factor来扩大表示范围&#xff0c;对吧&#xff1f;

开源在线剪切板 PrivateBin 安装和使用教程

我们经常需要在网上快速分享一些文本内容&#xff0c;比如代码片段、临时笔记或者敏感信息。传统的在线剪贴板服务虽然使用方便&#xff0c;但往往缺乏足够的隐私保护。 那么&#xff0c;有没有一种既方便又安全的在线文本分享方式呢&#xff1f;今天我要向大家推荐一个优秀的…

常见的图像融合方法

这里我们将介绍一些常用的图像融合方式&#xff0c;并不涉及到诸如CutMix、MixUp、TokenMix、Mosaic、Copy-Paste等图像增强方法。 首先是读取图像&#xff0c;我们这边采用了PIL库进行&#xff0c;那么读进来就应该是一个Image对象。下面介绍Image对象与array的转换方式。 f…

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测

土地利用/土地覆盖数据是生态、环境和气象等领域众多模型的重要输入参数之一。基于遥感影像解译&#xff0c;可获取历史或当前任何一个区域的土地利用/土地覆盖数据&#xff0c;用于评估区域的生态环境变化、评价重大生态工程建设成效等。借助CLUE模型&#xff0c;实现对未来土…

AI9-文本识别

本章主要介绍文本识别算法的理论知识,包括背景介绍、算法分类和部分经典论文思路。 通过本章的学习,你可以掌握: 1. 文本识别的目标 2. 文本识别算法的分类 3. 各类算法的典型思想 1 背景介绍 文本识别是OCR(Optical Character Recognition)的一个子任务,其任务为识别一个…

pytorch的入门使用

pytorch安装略&#xff01; 一.张量Tensor 张量是一个统称其中包含0阶&#xff0c;1阶&#xff0c;2阶&#xff0c;3阶&#xff0c;4阶&#xff0c;.......n阶。 0阶&#xff1a;标量&#xff0c;常数&#xff0c;0-D Tensor 1阶&#xff1a;向量&#xff0c;1-D Tensor 2…

使用java反编译工具jad

文章目录 反编译工具 JAD下载配置环境变量使用其他反编译工具 JD-GUI 反编译工具 JAD 反编译是指将编译后的字节码文件&#xff08;.class 文件&#xff09;转换回可读的 Java 源代码。JAD (Java Decompiler) 是一个经典的反编译工具&#xff0c;广泛用于将 Java 字节码反编译…

国内AI大模型168个,哪个最有前途?

168个国产大模型&#xff0c;都是什么来头&#xff1f; 1785年&#xff0c;瓦特改进了蒸汽机&#xff0c;人类从此摆脱了手工业的桎梏&#xff0c;迈向辉煌的蒸汽时代。 1870年&#xff0c;第二次工业革命光芒四溢&#xff0c;人类踏上了电气时代的漫长征程。 20世纪70年代后…

手机有两个卡槽分别放什么卡,这篇文章建议收藏!

你发现了吗&#xff0c;我们现在对于手机卡的需求是越来越大了&#xff0c;相信大多数用户手上都不止一张SIM卡&#xff0c;大部分都是双卡&#xff0c;甚至三卡了&#xff0c;那么&#xff0c;这些卡槽你真的利用对了吗&#xff1f; 这篇文章就告诉大家&#xff0c;如何更好的…

【Windows】Beyond Compare 5(文件数据对比神器) 软件介绍

今天给大家介绍的软件叫Beyond Compare&#xff0c;这是一个文件数据对比神器&#xff0c;可以让你从茫茫数据、文字中解放出来。 Beyond Compare 是一款功能强大的文件和文件夹比较工具&#xff0c;主要用于比较和同步文件、文件夹及其内容。以下是该软件的主要特点和功能&…

一款免费开源的在线白板,手绘风格在线画图神器

Excalidraw 是一款开源的虚拟手绘风格在线白板工具&#xff0c;它专注于提供简单、直观且功能丰富的绘图体验。这款工具特别适合用于创建图表、线框图、思维导图、流程图以及其他各种类型的图形和视觉内容。 Excalidraw 的主要特点包括&#xff1a; 免费开源&#xff1a;Exca…

如何正确地实现虚拟类?

在 Python 中&#xff0c;所谓的虚拟类通常是指抽象基类&#xff08;Abstract Base Class&#xff0c;简称 ABC&#xff09;。抽象基类不可实例化&#xff0c;其主要作用是定义一组抽象方法&#xff0c;子类必须实现这些抽象方法才能被实例化。 要正确实现虚拟类&#xff08;抽…

新时代来临,跟60后、70后的奢侈消费观念说拜拜吧!

在长达几十年的改革开放壮丽征程中&#xff0c;60后与70后的消费观念深刻塑造了家庭经济的面貌&#xff0c;他们倾尽所有为子女铺设未来之路&#xff0c;从婚房婚车到教育投资&#xff0c;无一不体现了深沉的父爱母爱。然而&#xff0c;随着时代的变迁&#xff0c;尤其是当中国…

连接数据库报错bad handshake

堡垒机账号没有授权访问权限

【xml文档的读取与导入】

首先基于unity引擎&#xff0c;关于xml文档的导入只需要Excel与笔记本两种 打开记事本编写xml代码如下 <?xml version"1.0" encoding"UTF-8"?> <root> <item ID""> <surname></surname> &…

2024开学季必备物品有哪些?新学期学生必备必备物品清单

临近开学&#xff0c;萌新们是否已经开始准备学习物品了呢&#xff1f;正在准备的你&#xff0c;头脑里一定有满满的问号感到头大&#xff0c;不用担心&#xff01;学长学姐们为你准备了详细的开学物品清单&#xff0c;到处搜攻略不如直接看此篇清单&#xff01;快来一起看看吧…

Eclipse 2024 下载 安装 汉化

1&#xff0c;解压 Eclipse 2024 压缩包到当前目录下&#xff1a; 点击此处蓝色字体下载压缩包 提取码 j5nl 2&#xff0c;鼠标右键 点击 jdk-19_windows-x64_bin.exe 选择 以管理员身份运行 &#xff1a; 3&#xff0c;点击 下一步&#xff1a; 4&#xff0c;点击 更改 选择位…

fscan安装

windows安装 1.go语言下载。 下载msi版本&#xff0c;直接安装就可以不用配置环境变量&#xff0c;默认是帮你安装配合好的 All releases - The Go Programming Language 2.配置go环境 使用默认配置的话&#xff0c;下载速度过慢&#xff0c;导致无法完成编译。故需要配置代理…

sql注入——sqlilabs1-15

目录 sql注入靶场练习--sqlilabs 1.less-1​编辑 1.测试发现单引号为逃逸符号 2.确定查询列数为三列 3.查询到数据库名 4.查询数据库中的表名 5.查询用户表的列名字 6.查询用户信息 2.less-2​编辑 2.确定查询列数为三列 3.查询到数据库名 4.查询数据库中的表名 5.…