2016-02-29 83 views
1

我想做这个“手工”,而不是使用曲面拟合工具,因为根据我有的数据,曲面拟合可能会有所不同。所以,我首先读取Excel表格中的数据,然后初始化一些系数,计算一个3D表面(f(x,y)),然后计算总最小平方和,我希望将其最小化。每次我运行该脚本时,它都会告诉我我处于本地最小值,即使我更改了初始值。改变容差也不会影响结果。从最基本的原则最小二乘曲面拟合

这是代码:

% flow function in a separate .m file (approximation, it’s a negative paraboloid, maybe if required, this function may vary): 

function Q = flow(P1,P2,a,b,c,d,e,f) 
Q1 = a-b.*P1-c.*P1.^2; 
Q2 = d-e.*P2-f.*P2.^2; 
Q = Q1 + Q2; 

% Variable read, I use a xlsread instead 
p1a = [-5, -5, -5, -5, -5, -5, -5, -5, -5, -5]; 
p2a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 
qa = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 

p1b = [-6, -6, -6, -6, -6, -6, -6, -6, -6, -6]; 
p2b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 
qb = [12, 11, 10, 9, 8, 7, 6, 5, 4, 3]; 

% Variable initialization 
coef = [50, 1, 1, 10, 1, 1]; 

% Function calculation 
q1a = flow(p1a,p2a,coef(1),coef(2),coef(3),coef(4),coef(5),coef(6)); 
q1b = flow(p1b,p2b,coef(1),coef(2),coef(3),coef(4),coef(5),coef(6)); 

% Least squares 
LQa = (qa-q1a).^2; 
LQb = (qb-q1b).^2; 
Sa = sum(LQa); 
Sb = sum(LQb); 
St = Sa+Sb; 

% Optimization (minimize the least squares sum) 
func = @(coef)(St); 
init = coef; 
opt = optimoptions('fminunc', 'Algorithm', 'quasi-newton', 'Display', 'iter','TolX', 1e-35, 'TolFun', 1e-30); 
[coefmin, Stmin] = fminunc(func, init, opt); 

如果你运行它,你应该得到的​​结果为Stmin,但如果你改变的系数,你会得到另一种结果,而这也将是视为当地最低标准。

我在做什么错?

+1

所以你说当你改变初始值时你正在碰到不同的局部最小值?这听起来很正常......一种解决方法是用一些不同的初始值向量播种,然后选择性能最佳的播放器(多启动策略) – Dan

+0

感谢您的回答。对我知道那个。问题是,第一次迭代显示我最低限度,这不正确。而且我也知道,在6个自由度中,我可以有一组无穷的结果(局部最小值),以及另一个无限的全局最小值结果集。我不在乎每个系数的值是什么(我没有限制),我只需要一个全局最优(一个),这将允许我(和任何想要使用此代码的人)更好地适合我的实验点多项式二次表达式。 – Lifehaxor

+0

好吧,我现在看到了,你的问题并不清楚。问题在于你如何定义'func'。我发布了一个答案,显示它应该如何。 – Dan

回答

1

问题是您的func只是一个常数。它只是返回预先计算的值,St,无论您传递给func的输入如何,该值都是常数。尝试使用各种不同的输入呼叫func来测试。

您的目标函数需要包含将您带到St的所有计算。因此,我建议你保存在一个M文件的函数看起来像这样替换你func

function St = objectiveFunction(coef, p1a, p2a, p1b, p2b, qa, qb, q1a, q1b) 

    % Function calculation 
    q1a = flow(p1a,p2a,coef(1),coef(2),coef(3),coef(4),coef(5),coef(6)); 
    q1b = flow(p1b,p2b,coef(1),coef(2),coef(3),coef(4),coef(5),coef(6)); 

    % Least squares 
    LQa = (qa-q1a).^2; 
    LQb = (qb-q1b).^2; 
    Sa = sum(LQa); 
    Sb = sum(LQb); 
    St = Sa+Sb; 

end 

然后在你的脚本调用objectiveFunction利用这样的匿名函数:

[coefmin, Stmin] = fminunc(@(coef)(objectiveFunction(coef, p1a, p2a, p1b, p2b, qa, qb, q1a, q1b)), init, opt); 

的的想法是创建一个匿名函数,只需要一个参数coef,这是fminunc将会宠爱并转回到您的目标函数的变量。您的objectiveFunction需要的其他参数(即p1a, p2a, p1b,...)现在被认为是由您的匿名功能预先计算的,因此也被fminunc预先计算。

其余的代码可以保持不变。

+0

非常感谢丹。我希望这段代码能够为社区其他人带来一些想法。问候。 – Lifehaxor