2016-02-29 7 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); 

Если запустить это, вы должны получить результат 15546 для Stmin, но если изменить коэффициенты, вы получите другой результат, и он также будет рассматриваемый как локальный минимум.

Что я делаю неправильно?

+1

Итак, вы говорите, что при изменении начальных значений вы используете другой локальный минимум? Это звучит довольно нормально ... одно обходное решение состоит в том, чтобы засеять его несколькими различными векторами начальных значений, а затем выбрать тот, который лучше всего работает (стратегия с несколькими пусками). – Dan

+0

Спасибо за ваш ответ. Да, я знаю это. Проблема в том, что первая итерация показывает мне минимум, и это не нормально. И я также знаю, что с 6 степенями свободы я могу иметь бесконечный набор результатов (локальные минимумы) и еще один бесконечный набор результатов для глобальных минимумов. Мне все равно, какие значения найдены для каждого коэффициента (у меня нет ограничений), мне нужен только глобальный оптимум (один), который позволит мне (и любому, кто хочет использовать этот код) лучше подойти к моим экспериментальным точкам с помощью полиномиальное выражение 2-й степени. – Lifehaxor

+0

ОК, я вижу сейчас, это было непонятно из вашего вопроса. Проблема в том, как вы определили 'func'. Я опубликовал ответ, показывающий, как это должно быть. – Dan

ответ

1

Проблема в том, что ваш func является константой. Он просто возвращает предварительно рассчитанное значение, St, которое является постоянным независимо от того, какой ввод вы передаете func. Попробуйте позвонить func с различными входами, чтобы проверить это.

Ваша целевая функция должна содержать все вычисления, которые привели вас к St. Поэтому я предлагаю вам заменить 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

 Смежные вопросы

  • Нет связанных вопросов^_^