学习笔记-Matlab算法篇-插值算法

插值算法

01拉格朗日多项式插值

 

进而得到拉格朗日多项式:

Matlab求解:matlab中没有自带的求解函数,需要自行实现。

function f = Language(x,y,x0)
    syms t;
    if(length(x) == length(y))
        n = length(x);    
    else
        disp('x和y的维数不相等!');
        return;
    end                                      %检错
    f = 0.0;
    for i = 1:n
        l = y(i); 
        for j = 1:i-1
            l = l*(t-x(j))/(x(i)-x(j));      
        end
        for j = i+1:n
            l = l*(t-x(j))/(x(i)-x(j));      %计算拉格朗日基函数
        end
        f = f + l;                           %计算拉格朗日插值函数      
        simplify(f);                         %化简
        if(i==n)
            if(nargin == 3)
                f = subs(f,'t',x0);          %计算插值点的函数值
            else
                f = collect(f);          %将插值多项式展开
                f = vpa(f,6);                %将插值多项式的系数化成6位精度的小数
            end
        end
    end
end

例子(e01):使用拉格朗日多项式插值计算数据

x=-5:0.2:5;
y=-3*x.^2+2*x+x.^3-2;
figure,plot(x,y,'-.b+','linewidth',2);hold on;

x0=2.3;
y0=3*x0+2*x0.^2-x0.^3+2;
tic
yl=Language(x,y,2.3);
toc
fprintf('理论值:%.4f,实际值%.4f\n',y0,yl);
plot(x0,y0,'r*','markersize',12);hold off;

结果:

>> e01
时间已过 35.958879 秒。
理论值:7.3130,实际值-1.1030

02牛顿法插值

进而可得到:

function f = Newton(x,y,x0)
syms t;

if(length(x) == length(y))
    n = length(x);
    c(1:n) = 0.0;
else
    disp('x和y的维数不相等!');
    return;
end

f = y(1);
y1 = 0;
l  = 1;
 
for(i=1:n-1)   
    for(j=i+1:n)
        y1(j) = (y(j)-y(i))/(x(j)-x(i));
    end
    c(i) = y1(i+1);     
    l = l*(t-x(i));  
    f = f + c(i)*l;
    simplify(f);
    y = y1;
    
    if(i==n-1)
        if(nargin == 3)
            f = subs(f,'t',x0);
        else
            f = collect(f);                %将插值多项式展开
            f = vpa(f, 6);
        end
    end
end



x=-5:0.2:5;
y=3*x+2*x.^2-x.^3+2;
figure,plot(x,y,'-.b+','linewidth',2);hold on;

x0=2.3;
y0=3*x0+2*x0.^2-x0.^3+2;
tic
yl=Newton(x,y,2.3);
toc
fprintf('理论值:%.4f,实际值%.4f\n',y0,yl);
plot(x0,y0,'r*','markersize',12);hold off;

结果:

>> e02
时间已过 16.260375 秒。
理论值:7.3130,实际值7.3130

03分段线性插值

Matlab实现:使用函数y=interp1(x,y,x0,’method’)

method 指定插值的方法,默认为线性插值。其值可为:

'nearest' 最近项插值

'linear' 线性插值

'spline' 逐段 3 次样条插值

'cubic' 保凹凸性 3 次插值。

所有的差值方法都要求x0是单调的。

例子(e03):使用分段线性插值计算数据

x=-5:0.2:5;
y=3*x+2*x.^2-3*x.^3+2*x.^4+2;
figure,plot(x,y,'-.b+','linewidth',2);hold on;

x0=2.3;
y0=3*x0+2*x0.^2-x0.^3+2;
tic
yl=interp1(x,y,2.3);
toc
fprintf('理论值:%.4f,实际值%.4f\n',y0,yl);
plot(x0,y0,'r*','markersize',12);hold off;

结果:

>> e03
时间已过 0.025925 秒。
理论值:7.3130,实际值39.3952

 

04埃米尔插值

定义:如果对插值函数,不仅要求它在节点处与函数同值,而且要求它与函数有相同的一阶、二阶甚至更高阶的导数值,这就是 Hermite 插值问题。即:

艾米尔特插值多项式为:

Matlab没有现成的Hermite函数,需要手动编写:Hermite

例子(e04):使用艾米尔特插值计算数据

function f = Hermite(x,y,y_1,x0)
syms t;
f = 0.0;

if(length(x) == length(y))
    if(length(y) == length(y_1))
        n = length(x);
    else
        disp('y和y的导数的维数不相等!');
        return;
    end
else
    disp('x和y的维数不相等!');
    return;
end

for i=1:n
    h = 1.0;
    a = 0.0;
    for j=1:n
        if( j ~= i)
            h = h*(t-x(j))^2/((x(i)-x(j))^2);
            a = a + 1/(x(i)-x(j));
        end
    end
    
    f = f + h*((x(i)-t)*(2*a*y(i)-y_1(i))+y(i));
    
    if(i==n)
        if(nargin == 4)
            f = subs(f,'t',x0);
        else
            f = vpa(f,6);
        end
    end
end
x=-5:0.2:5;
y=3*x+5*x.^2-4*x.^3+2*x.^5+2;
figure,plot(x,y,'-.b+','linewidth',2);hold on;

x0=2.3;
y0=3*x0+2*x0.^2-x0.^3+2;
y01=3+4*x0-9*x0.^2-8*x0.^3;
tic
y1=Hermite(x,y,y01,x0);
toc
fprintf('理论值:%.4f,实际值%.4f\n',y0,yl);
plot(x0,y0,'r*','markersize',12);hold off;

结果: 

>> e04
y和y的导数的维数不相等!
时间已过 0.071891 秒。
理论值:7.3130,实际值39.3952

05样条插值 

定义:数学上将具有一定光滑性的分段多项式称为样条函数。

2次样条函数定义:

3次样条函数定义:

Matlab中的3次样条函数:

y=interp1(x0,y0,x,'spline')

y=spline(x0,y0,x)

pp=csape(x0,y0,conds)y=ppval(pp,x)

推荐使用csape函数。

pp=csape(x0,y0):使用默认的边界条件,即 Lagrange 边界条件。pp=csape(x0,y0,conds)中的 conds 指定插值的边界条件,其值可为:

'complete' 边界为一阶导数,即默认的边界条件

'not-a-knot' 非扭结条件

'periodic' 周期条件

'second' 边界为二阶导数,二阶导数的值[0, 0]

'variational' 设置边界的二阶导数值为[0,0]

例子(e05):待加工零件的外形根据工艺要求由一组数据(x,y)给出(在平面情况下),用程控铣床加工时每一刀只能沿 x 方向和 y 方向走非常小的一步,这就需要从已知数据得到加工所要求的步长很小的(x,y)坐标。表中给出的x,y数据位于机翼断面的下轮廓线上,假设需要得到 x 坐标每改变0.1时的y坐标。试完成加工所需数据,画出曲线,并求出x=0处的曲线斜率和13≤x≤15范围内y的最小值。要求用 Lagrange、分段线性和三次样条三种插值方法计算。

0

3

5

7

9

11

12

13

14

15

0

1.2

1.7

2.0

2.1

2.0

1.8

1.2

1.0

1.6

x0=[0 3 5 7 9 11 12 13 14 15];
y0=[0 1.2 1.7 2.0 2.1 2.0 1.8 1.2 1.0 1.6];
x=0:0.1:15;
y1=Language(x0,y0,x); %调用前面编写的Lagrange插值函数
y2=interp1(x0,y0,x);
y3=interp1(x0,y0,x,'spline');
pp1=csape(x0,y0); y4=ppval(pp1,x);
pp2=csape(x0,y0,'second'); y5=ppval(pp2,x);
fprintf('比较一下不同插值方法和边界条件的结果:\n')
fprintf('x y1 y2 y3 y4 y5\n')
xianshi=[x',y1',y2',y3',y4',y5'];
fprintf('%f\t%f\t%f\t%f\t%f\t%f\n',xianshi')
subplot(2,2,1), plot(x0,y0,'+',x,y1), title('Lagrange')
subplot(2,2,2), plot(x0,y0,'+',x,y2), title('Piecewise linear')
subplot(2,2,3), plot(x0,y0,'+',x,y3), title('Spline1')
subplot(2,2,4), plot(x0,y0,'+',x,y4), title('Spline2')
dyx0=ppval(fnder(pp1),x0(1)) %求x=0处的导数
ytemp=y3(131:151);
index=find(ytemp==min(ytemp));
xymin=[x(130+index),ytemp(index)]

%% 结果分析
%可以看出,拉格朗日插值的结果根本不能应用,分段线性插值的光滑性较差(特别
%是在 14 = x 附近弯曲处),建议选用三次样条插值的结果。

结果:

几种插值方法的比较:https://blog.csdn.net/f2157120/article/details/80371214

 

猜你喜欢

转载自blog.csdn.net/seek97/article/details/108322553