在MATLAB中关于函数拟合的函数主要分为两类。一类是线性拟合,另一类则是非线性拟合。非线性拟合相对来说,难度会比线性拟合更大一些。本篇文章主要是关于如何使用lsqcurvefit函数进行非线性拟合的,从而得到函数中的多个未知量。
1、首先,我们通过MATLAB命令行窗口输入help lsqcurvefit,对lsqcurvefit函数的使用作一个大致的了解。
Nonlinear least-squares solver——基于最小二乘法的非线性拟合
以下是使用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 = lsqcurvefit(problem)
[x,resnorm] = lsqcurvefit(___)
[x,resnorm,residual,exitflag,output] = 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矩阵。
一般来说,拟合复杂的函数并不是一开始就能成功的,resnorm是一个衡量拟合质量好坏的参数,所以不建议采用前四中格式。本次采用的为:[x,resnorm] = lsqcurvefit(___)
2、编写待拟合的函数
在拟合的.m文件末尾编写待拟合的函数,以下为我需要拟合的函数,其中含有6个未知参数。在拟合前,一定一定要多次检验待拟合函数的正确性。待拟合函数中出现错误,会是致命的错误。以下,是本人需要拟合的函数。
function neff=nef_r(a,f)
epxlb=a(1); f0e=a(2); miub=a(3); fpm=a(4); f0m=a(5); gammam=a(6);
epxl0=1/(36*pi*10^9);
miu0=4*pi*10^-7;
h=0.0003;
d=0.003;
k=2*pi*f*sqrt(epxl0*miu0);
epxl=epxlb*(1-(f0e*10^9)^2./f.^2);
miu=miub-(fpm*10^9)^2./(f.^2-(f0m*10^9)^2+1i*(gammam*10^9)*f);
epxl_av=epxl*h/d;
miu_av=miu*h/d;
n_r=real(1./(k*d).*acos((4-(k*d).^2.*epxl_av.*miu_av)./(4+(k*d).^2.*epxl_av.*miu_av).*cos(k*d)-(2*(epxl_av+miu_av).*k*d)./(4+(k*d).^2.*epxl_av.*miu_av).*sin(k*d)));
n_i=imag(1./(k*d).*acos((4-(k*d).^2.*epxl_av.*miu_av)./(4+(k*d).^2.*epxl_av.*miu_av).*cos(k*d)-(2*(epxl_av+miu_av).*k*d)./(4+(k*d).^2.*epxl_av.*miu_av).*sin(k*d)));
for m=1:length(f)
if n_i(m)<0
n_r(m)=-n_r(m);
n_i(m)=-n_i(m);
end
end
neff=n_r;
end
3、设置拟合的上、下限以及初始值。
这应该是多个未知参数拟合最难的部分,也是最容易卡壳的地方。在设置拟合的上、下限和初始值时,稍有偏差,就会使拟合效果不佳,即resnorm值偏大。这一部分我们留到最后再说明如何调试出较佳的拟合效果。
a0=[1; 35; 10; 26; 10; 0.02];%初始值
lb=[0; 30; 1; 24; 8; 0];%下限
ub=[2; 50; 14; 30; 20; 0.5];%上限
4、绘图
应该是最简单,但却又是很重要的部分。绘图是最直观的观测拟合效果的方法。我们将原始数据real(n)用红色实线绘图,待拟合函数用红色虚线绘图。
plot(f/(10^9),real(n),'r');
hold on;
plot(f/(10^9),n_r,'r--');
hold on;
5、拟合选项设置
options = optimset('Display','iter','Tolx',1e-15,'TolFun',1e-15);
其中,‘Display’为显示级别,本次显示级别为‘iter’,在每次迭代时显示输出。
‘Tolx’为关于当前点 x 的终止容差,在当前点与先前点相差小于 TolX 时(相对于 x 的大小),迭代结束。本次当前点 x 终止容差为1e-15。
TolFun’为函数值的终止容差,在当前函数值与先前值相差小于 TolFun 时(相对于初始函数值),迭代结束。本次函数值的终止容差为1e-15。
6、进行拟合
[x,renorm]=lsqcurvefit(@nef_r,a0,f',real(n),lb,ub,options)
当然,多未知参数非线性函数的拟合并不是一蹴而就的。需要不断的调试拟合的初始值、上限和下限。这会是一个漫长的过程。
接下来需要啃的硬骨头就是调试过程了:
1、首先,我们需要知道未知参数的大致量级,可以根据函数内未知参数的实际意义出发得到大概量级。
2、粗调:因为每次拟合得到的未知参数都是无法精准控制的。所以可以另写一个.m文件,提前给予未知参数一个确定的值(当然这个值是在已知每个未知参数的量级的前提下去大胆尝试)代入到待拟合函数中,对比绘画出的红色实线图形与红色虚线图形形状。如果形状大致一样,就可以进行下一步的细调;若形状不一样,继续修改猜测值,直到图形大致一致为止。
a0=[1.87 34.14 10.12 26.35 10.09 0.0224];
3、细调:细调的工作,我们就交给lsqcurvefit函数。将初始值设置为猜测值。将上下限稍微调大一些,当然初值得在上下限之间。再逐一缩小上限限,适当修改初始值,使resnorm值越小越好。注意:唯一的目的是使resnorm值越小。当拟合函数没问题以及resnorm值足够小时,实线与虚线应该是大致重合的。