• Регистрация
MaximSidorov
MaximSidorov +118.29
н/д

Моделируем распространение коронавирусной инфекции COVID-19 в Simulink - часть 3

15.04.2020

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

Спасибо!

Теги

    15.04.2020

    Комментарии

    • NB
      NB+13.21
      15.04.2020 20:23

      Спасибо. А что насчет подгонки какой-то модели под наши данные распространения в РФ?