Работа с пользовательскими шинами BusSignal в блоках оборудования
| Перед использованием пользовательских типов шин рекомендуется ознакомиться с блоками Создание шины и Выбор из шины. |
В Engee предусмотрена поддержка пользовательских структурированных сигналов через тип BusSignal (подробнее см. здесь). Этот тип позволяет объединить логически связанные сигналы в единую структуру — шину, где каждому элементу соответствует имя, тип и размерность (например, temperature::Int, position::Vector{Float64}, status::Bool).
Такие структуры удобны при взаимодействии с внешним оборудованием, которое возвращает или принимает целые наборы параметров. Так, вместо того чтобы передавать данные как неструктурированный набор:
(10, 3.2, [1, 2, 3])
Можно использовать шину с явно заданными именами:
(temperature = 10, pressure = 3.2, position = [1, 2, 3])
С помощью типа BusSignal такая структура может быть точно описана и типизирована на уровне модели, что важно для формализации интерфейса данных оборудования.
Тип BusSignal записывается следующим образом:
BusSignal{Names, Types, Dimensions, :BusName}
где:
-
Names— кортеж имен сигналов ((:a, :b, :c)); -
Types— соответствующие типы (Tuple{Int, Float64, Vector{Float64}}); -
Dimensions— размерности каждого элемента((), (), (3,))для скаляров и вектора длины 3); -
BusName— имя шины (заданное пользователем).
Тип BusSignal параметризуется именами сигналов (Names), базовыми типами (BaseTypes), размерностями (Dims), и именем шины (BusName). Например, шину с тремя сигналами можно описать так:
bus_type = BusSignal{(:s1, :s2, :s3), Tuple{Int, Float64, Float64}, ((), (), (3,)), :MyBus}
В BaseTypes указываются только базовые типы (например, Int, Float64), а не контейнеры (например, Vector{Int}).
Размерности массивов задаются отдельно в Dims.
|
Здесь:
-
:s1,:s2,:s3— имена сигналов; -
Tuple{Int, Float64, Float64}— типы данных сигналов; -
(), (), (3,)— размерности сигналов (например,s3— массив длины3). -
MyBus— имя шины.В имени сигнала и шины допустимы любые символы, кроме кавычки ( ").
Пример простого использования:
# Задаем значение типа шины (структуру без данных, поэтому круглые скобки)
bus_type = BusSignal((:a, :b), (Int, Float64), ((), ()), :MyBus)
# Создаем объекты этой шины, у параметров типа NamedTuple фигурные скобки
bus1 = BusSignal{(:a, :b), Tuple{Int, Float64}, ((), ()), :MyBus}((a = 5, b = 6.4))
# Через ключевые аргументы
bus2 = BusSignal{(:a, :b), Tuple{Int, Float64}, ((), ()), :MyBus}(a = 5, b = 6.4)
# Через позиционные аргументы (varargs)
bus3 = BusSignal{(:a, :b), Tuple{Int, Float64}, ((), ()), :MyBus}(5, 6.4)
Шины могут быть вложенными, например:
Inner = BusSignal{(:x, :y), Tuple{Int, Int}, ((), ()), :InnerBus}
Outer = BusSignal{(:a, :b), Tuple{Float64, Inner}, ((), ()), :OuterBus}
Для анализа типа доступны функции:
get_names_types_dims(::Type{BusSignal{Names, Types, Dimensions, BusName}}) where {Names, Types, Dimensions, BusName} # все параметры сразу
get_bus_names(::Type{BusSignal{Names, Types, Dimensions, BusName}}) where {Names, Types, Dimensions, BusName} # кортеж имен сигналов
get_bus_types(::Type{BusSignal{Names, Types, Dimensions, BusName}}) where {Names, Types, Dimensions, BusName} # кортеж базовых типов
get_bus_dimensions(::Type{BusSignal{Names, Types, Dimensions, BusName}}) where {Names, Types, Dimensions, BusName} # кортеж размерностей
get_bus_name(::Type{BusSignal{Names, Types, Dimensions, BusName}}) where {Names, Types, Dimensions, BusName} # имя шины
get_bus_signal_type(x::NamedTuple)
Функция get_bus_signal_type особенно удобна: она позволяет автоматически определить тип шины по значению, например:
bus = (s1 = 5, s2 = [4.3, 5.4], s3 = (a = 4, b = 5.5))
bus_type = get_bus_signal_type(bus)
# bus_type равен: BusSignal{(:s1, :s2, :s3), Tuple{Int64, Float64, BusSignal{(:a, :b), Tuple{Int64, Float64}, ((), ())}}, ((), (2,), ())}
Эта функциональность активно применяется в блоках оборудования. Чтобы не задавать типы шин вручную, такие блоки настраиваются масками — интерфейсом, в котором достаточно указать только имена и количество сигналов.
Далее рассмотрим, как работает эта схема: от параметров маски до автоматического формирования BusSignal внутри блока оборудования.
Пользовательские шины в блоках оборудования
Рассмотрим пример — динамическое формирование типов шин BusSignal на примере блока оборудования UM Cosimulation. Этот блок имеет следующие параметры:

Для того чтобы автоматически сформировать типы шин, достаточно задать только количество и имена входных и выходных сигналов через маску, а также имена самих шин.
Для того чтобы посмотреть как это работает — откройте маску блока (ПКМ по блоку/Маска/Посмотреть маску), перейдите во вкладку «Редактор кода» → Global и в обратном вызове blockChangedCallback найдите следующий код:
engee.set_param!(engee.gcb(), "InputPort1BusType" => "BusSignal($(mask.parameters.m_input_signal_names.value), Tuple(fill(Float64, $(mask.parameters.m_num_input_signals.value))), ntuple(_ -> (), $(mask.parameters.m_num_input_signals.value)), $(mask.parameters.m_input_bus_name.value))")
engee.set_param!(engee.gcb(), "OutputPort1BusType" => "BusSignal($(mask.parameters.m_output_signal_names.value), Tuple(fill(Float64, $(mask.parameters.m_num_output_signals.value))), ntuple(_ -> (), $(mask.parameters.m_num_output_signals.value)), $(mask.parameters.m_output_bus_name.value))")
В этом коде:
-
m_num_input_signals— количество входных сигналов; -
m_num_output_signals— количество выходных сигналов; -
m_input_signal_names— имена входных сигналов (например,(:a,:b,:c)); -
m_output_signal_names— имена выходных сигналов; -
m_input_bus_name— имя входной шины (Symbol, например,:InputBus); -
m_output_bus_name— имя выходной шины (Symbol, например,:OutputBus).
Значения m_input_bus_name и m_output_bus_name должны приходить в виде корректных литералов Julia Symbol, то есть с двоеточием: :InputBus, :MyHwIn, и т.д.
|
В коде устанавливается путь к текущему блоку с помощью функции gcb(), после чего считываются значения параметров маски m_input_signal_names, m_num_input_signals, m_output_signal_names, m_num_output_signals, а также m_input_bus_name и m_output_bus_name. Эти значения используются для формирования строкового представления типа BusSignal с заданными именами сигналов, базовыми типами (Float64), размерностями () и именем шины (четвертый аргумент типа Symbol). Чтобы значения считывались, имена параметров необходимо объявить в блоке Engee Function. Для этого перейдите в настройки блока оборудования и нажмите Посмотреть под маску, чтобы открыть параметры блока Engee Function. На вкладке Parameters указаны программные названия параметров из маски:

Затем функция engee.set_param! автоматически обновляет параметры Output bus type для Input port 1 (программное имя InputPort1BusType) и Output bus type (программное имя OutputPort1BusType) для Output port 1 на вкладке Ports, подставляя сгенерированные типы шин для входного и выходного портов:

Таким образом, вся настройка сводится к заполнению полей маски. Типы шин формируются автоматически, без ручного редактирования вкладки Ports. Это делает блок удобным, адаптивным и готовым к повторному использованию.