Корни MATLAB функционируют в MATLAB иначе, чем в Simulink?

Я реализовал следующую пользовательскую функцию в MATLAB:

function Q = Calc_Q(Head, freq)
b6 = [3.7572E-07 -1.5707E-05 6.0490E-03 5.0018E-02 2.1180E-01];
b5 = [-9.0927E-06 8.9033E-04 -3.2415E-02 5.4525E-01 -8.1649E+00] / 10e2;
b4 = [7.5172E-06 -5.6565E-04 1.0024E-02 3.5888E-01 3.8894E-02] / 10e5;
b3 = [-4.8767E-06 4.8787E-04 -1.3311E-02 -1.2189E-01 -5.3522E+00] / 10e8;
b2 = [5.9227E-06 -8.1716E-04 3.5392E-02 -4.5413E-01 1.9547E+00] / 10e11;
b1 = [-2.0004E-06 2.9027E-04 -1.3754E-02 2.3490E-01 -1.2363E+00] / 10e14;

a = [polyval(b1,abs(freq)), polyval(b2, abs(freq)), polyval(b3, abs(freq)), polyval(b4, abs(freq)), polyval(b5, abs(freq)), polyval(b6, abs(freq)) - Head];

Q_roots = roots(a);
%Delete roots with imaginary part
i = 1;
while i <= length(Q_roots)
    if(imag(Q_roots(i)) ~= 0)
        Q_roots(i) = [];
        i = i - 1;
    end
    i = i + 1;
end
%Delete roots with real part greater then 3100
i = 1;
while i <= length(Q_roots)
    if(Q_roots(i) >= 3100 || Q_roots(i) < 0)
        Q_roots(i) = [];
        i = i - 1;
    end
    i = i +1;
end

if freq < 0
    Q = real(Q_roots(1)) * -1;
else
    Q = real(Q_roots(1));        
end
end

Когда я вызываю эту функцию в Matlab, она отлично работает. Однако, если я использую этот точный код как функцию MATLAB в simulink, он перестанет работать. (на самом деле это работает, но вывод всегда равен нулю.)

У меня есть подозрение, в чем может быть проблема. При запуске скрипта в режиме отладки я не могу просмотреть результат для Q_roots (он просто ничего не отображает).

Q_roots = roots(a);

Любые идеи ?


person Koen Van den Maegdenbergh    schedule 30.07.2015    source источник
comment
Какой блок Simulink вы использовали для вызова этой функции? Входные данные для функции в порядке в Simulink?   -  person Navan    schedule 30.07.2015
comment
Я использовал функциональный блок MATLAB... Я предполагаю, что входы в порядке... Я просто подключил 2 константы к входам   -  person Koen Van den Maegdenbergh    schedule 30.07.2015


Ответы (2)


Проблема, скорее всего, связана с вашей логикой, которая исключает любые корни, которые не имеют точно нуля в мнимой части. Это математический способ мышления, который на самом деле плохо работает в числовом выражении, по крайней мере, в целом. Все корни, вероятно, находятся в обоих случаях (нет никаких ограничений, которые подразумевают обратное), но в Simulink и при генерации кода проблема рассматривается как сложная, и некоторые корни могут возвращаться с крошечными мнимыми частями. Вместо удаления корней, если их мнимые части не равны нулю, удалите корни с мнимыми частями, которые численно несущественны, либо очень малы относительно действительной части, либо очень малы вообще. . Что-то вроде

tol = 10*eps(class(Q_roots));
keepers = abs(imag(Q_roots)) < tol*max(abs(real(Q_roots)),1) & ...
    real(Q_roots) >= 0 & real(Q_roots) <= 3100;
Q_roots = Q_roots(keepers);

позаботится обо всех удалениях одним махом. Здесь я использовал 10*eps в качестве допуска.

Но если вам нужен только первый соответствующий корень, вы можете просто сделать это:

Q = nan('like',a);
tol = 10*eps(class(a));
for k = 1:numel(Q_roots)
    r = real(Q_roots(k));
    if abs(imag(Q_roots(k))) < tol*max(abs(r),1) && r >= 0 && r <= 3100;
        Q = r;
        break
    end
end

if freq < 0
    Q = -Q;
end
person Michael Hosea    schedule 30.07.2015
comment
Майкл, если я посмотрю на корни, которые функция roots() создает соответственно в Matlab и simulink, Simulink действительно дает другой результат (то есть меньше найденных корней, а не тот, который меня интересует). - person Koen Van den Maegdenbergh; 31.07.2015
comment
Не могли бы вы предоставить мне точные входные данные Head и Freq, которые демонстрируют это? Мы ожидаем численно незначительные различия и другой порядок. Мы не ожидаем меньшего количества корней или других корней, за исключением случаев крайне плохого кондиционирования, когда тот или иной может давать более приятные результаты, но не постоянно. Основное преимущество MATLAB в этом вопросе заключается в возможности использовать решатель собственных значений для действительной матрицы, что приведет к точным комплексно-сопряженным парам для невещественных корней. - person Michael Hosea; 31.07.2015

Ок, я нашел проблему.

С другого форума:

Привет Космин,

Я взглянул на реализацию корней для блока Embedded MATLAB Function (\toolbox\eml\lib\matlab\polyfun\roots.m). Там указано:

% Ограничения: % Вывод всегда имеет переменный размер. % Вывод всегда сложный. % Корни могут быть не в том же порядке, что и в MATLAB. % Корни плохо обусловленных полиномов могут не соответствовать MATLAB. Последнее предложение вызывает у вас головную боль (и да, ваш полином плохо обусловлен!). Если вы посмотрите на график, то увидите, что кривая практически не касается оси x.

У меня есть предложение: значение -z/b является (очень) хорошим приближением к корню, который вы ищете...?

Тит

http://www.mathworks.com/matlabcentral/answers/25624-roots-in-simulink

Очевидно, корневая функция в simulink не всегда находит все корни данного многочлена. Это печально и не легко разрешимо. Однако я нашел решение.

Для всех различных многочленов, которые мне нужно решить, я знаю интервал интересующего меня корня ([-3000, 3000]).

Я просто в основном делаю шаги 50 от -3000 до 3000, пока функция не упадет ниже 0. Тогда я знаю примерное решение корня. Я использую это приближение в качестве основы для метода Ньютона-Рафсона.

Прямая реализация метода Ньютона-Рафсона с заданным начальным числом для всех полиномов, которые мне нужно решить, не работала, потому что иногда он повторялся до другого корня (того, который меня не интересовал).

Вот код:

function Q = Calc_Q(Head, freq)
    b6 = [3.7572E-07 -1.5707E-05 6.0490E-03 5.0018E-02 2.1180E-01];
    b5 = [-9.0927E-06 8.9033E-04 -3.2415E-02 5.4525E-01 -8.1649E+00] / 10e2;
    b4 = [7.5172E-06 -5.6565E-04 1.0024E-02 3.5888E-01 3.8894E-02] / 10e5;
    b3 = [-4.8767E-06 4.8787E-04 -1.3311E-02 -1.2189E-01 -5.3522E+00] / 10e8;
    b2 = [5.9227E-06 -8.1716E-04 3.5392E-02 -4.5413E-01 1.9547E+00] / 10e11;
    b1 = [-2.0004E-06 2.9027E-04 -1.3754E-02 2.3490E-01 -1.2363E+00] / 10e14;

    %coeff for the polynominal
    a = [polyval(b1,abs(freq)), polyval(b2, abs(freq)), polyval(b3, abs(freq)), polyval(b4, abs(freq)), polyval(b5, abs(freq)), polyval(b6, abs(freq)) - Head];

    %coeff for the derrivative of polynominal
    da = [5*a(1) 4*a(2) 3*a(3) 2*a(4) a(5)];

    Q = -3000;
    %Search for point where function goes below 0
    while (polyval(a, Q) > 0)
        Q = Q + 25;
    end    
    error_max = 0.01
    iter_counter = 1;
    while abs(polyval(a,Q)) >= error_max && iter_counter <= 1000
        Q = Q - polyval(a, Q)/polyval(da, Q);
        iter_counter = iter_counter + 1;
        error = abs(polyval(a,Q));
    end
    if(freq < 0)
        Q = Q * - 1;
    end
end
person Koen Van den Maegdenbergh    schedule 30.07.2015