三次样条差值

1计算原理和程序流程图

设在区间[a, b]上给定n+1个节点xiax0<x1< …< xnb),在节点xi处的函数值为yi=f(xi) (i= 0,1,…,n)。若函数S(x)满足以下三个条件:

(1) 在每个子区间[xi-1, xi] (i= 0,1,…,n)上,S(x)是三次多项式;

(2) S(xi) = yi(i=0,1,…,n);

(3) 在区间[a, b]上,S(x)的二阶导数S”(x)连续。

则称S(x)为函数yi= f(x)在区间[a,b]上的三次样条插值函数。

由定义可知S(x)共有4n个待定参数,根据条件(3)可得如下3n-3个方程,再加上条件(2)的n+1 个方程,共有4n-2 个方程,因此还需要增加两个条件才可以确定出4n 个待定参数。所增加的条件称为边界条件或端点条件。常用的三种边界条件为:①已知 f”(a), f”(b);②已知 f”(a)= f”(b);③已知 f(x)是以 T=b-a 为周期的周期函数。

三次样条插值计算流程图如下:

 

图2求三次样条插值函数的程序框图

2.2程序使用说明

根据需要可在程序中直接修改函数f(x),插值多项式阶数和边界条件等即可。对于例题中的三弯矩方程组因为是严格对角占优的,所以选用追赶法求解。

2.3计算结果展示

例题为课本141页计算实习,分别把不同阶数的牛顿插值和三次插值多项式画图比较。结果得到的S(x)表达式如下:

y=69962787255772577/35184372088832- (54675*(x - 1)^3)/160004 - (38868241859560495*x)/17592186044416。

其中Netwon10插值误差EnMax =1.9156,三次样条插值误差EsMax =0.0220。函数图像如下:

%%
% ** 文件名:spline.m
% 
% ** 创建人:***
% 
% ** 日 期:2016.12.14
% 
% ** 描 述:三次样条差值运算 与牛顿插值的比较
% 
% **   第 141 页计算实习  求三次样条插值
% **   Runge函数f(x)=(1+25x^2)^(-1),(-1<= x <=1)
% 
% **  取等距节点,构造牛顿插值多项式N5(x)和N10(x)及三次样条差值S10(x)。
% **  分别将三种差值多项式与f(x)的曲线画在同一个坐标系进行比较。
% **参考教材:《数值分析》李乃成,梅立泉,科学出版社   
clear
clc
close all
%%
%差值多项式N5(x)
N=5;
i=0:N;
fprintf('插值节点xi');xx=-1+2/N*i;
fprintf('插值节点xi处的函数值f(xi)');fx=(1+25*xx.^2).^(-1);
yy=fx;
%----------求Newton插值多项式的各阶差商-------
%注意:数组下表为1...N+1,区别于课本中的0...N  在MATLAB中数组下标是从1开始的
for k=1:N  %求差商表
    for i=N+1:-1:k+1%之所以采用倒序,是为了不覆盖掉上一次循环所得的值
        yy(i)=(yy(i)-yy(i-1))/(xx(i)-xx(i-k));
    end
end
syms x y
%--------用秦九韶算法计算多项式的表达式
y=yy(N+1);%差商表的最后一个值
for i=N:-1:1
    y=y*(x-xx(i))+yy(i);%之所以用逆序是为了从项数最多的到项数最少的,进而得到表达式
end
fprintf('Newton插值多项式的表达式:');simplify(y);

%-------计算xk(k=1...99)对应的y(xk),N(xk),S(xk)------
K=99;
k=1:K;
xk=-1+0.02*k;
yk=1./(1+25*xk.^2);
%-------计算N(x)在对应数据点上的的函数------
Nk5=zeros(1,K);
for k=1:K
    Nk5(k)=yy(N+1);
    for i=N:-1:1
        Nk5(k)=Nk5(k)*(xk(k)-xx(i))+yy(i);%得到表达式 在k的值
    end
end

%%
%差值多项式N10(x).S10(x)
N=10;
i=0:N;
%format short;
fprintf('插值节点xi');xx=-1+2/N*i
fprintf('插值节点xi处的函数值f(xi)');fx=(1+25*xx.^2).^(-1)
yy=fx;
%----------求Newton插值多项式的各阶差商-------
%注意:数组下表为1...N+1,区别于课本中的0...N  在MATLAB中数组下标是从1开始的
for k=1:N  %求差商表
    for i=N+1:-1:k+1%之所以采用倒序,是为了不覆盖掉上一次循环所得的值
        yy(i)=(yy(i)-yy(i-1))/(xx(i)-xx(i-k));
    end
end
fprintf('Newton插值多项式的各阶差商');yy %最终所得的对角线上的N+1个值
syms x y
%--------用秦九韶算法计算多项式的表达式
y=yy(N+1);%差商表的最后一个值
for i=N:-1:1
    y=y*(x-xx(i))+yy(i);%之所以用逆序是为了从项数最多的到项数最少的,进而得到表达式
end
fprintf('Newton插值多项式的表达式:');simplify(y)
%----------(自然)三次样条插值多项式-----------M0=Mn=0
M=zeros(1,N+1);%M(i)对应s(x)在节点x(i)处的二阶导数
h=zeros(1,N);%h(i)=x(i)-x(i-1)
A=zeros(N-1,N-1);%三弯矩方程组的系数矩阵(自然三次样条插值)
b=zeros(1,N-1);a=b;c=b;d=b;
h(1)=xx(2)-xx(1);
for i=1:N-1 %i代表各数组中的第i个元素,对应的y的下标为i-1,h为i,d为i+1
    h(i+1)=xx(i+2)-xx(i+1);
    a(i)=h(i)/(h(i)+h(i+1));%三弯矩方程组的第-1条对角线元素  miou
    c(i)=1-a(i);%三弯矩方程组的第-1条对角线元素  lanmuda
    b(i)=2;%三弯矩方程组的主对角线上的元素  主对角
    d(i+1)=6/(h(i)+h(i+1))*((fx(i+2)-fx(i+1))/h(i+1)-(fx(i+1)-fx(i))/h(i));
end
d=d(2:N);
M(1)=0;M(N+1)=0;%自然三次样条插值函数的边界条件
%-----------用追赶法解严格三对角占优阵----------
z=zeros(N-1,1);w=z;%z为中间矩阵,w为方程的解
u=zeros(1,N-1);l=u;%u矩阵U的主对角线元素,l矩阵L的第-1条对角线元素
%---------追过程--------
u(1)=b(1);z(1)=d(1);
for i=2:N-1
    l(i)=a(i)/u(i-1);
    u(i)=b(i)-l(i)*c(i-1);
    z(i)=d(i)-l(i)*z(i-1);
end
%---------赶过程--------
w(N-1)=z(N-1)/u(N-1);
for i=N-2:-1:1
    w(i)=(z(i)-c(i)*w(i+1))/u(i);
end
fprintf('三弯矩方程组的解向量:');w'
M(2:N)=w;
for i=1:N
    syms x y;
    fprintf('在第%d个区间(%5.4f<=x<=%5.4f)内,S(x)的表达式为:\n',i,xx(i),xx(i...
+1));
    y=(xx(i+1)-x)^3/(6*h(i))*M(i)+(x-xx(i))^3/(6*h(i))*M(i+1)+(yy(i)-h(i)...
^2/6*M(i))*(xx(i+1)-x)/h(i)+(yy(i+1)-h(i)^2/6*M(i+1))*(x-xx(i))/h(i);
    y=simplify(y)
end
%%
%开始准备作图
%-------计算xk(k=1...99)对应的y(xk),N(xk),S(xk)------
K=99;
k=1:K;
xk=-1+0.02*k;
yk=1./(1+25*xk.^2);
%-------计算N(x)在对应数据点上的的函数------
Nk10=zeros(1,K);
for k=1:K
    Nk10(k)=yy(N+1);
    for i=N:-1:1
        Nk10(k)=Nk10(k)*(xk(k)-xx(i))+yy(i);%得到表达式 在k的值
    end
end
%-------计算S(x)在对应数据点上的的函数------
Sk10=zeros(1,K);
s=zeros(1,K);
for k=1:K
    for i=1:N-1
        if xk(k)<=xx(i+1)
            s(k)=i;
            break;      %s为xk(k)所在的插值区间号
        else
            s(k)=N;
        end
    end  
    hh=xx(s(k)+1)-xx(s(k));
    xRight=xx(s(k)+1)-xk(k);
    xLeft=xk(k)-xx(s(k));
    Sk10(k)=(M(s(k))*xRight^3/6+M(s(k)+1)*xLeft^3/6+(fx(s(k))-M(s(k))*hh^2/6)...
*xRight+(fx(s(k)+1)-M(s(k)+1)*hh^2/6)*xLeft)/hh;%得到表达式 在k的值
end
figure(1);
plot(xk,yk,'r-',xk,Nk5,'m',xk,Nk10,'g',xk,Sk10,'b');title('差值结果');
legend('原函数f(x)','Newton插值函数N5(x)','Newton插值函数N10(x)','三次样条插值函数S10(x)');
hold on
En=abs(Nk10-yk);
fprintf('Netwon10插值误差');EnMax=max(En)

Es=abs(Sk10-yk);
fprintf('三次样条插值误差');EsMax=max(Es)


你可能感兴趣的:(matlab)