Ошибки симуляции математических моделей с тригонометрическими функциями в Matlab&Simulink
23.03.2020
Рассмотрены два вида построения математической модели:
- Используя Matlab function, с определением в ней функции sin
- Используя тригонометрическую функцию sin
В связи с этим возникает вопрос - как правильно завести данную модель ?
Модели прикладываю. Дифференциальное уравнение вида : dx/dt=sin(x+pi); x(0)=0
Ответы
А что не так-то? (я про модель) Вроде то, что вы собрали, работает как надо (в соответствии с графиками).
Так-то scope должен показать 0 без колебаний. Решение дифференциального уравнения: x(t)=0
там у вас что-то в духе минус 16 степень
на правом графике -4 степень, что уже не мало. Но это синтетический пример, есть несколько реальных, когда система приходит в ноль и вдруг происходит какая-то странная вешь и из нуля она выбегает. Иногда это просто объяснить численностью моделирования матлаба, но не всегда так легко списать проблему на это.
Хочется понять, что делать в подобных ситуациях.
С "синтетическим" примером вроде все ок.
Анализировать работу, искать ощибки. (имхо)
Какие ошибки могут быть в sin(pi)=0 ?
1. А вы попробуйте синус пи в командной строке просто введите.
2. Матлаб это машина делающая численные вычисления. Любые алгоритмы имеюют точность. Это вы в курсе, что синус пи это ноль. А в машине обычно алгоритм на общий случай любого аргумента.
3. Самое занятное, что даже числа пи вы тоже не знаете, а только с какой-то точностью.
Все это понятно, вопрос-то в другом. Как лучше поступить чтобы убрать такое?
Поможет ли zero-crossing, как его настроить?
На практике это не нужно убирать. Максимум, что можно сделать - это уменьшить погрешность с помощью подбора и настройки решателя.
В данной задачае можно просто уменьшить масштаб по оси ординат и все эти шумы рещателя сольются в прямую линию) Какое нам дело до степеней -16, когда у нас на входе числа порядка pi.
Добрый день, никаких ошибок тут нет. Вы столкнулись с особенностями численных расчетов, давайте по порядку.
Начнем с модели BUG_1, где синус выполнен в виде MATLAB-функции. В настройках модели стоит решатель auto, и Simulink автоматически выбирает решатель ode45 с максимальным шагом 0.2 с, что отображается в нижнем правом углу модели.
На выходе вы получаете график, который прислали.
Да он не нулевой, как ожидалось, но обратите внимание на порядок величин - 3e-16, что вполне согласуется с точностью чисел типа double и является всего лишь допустимой погрешностью расчета, которой можно пренебречь. Более того, если вы попробуете другие решатели (например, fixed step ode4), то графики и погрешность расчета будут отличаться, но, в любом случае, результат будет около нуля.
Так работают численные решатели дифференциальных уравнений и с этим приходится мириться. Не может процессор считать идеально :) Не зря ведь в настройках ode45, например, есть целых 2 настраиваемых параметра точности.
Теперь модель BUG_2. Когда я открыл ее и запустил, симуляция остановилась с ошибкой на 0,0119 секунде. Дело в том, что у нее тоже стоит решатель auto, но в данной модели Simulink атвоматически ставит решатель ode15s с огромным шагом интегрирования 2 с. И получается, что этот решатель с такими настройками не способен справиться с задачей.
Для простоты поставим для этой модели решатель ode45 с максимальным шагом 0.2 - как в предыдущей модели.
Получаем вот такой страшный график
Возникает 2 вопроса:
- Почему график так сильно отличется от первой модели, если и там и там - всего лишь синус, хоть и задан он по-разному?
- Почему по графику получается такая дикая погрешность - 4e-4? Это уже никак не соотносится с погрешностью типа double
Ответ на оба вопроса кроется в настройках блока sin второй модели. По какой-то причине, видимо в ходе экспериментов, вы включили в параметрах блока синуса (Trigonometric Function) вместо чистого синуса его аппроксимацию методом CORDIC, чем загрубили расчет. В данной задаче нам это не нужно, скорее, только мешает.
Если в Approximation method поставить None и запустить симуляцию на 10 секундах, то получим точно такой же график, что и в первой модели.
Итак, мы выяснили, что при одинаковых настройках решателя, обе модели работают одинаково, с допустимой точостью, которой мы можете управлять путем тонкой настройки решателя. В данном случае, я бы рекомендовал использовать второй вариант с блоком Trigonometric Function, чтобы не переусложнять модель кодом MATLAB.
И в качестве бонуса хочу обратить ваше внимание на еще один важный момент. Дело тут ведь не только в решателях.
Не забывайте, что, задавая число пи с помощью функци pi, вы получаете ни чистое пи, определенное до бесконечного количества знаков после запятой, а "почти" пи, определенное с точностью типа данных double - до 16 знака после запятой. Поэтому вы в принципе не можете ожидать от синуса идельный ноль, ведь вы подаете неидеальное пи.
Если это практическая задача, то оставляйте все как есть, и не бращайте внимание на погрешность выходного сигнала, считайте, что он нулевой.
Если же вам принципиально получить чистый ноль в демонстрационных целях - замените в блоке MATLAB Function функцию sin на sind, которая принимает на вход не радианы, а градусы. Соответственно в модели замените константу pi на 180.
Получите идеальную прямую линию.
ВЫВОДЫ:
1) ошибок тут нет, все работает, как должно
2) правильно выбирайте и настраивайте решатели. Вот инструкция:
https://www.mathworks.com/help/simulink/ug/choose-a-solver.html
https://docs.exponenta.ru/simulink/ug/choose-a-solver.html
3) погрешность есть всегда и с ней приходится мириться, а также ей можно управлять
4) Иногда погрешность можно свести к нулю, используя правильные блоки
Спасибо за интересный вопрос! У самого на заре работы в Simulink возникали подобные проблемы, пришлось быстро понять, что решатель - это не какая-то непонятная штука, а очень важная вещь, которую не нужно бояться и которой нужно управлять.
P.S. Приходите к нам не тренинги, на SLBE мы подробно разбираем особенности численных расчетов и работы решателей
https://exponenta.ru/SLBE
Это зависит от того, чем оно вам мешает. Если у вас на фоне таких нулей (что обычно на првктике и имеет место) есть еще реальные не нулевые величины, то -16 степень в принципе не видна.
Можно блок ифо-кейса вляпать (if block). Т.е. если значение мешьше к.л. значения (1е-9 например), то на выход отправлять ноль.