clear;clc
x0=[-2 -1.7 -1.4 -1.1 -0.8 -0.5 -0.2 0.1 0.4 0.7 1 1.3 1.6 1.9 2.2
2.5 2.8 3.1 3.4 3.7 4.0 4.3 4.6 4.9];
y0=[0.10289 0.11741 0.13158 0.14483 0.15656 0.16622 0.17332 0.1775
0.17853 0.17635 0.17109 0.16302 0.15255 0.1402 0.12655 0.11219
0.09768 0.08353 0.07015 0.05786 0.04687 0.03729 0.02914
0.02236];
f=@(a,x)1/(sqrt(2*pi)*a(1))*exp(-(x-a(2)).^2/(2*a(1)^2));
a=lsqcurvefit(f,[2,2],x0,y0)
x1=-2:0.1:5;
f1=1/(sqrt(2*pi)*a(1))*exp(-(x1-a(2)).^2/(2*a(1)^2));
plot(x0,y0,x1,f1,'*r')
非线性曲线拟合是已知输入向量xdata和输出向量ydata,并且知道输入与输出的函数关系为ydata=F(x,
xdata),但不知道系数向量x。今进行曲线拟合,求x使得输出的如下最小二乘表达式成立:
min Σ(F(x,xdatai)-ydatai)^2
函数 lsqcurvefit
格式 x = lsqcurvefit(fun,x0,xdata,ydata)
x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub)
x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub,options)
[x,resnorm] = lsqcurvefit(…)
[x,resnorm,residual] = lsqcurvefit(…)
[x,resnorm,residual,exitflag] = lsqcurvefit(…)
[x,resnorm,residual,exitflag,output] = lsqcurvefit(…)
[x,resnorm,residual,exitflag,output,lambda] = lsqcurvefit(…)
[x,resnorm,residual,exitflag,output,lambda,jacobian]
=lsqcurvefit(…)
参数说明:
x0为初始解向量;xdata,ydata为满足关系ydata=F(x, xdata)的数据;
lb、ub为解向量的下界和上界lb≤x≤ub,若没有指定界,则lb=[ ],ub=[ ];
options为指定的优化参数;
fun为待拟合函数,计算x处拟合函数值,其定义为 function F = myfun(x,xdata)
resnorm=sum ((fun(x,xdata)-ydata).^2),即在x处残差的平方和;
residual=fun(x,xdata)-ydata,即在x处的残差;
exitflag为终止迭代的条件;
output为输出的优化信息;
lambda为解x处的Lagrange乘子;
jacobian为解x处拟合函数fun的jacobian矩阵。
例 求解如下最小二乘非线性拟合问题
已知输入向量xdata和输出向量ydata,且长度都是n,待拟合函数的表达式为
ydata(i)=x(1)-xdata(i)^2+x(2)-sin(xdata(i))+x(3)-xdata^3
即目标函数为min Σ(F(x,xdata(i))-ydata(i))^2
其中:F(x,xdata) = x(1)*xdata^2 + x(2)*sin(xdata) + x(3)*xdata^3
初始解向量为x0=[0.3, 0.4, 0.1],即表达式的 个参数[x(1),x(2),x(3)]。
先建立拟合函数文件,并保存为myfun.m
function F = myfun(x,xdata)
F = x(1)*xdata.^2 + x(2)*sin(xdata) + x(3)*xdata.^3;
然后给出数据xdata和ydata
>>xdata = [3.6 7.7 9.3 4.1 8.6 2.8 1.3 7.9 10.0 5.4];
>>ydata = [16.5 150.6 263.1 24.7 208.5 9.9 2.7 163.9 325.0
54.3];
>>x0 = [10, 10, 10]; %初始估计值
>>[x,resnorm] = lsqcurvefit(@myfun,x0,xdata,ydata)
结果为:
Optimization terminated successfully:
Relative function value changing by less than OPTIONS.TolFun
x = 0.2269 0.3385 0.3021
=>即解出的系数最优估计值
resnorm = 6.2950
=>在x解值处的目标最小二乘表达式值。即所谓残差。
问题:有些时候我们需要拟合一些非线性的表达式。
比如:我们知道一个表达式的式子是y=A*sin(x).*exp(x)-B./log(x),现在我们手里面有x与y对应的一大把数据。我们如何根据x,y的值找出最佳的A、B值。则我们现在借助Matlab的函数lsqcurvefit、nlinfit,当然你也可以使用lsqnonlin.其具体用法请自己用Matlab的帮助命令进行查看。这里仅简单介绍一下常用的方式。
注意:如果对初值比较敏感,涉及到初值设置的问题;以及拟合表达式包含积分表达式或者微分项等问题;以及一些拟合降维的问题,可以参看我的另一篇博文《数据拟合遇见》
PS:如果使用Matlab以上函数拟合不出理想的结果的话,可以尝试使用我自己写的《数学计算器》里的nlinFit、nlinFit2、nlinFit4、nlinFitDE、nlinFitGA、nlinFitLM、nlinFitPSO、nlinFitPSO2、nlinFitPSO3函数
格式:lsqcurvefit(f,a,x,y)、nlinfit(x,y,f,a)
f:符号函数句柄,如果是以m文件的形式调用的时候,别忘记加@.这里需要注意,f函数的返回值是和y匹对的,即拟合参数的标准是(f-y)^2取最小值,具体看下面的例子
a:最开始预估的值(预拟合的未知参数的估计值)。如上面的问题如果我们预估A为1,B为2,则a=[1 2]
x:我们已经获知的x的值
y:我们已经获知的x对应的y的值
例子1:
问题:对于函数y=a*sin(x)*exp(x)-b/log(x)我们现在已经有多组(x,y)的数据,我们要求最佳的a,b值
%针对上面的问题,我们可以来演示下如何使用这个函数以及看下其效果
>> x=2:10;
>> y=8*sin(x).*exp(x)-12./log(x);
%上面假如是我们事先获得的值
>> a=[1 2];
>> f=@(a,x)a(1)*sin(x).*exp(x)-a(2)./log(x);
%第一种方法使用lsqcurvefit
>> lsqcurvefit(f,a,x,y)
ans =
7.999999999999987 11.999999999988997%和我们预期的值8和12结合得非常好
>>
%第二种方法使用nlinfit
>> nlinfit(x,y,f,a)
ans =
8.000000000000000 11.999999999999998
>>
%**********************************
%另一种方法,假如我们写了一个如下的m文件
function f=test(a,x)
f=a(1)*sin(x).*exp(x)-a(2)./log(x);
end
%则在上面lsqcurvefit函数调用如下,不要忘记那个@
lsqcurvefit(@test,a,x,y)
例子2:(多元的情况,注意看格式)
问题:我们已知z=a*(exp(y)+1)-sin(x)*b且有多组(x,y,z)的值,现在求最佳系数a,b
>> x=2:10;
>> y=10*sin(x)./log(x);
>> z=4.5*(exp(y)+1)-sin(x)*13.8;
>> f=@(a,x)a(1)*(exp(x(2,:))+1)-sin(x(1,:))*a(2);
%第一种方法使用lsqcurvefit
>> lsqcurvefit(f,[1 2],[x;y],z)%注意这里面的[x;y],这里的[1 2]表示我们设置f函数里的初始值a(1)=1,,a(2)=2
ans =
4.499999999999999 13.800000000000024
%第二种方法使用nlinfit
>> nlinfit([x;y],z,f,[1 2])
ans =
4.500000000000000 13.799999999999956