Специальные подсистемы в Engee
Специализированные подсистемы в Engee
В сообществе уже обсуждались различные методы разделение модели на смысловые и функциональные блоки с помощью подсистем и моделей ссылок. Однако, в Engee существуют специализрованные подсистемы, позволяющие создать и использовать конструкции программирования. Цель данной публикации - ознакомится с ними.
Action-Call подсистемы
Задача этих подсистем - срабатывать по условию, заданному как вызов функции. Здесь, вызов функции является событием, которое генерируется блоками If-else или Switch-Case. Применение таких подсистем позволяет промоделировать ветвление алгоритмов. Для этого предназначены блоки Оператор If и Оператор Switch Case. Пример использования этих блоков находится в модели function_callers.
Промоделируем такую конструкцию с помощью блока Оператор If:
if u > 0
y = foo()
else
y = bar()
end

Аналогично, с помощью блока Оператор Switch Case можно промоделировать конструкцию:
switch u
case 1:
y = foo_case()
default:
y = bar_case()
end

Вы наверняка заметили, что выходы подсистем подаются на блок Merge. Это специальный блок, который объединяет несколько входных сигналов в один. Главное правило - в конкретный момент времени "активным" должен быть только один сигнал. Под "активностью" понимается то, что у сигнала есть действительное значение.
На практике это работает так: когда осуществляется вызов подсистемы foo(), то на выходе этой подсистемы появляется значение, а в это время bar() неактивна и ее выход не имеет значения, и наоборот.
Так же следует обратить внимание на то, что на выходе блоков операторов if и switch case сигналы являются "вызовами" функций. Это специальный тип сигналов в Engee, предназначенный для "активации" подсистем, содержащих блок Порт действия (Action Port). В качестве примера использования этого блока рассмотрим подсистему foo:
.png)
Подсистемы с итераторами
Данные подсистемы предназначены для выполнения нескольких итераций своего содержимого за один шаг симуляции. Эти подсистемы являются прямыми аналогами циклов for, while и do…while. Примеры таких подсистем находятся в модели iterative_subs.
Важно!
Подсистемы с итераторами выполняют N итераций за один шаг симуляции. Выходной сигнал такой подсистемы - это результат, полученный после завершения всех итераций.
For Iterator Subsystem
Данная подсистема реализует цикл for с помощью блока "Итератор For". Посмотрим на его настройки:
Для нас представляют интерес настройки итератора (переменной итерации). Например, можно задать свой итератор с помощью настройки Внешний источник переменной итерации. Далее, мы можем использовать значение внешнего сигнала, как источник количества итераций, а не вводить его вручную. Такая настройка позволяет гибко управлять количеством итераций:
Здесь, на вход VectorSig поступает некоторый векторный сигнал, затем он поступает на вход блока Probe. Блок Probe - это служебный блок, который извлекает информацию о сигнале, в том числе и количество элементов в сигнале. Затем, количество элементов передается в блок итератора как количество итераций:
Дополнительно, мы извлекаем значение нашего итератора с помощью настройки Вывод переменной итерации.
While Iterator Subsystem
Данная подсистема реализует условный цикл while или do…while с помощью блока Итератор While. Итерации будут выполняться до тех пор, пока на входе cond будет положительный ненулевой сигнал. Как и для For можно вывести значение итератора.
Как и в обычных языках программирования при применении таких циклов всегда есть опасность создания бесконечного цикла. Для защиты от бесконечного цикла у блока Итератор While есть настройка максимального количества итераций:
Рассмотрим различие между типами циклов while и do…while:
В случае while у блока существует дополнительный вход IC - начальное логическое условие
Подсистемы For Each
Подсистемы For Each предназначены для работы с многомерными сигналами. Такая подсистема разделяет один или несколько входных сигналов на элементы и применяет свое содержимое на каждый элемент. Удобство заключается в том, расчет количества итераций происходит автоматически.
Такая подсистема - это прямой аналог цикла foreach, который есть во многих современных языках программирования.
Важно! В таких подсистемах как минимум один вход должен иметь настройку "Разделение":
Три следующие настройки позволяют настроить разделение входного многомерного сигнала.
В качестве примера воспользуемся моделью for_each_subsystem:
На вход этой подсистемы будет поступать вектор из двух синусоид, а внутри к каждому элементу вектора будет применена следующая операция:
Обратите внимание, что я дополнительно извлекаю номер итерации. Посмотрим как работает эта модель:
fe_sub = engee.open(joinpath(@__DIR__,"for_each_subsystem.engee"))
res = engee.run(fe_sub)
orig_sig = collect(res["Генератор синусоиды-1.1"])
proc_sig = collect(res["For Each Subsystem.Выход1"])
p1 = plot(orig_sig.time,stack(orig_sig.value,dims=1),label=["O1" "O2"])
p2 = plot(proc_sig.time,stack(proc_sig.value,dims=1),label=["O1" "O2"])
plot(p1,p2,layout = (2,1),link = :x)
Первый график - это оригинальный сигнал, а нижний - результат работы подсистемы For Each
Выводы
В данной публикации мы познакомились с специализированными подсистемами, которые позволяют реализовывать типичные конструкции программирования и облегчают задачи моделирования.