Моделируем распространение коронавирусной инфекции COVID-19 в Simulink - часть 3
Итак, сначала мы с вами познакомились с проектом моделирования распространения вирусной инфекции. Потом посмотрели, как эта модель построена в Simulink и Stateflow.
А теперь посмотрим, как сделана визуализация и управление симуляцией в MATLAB и App Designer с применением новых функций среды MATLAB.
Напоминаю, что вы можете самостоятельно поиграться с этой моделью, для чего можете оперативно получить от нас пробную версию MATLAB R2020a на время карантина. Скачать проект можно в первом посте.
Начнем с того, что симуляция распространения эпидемии предполагает задание ряда параметров: количество людей, их скорость передвижения, долю людей, которые сидят на карантине и не двигаются и др.
Чтобы не здавать эти параметры каждый раз через окно команд или не писать в каком-нибудь скрипте, я решил сделать удобный интерфейс для настройки и запуска симуляции, а также для визуализации результатов. Лучше всего для создания графических интерфейсов и приложений подходит инструмент App Designer, который встроен в MATLAB.
С помощью App Designer я создал приложение propagationApp
, интерфейс которого вы видите на картинке.
При запуске приложение отрисовывает начальный момент симуляции, поэтому не левом графике вы видите начальную расстановку точек (людей), а на правом пока ничего нет.
Двигая ползунки в левой части приложения, можно настроить параметры симуляции, что сразу отображается на графике. При этом параметры симуляции и начальные координаты и скорости точек с помощью функции initData()
записываются в переменную initdata
. Из этой переменной их считывает Simulink-модель в начале симуляции.
Когда параметры настроены, мы нажимаем кнопку Simulate и ждем, пока модель закончит выполнение. После чего в окне приложения отрисовываются конечное расположение точек и график изменения количества здоровых, больных и переболевших.
При нажатии кнопки Animate Propagation открывается новая фигура, в которой точки начинают двигаться, а графики отрисовываются на глазах. Это выгляди достаточно залипательно и позволяет качественно оценить, как передается инфекция между людьми.
(нижмите на картинку, чтобы анимировать)
Если вы уже делаете приложения в App Designer или только задумываетесь о том, чтобы попробовать, советую изучить приложение propagationApp
, в котором реализован адаптивный интерфейс, работа с Workspace и моделью Simulink. А начать лучше с короткого видео, в котором я описывал начало работы с инструментом:
1. Объявление аргументов
Также программистам в MATLAB может быть интересен класс propagationAnimator
, который отвечает за отрисовку визуализации распространения и за ее анимацию. Это хороший пример объектно-ориентированного программирования в MATLAB и анимирования графиков.
Он создан с использованием последних нововведений MATLAB, о которых вы могли не знать. Давайте их разберем.
Для примера посмотрим на конструктор класса. Он начинается с кода:
function obj = propagationAnimator(data, task, opts)
%POPULATIONANIMATOR Construct an instance of this class
arguments
data
task {mustBeMember(task, {'silent','init','play','plot'})} = 'play'
opts.Figure = []
opts.Ts {mustBeNumeric,mustBePositive} = 0.1
opts.ForceNewWindow logical = false
end
obj.Figure = opts.Figure;
obj.ForceNewWindow = opts.ForceNewWindow;
Обратите внимание на блок arguments...end
. В нем описаны входные агументы функции:
- обязательные: data
- опциональные: task
- параметры: Figure
, Ts
, ForceNewWindow
Это позволяет очень лаконично задать типы аргументов, различные проверки, а главное - значения по умолчанию! Больше не нужно мучаться с nargin
, varargin
и inputParser
, все стало красиво и удобно.
Возьмем к примеру параметр Ts
- когда мы его передаем функции, она сама проверяет, что это число и оно больше нуля, а если Ts
мы не передадим, то он инициализируется значением 0.1
.
А для опционального аргумента task
задан набор допустимых значений. Если пользователь попытается передать каку-то свою строку, то автоматически получит информативную ошибку со списком возможных значений:
Более того, теперь при наборе функции в окне команд или в скрипте работает автодополнение, прямо как со встроенными функциями. Это значительно упрощает использование ваших функций другими людьми.
Такое задание аргументов работает не только в классах, но и с обычными функциями, поробнее читайте здесь. А мы переходим к следующей фиче.
2. Адаптивная раскладка графиков
Раньше, чтобы отобразить несколько графиков в одной фигуре, нужно было использовать функцию subplot()
, которая позволяла задать раскладку фигуры и заполнять ее графиками в определенной конфигурации. Это способ неплохо работает и сейчас, но у него есть один недостаток - если вы будете менять размер окна, нарушать его пропорции, то графики останутся на своих местах и не будут менять свое местоположение на фигуре ради лучшей читаемости. То есть у subplot()
нет адаптивности под размер окна которая сейчас повсеместно рулит.
А вот у новой функции tiledlayout()
адаптивность есть! Посмотрите, как графики автоматически перераспределяются при изменении ширины окна:
Но больше всего функция tiledlayout()
понравилась мне за то, что она умеет создавать оси не только в обычной фигуре (figure
), но и на панелях приложений App Designer (uipanel
)! Чем я и воспользовался, чтобы сделать приложение адаптивным. В приложении графики отрисовывает тот же код класса propagationAnimator
, который строит их в отдельной обычной фигуре:
Подробнее о tiledlayout()
3. Передискретизация данных
В заключение расскажу о приеме, который я использовал, чтобы сделать анимацию плавной и иметь возможность управлять ее скоростью.
После симуляции на выходе из модели мы получаем переменную out
, в которой среди прочего хранятся координаты всех точек во времени, на основе которых строится анимация. Но тут важно учитывать, что модель согласно настройкам решателя работает с переменным шагом, поэтому наши кадры для анимации получаются с рваным шагом.
А чтобы анимация была плавной, нам нужно чтобы временной шаг наших данных был постоянным, тогда мы можем просто брать точки по очереди и выводить их на график. А изменяя длительность такта, мы можем управлять скоростью, с которой анимация будет происходить.
Иначе говоря, если у нас в 10-секундном сигнале 10 точек с тактом 1 с, анимация будет содержать 10 кадров и пройдет быстро. А если это будет 1000 точек с тактом 0,001 с, то анимация замедлится в 100 раз. А если шаг вообще будет непостоянным, то анимация будет дергаться.
Возникает вопрос - как из исходного сигнала с непостоянным шагом получить сигнал с заданным постоянным?
propagationAnimator
использует для этого функцию retime()
, которая позволяет передискретизироавть данные. Чтобы она работала, данные переводятся во временнУю таблицу timetable
. А меняя свойство Ts
объекта propagationAnimator
, мы изменяем количество точек в сигнале, управляя тем самым скоростью анимации.
На картинке представлены выборки сигналов: с рваным шагом ДО retime()
(1299 точек) и с постоянным шагом ПОСЛЕ (596 точек)
Подробнее о timetable()
и retime()
я рассказывал в видео:
Заключение
Итак, я осветил в этой статье некоторые из самых интересных, на мой взгляд, нововведений последних релизов MATLAB. Уверен, что вы тоже сможете эффективно их использовать в своих проектах.
На этом я вроде бы рассказал все, что хотел, про симулятор распространения вируса, так что цикл статей можно предварительно считать законченым, дальше дело за вами. Если я забыл осветить что-то интересное, напишите об этом коммент, дополню цикл.
Также напишите, стоит ли еще писать про новые и крутые фишки MATLAB.
Спасибо!
Комментарии
Спасибо. А что насчет подгонки какой-то модели под наши данные распространения в РФ?