MATLAB 中進行非線性最小二乘擬合的函數為:lsqnonline 函數和 lsqcurvefit 函數。幫助文檔中的解釋為:
lsqnonlin: Solve nonlinear least-squares (nonlinear data-fitting) problem(非線性最小二乘);
lsqcurvefit: Solve nonlinear curve-fitting (data-fitting) problems in least-squares sense(非線性曲線擬合)。
但是這兩個函數本質上是一樣的,他們用的默認算法都是:trust-region-reflective,並且都可以修改為:levenberg-marquardt
algorithm(詳見MATLAB中的幫助文檔)。
這兩個函數的不同在於 lsqcurvefit 的使用形式要更簡單一點。下面將結合MATLAB中的幫助文檔,簡單介紹這兩個函數的使用方法。
lsqnonlin 非線性最小二乘
其中,x就是個待辨識的參數,本質就是求滿足最適合的參數x,是的擬合誤差最小。
% 函數 lsqnonlin 非線性最小二乘 % 格式 x = lsqnonlin(fun,x0) x = lsqnonlin(fun,x0,lb,ub) x = lsqnonlin(fun,x0,lb,ub,options) % x0為初始解向量; % lb、ub為解向量的下界和上界lb≤x≤ub,若沒有指定界,則lb=[ ],ub=[ ]; % options為指定的優化參數; % lsqnonlin解決非線性最小二乘法問題,包含非線性數據的擬合問題 % 其中初值x0要有。lb,ub,option可為空
使用例子,有兩種:
第一種是使用兩個文件(其中一個是函數文件,另一個是求解文件):
首先建立函數文件:
function result = NonlinFun(t) x = [0.1 0.5 1 1.5 2.5 4.5 6 7]; % 原函數的輸入 y = [29.45 26.65 23.52 20.76 16.16 9.81 6.74 5.25]; % 原函數的輸出 a = t(1); b = t(2); % 待擬合的參數 result = y - a*exp(-b*x); % 返回擬合結果 end
然后建立求解文件:
% 使用lsqnonlin函數辨識:用兩個文件書寫,進行非線性最小二乘擬合 clear; clc; close all; a0 = [30 0.2]; % 待辨識參數的初值 A = lsqnonlin('NonlinFun',a0) % 非線性擬合 % 將擬合結果代入函數 xx = 0:0.2:7; yy = A(1)*exp(-A(2).*xx); % 這兩組數據放在這里只是為了畫圖使用 x = [0.1 0.5 1 1.5 2.5 4.5 6 7]; % 原函數的輸入 y = [29.45 26.65 23.52 20.76 16.16 9.81 6.74 5.25]; % 原函數的輸出 figure(1); plot(xx,yy,'r-') hold on plot(x,y,'bp')
直接運行求解文件就可以得到結果,結果如下:
第二種:使用一個文件求解,也就是不使用單獨的函數文件:
% 使用lsqnonlin函數辨識:用一個文件書寫,進行非線性最小二乘擬合 clear; clc; close all; x = [0.1 0.5 1 1.5 2.5 4.5 6 7]; % 原函數的輸入 y = [29.45 26.65 23.52 20.76 16.16 9.81 6.74 5.25]; % 原函數的輸出 fun=@(a)(a(1)*exp(-a(2)*x)-y); % 定義函數,其中a待辨識的參數 a0 = [30 0.2]; % 待辨識參數的初值 t= lsqnonlin(fun,a0) % 非線性最小二乘辨識 % 將辨識結果代入函數中 xx = 0:0.2:7; yy = t(1)*exp(-t(2).*xx); figure(1) plot(xx,yy,'r-') hold on plot(x,y,'bp')
運行結果如下:
lsqcurvefit 非線性曲線擬合
% 函數 lsqcurvefit 非線性曲線擬合 % 格式 x = lsqcurvefit(fun,x0,xdata,ydata) x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub) x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub,options) % 參數說明: % x0為初始解向量;xdata,ydata為滿足關系ydata=F(x, xdata)的數據; % lb、ub為解向量的下界和上界lb≤x≤ub,若沒有指定界,則lb=[ ],ub=[ ]; % options為指定的優化參數; % fun為待擬合函數,計算x處擬合函數值,其定義為function F = myfun(x,xdata)
例子:
% lsqcurvefit 非線性曲線擬合:用一個文件書寫,進行非線性最小二乘擬合 clear; clc; close all; x = [0.1 0.5 1 1.5 2.5 4.5 6 7]; % 原函數的輸入 y = [29.45 26.65 23.52 20.76 16.16 9.81 6.74 5.25]; % 原函數的輸出 a0 = [30 0.2]; % 待辨識參數的初值 f=@(a,x)a(1)*exp(-a(2)*x); % 定義函數,a為待擬合的參數,特別注意,需要把自變量x也寫到函數變量聲明中 t= lsqcurvefit(f,a0,x,y) % 非線性曲線擬合 % 將辨識結果代入函數中 xx = 0:0.2:7; yy = t(1)*exp(-t(2).*xx); figure(1) plot(xx,yy,'r-') hold on plot(x,y,'bp')
結果:
由此可見,上述兩個函數的計算結果是一致的。可以發現,這兩個函數的做大區別是定義函數的不同:lsqnonline 定義的是誤差函數,lsqcurvefit 定義的辨識原函數。
局限性:
非線性最小二乘辨識和非線性曲線擬合方法的辨識結果都依賴於初值的選擇!當初值給的越接近真實值,辨識出的結果越精確。如果最優解和所給的初值距離比較近,迭代求出最優解的概率就比較大;如果初值設計的不理想,離最優解比較遠,而MATLAB對於迭代次數和迭代精度都有個默認的設定,這種情況下很可能沒有搜到最優解便給出了結果,也就是這個結果只是局部最優,而不是全局最優。一個比較好的初值選擇的思路是:
確定數學模型后,擬合非線性問題時,初值的選取:
1. 如果已知數學模型,有一定物理意義,則建議根據物理意義選取。
2. 當無法確定初值時,且你的數學模型有導數(如果求導模型很復雜甚至沒有導數,則可進行簡單的差分構造),則可以采用如下的辦法進行。
步驟:
(1)求出擬合函數的一階導數【如果有必要可求更高階導數】;
(2)使用已知數據求出近似點的一階導數 ;
(3)代入一階導數函數以及原函數求得初值近似值
一個檢查初值選取是否合適的思路:得到辨識結果后,畫出函數圖形,看看已知的數據點是否都在曲線附近,如果相差太大,就得考慮重新給初值再計算一次,直到獲得理想的結果。
總結:采用最小二乘法進行非線性參數辨識時,容易出現局部最優解,可以使用遺傳算法等智能方法進行非線性參數辨識,可以得到全局最優解。