Operation with user buses BusSignal
in equipment blocks
Before usage of custom tyre types, it is recommended to read the blocks Bus Creator and Bus Selector. |
In Engee there is support for custom structured signals through the BusSignal
type (see here for details). This type allows to combine logically connected signals into a single structure - a bus, where each element has a name, type and dimension (e.g. temperature::Int
, position::Vector{Float64}
, status::Bool
).
Such structures are convenient when interacting with external hardware that returns or accepts entire sets of parameters. So, instead of passing data as an unstructured set:
(10, 3.2, [1, 2, 3])
you can use a bus with explicitly defined names:
(temperature = 10, pressure = 3.2, position = [1, 2, 3])
With the BusSignal
type such a structure can be accurately described and typed at model level, which is important for formalising the hardware data interface.
The BusSignal
type is written as follows:
BusSignal{Names, Types, Dimensions}
Where:
-
Names
- tuple of signal names ((:a, :b, :c)
); -
Names
- tuple of signal names ((:a, :b, :c)
);Types
- corresponding types (Tuple{Int, Float64, Vector{Float64}}
); -
Names
- tuple of signal names ((:a, :b, :c)
);Dimensions
- dimensions of each element), (), (3,
for scalars and vector of length 3).
Example of simple usage:
MyBus = BusSignal{(:a, :b), Tuple{Int, Float64}, ((), ())}
data = MyBus((a = 5, b = 6.4))
It is allowed to specify values both as a named tuple and as arguments in order:
MyBus(5, 6.4) # по позициям
MyBus(a = 5, b = 6.4) # по именам
Tyres can be nested, e.g.:
Inner = BusSignal{(:x, :y), Tuple{Int, Int}, ((), ())}
Outer = BusSignal{(:a, :b), Tuple{Float64, Inner}, ((), ())}
Functions are available to analyse the type:
get_bus_names(type) # Возвращает кортеж имен сигналов шины
get_bus_types(type) # Возвращает кортеж типов данных каждого сигнала
get_bus_dimensions(type) # Возвращает кортеж размерностей каждого сигнала
get_names_types_dims(type) # Возвращает три кортежа: имена, типы и размерности одновременно
get_bus_signal_type(value) # Определяет тип BusSignal по значению NamedTuple (автоматический вывод типа)
The function get_bus_signal_type
is particularly convenient: it allows you to automatically determine the bus type from a value, e.g.:
bus = (a = 5, b = [1.2, 3.4])
bus_type = get_bus_signal_type(bus)
# → BusSignal{(:a, :b), Tuple{Int64, Vector{Float64}}, ((), (2,))}
This functionality is actively used in equipment blocks. In order not to specify bus types manually, such blocks are configured with masks, an interface in which you only need to specify the names and number of signals.
Below we will consider how this scheme works: from mask parameters to automatic BusSignal
formation inside the equipment block.
User buses in equipment blocks
Let’s consider an example - dynamic formation of BusSignal
bus types in the UM Cosimulation equipment block. This block has the following parameters:
In order to automatically generate the bus types, it is only necessary to set the number and names of the input and output signals via a mask.
To do this, open the block mask (PCM on the block/Mask/View Mask), go to the tab "Code Editor" -> Global and in the callback blockChangedCallback enter the following code:
engee.set_param!(engee.gcb(), "InputPort1BusType" => "BusSignal{$(mask.parameters.m_input_signal_names.value), NTuple{$(mask.parameters.m_num_input_signals.value), Float64}, ntuple(_ -> (), $(mask.parameters.m_num_input_signals.value))}")
engee.set_param!(engee.gcb(), "OutputPort1BusType" => "BusSignal{$(mask.parameters.m_output_signal_names.value), NTuple{$(mask.parameters.m_num_output_signals.value), Float64}, ntuple(_ -> (), $(mask.parameters.m_num_output_signals.value))}")
In this code:
-
m_num_input_signals
- number of input signals; -
m_num_output_signals
- number of output signals; -
m_input_signal_names
- names of input signals; -
m_output_signal_names
- names of output signals.
In the code the path to the current block is set using the gcb()
function, after which the values of the mask parameters m_input_signal_names
, m_num_input_signals
, m_output_signal_names
and m_num_output_signals
are read. These values are used to form a string representation of type BusSignal
with given signal names, type Float64
and dimensions ()
. To read the values - the names of parameters must be declared in the block Engee Function. To do this, go to the settings of the equipment block and click Look Under Mask to open Engee Function. Then on the Parameters tab specify programme names of parameters from the mask:
The function engee.set_param! then automatically updates the parameters Output bus type (program name InputPort1BusType
) for Input port 1 and Output bus type (program name OutputPort1BusType
) for Output port 1 on the Ports tab, substituting the generated bus types for the input and output ports:
Thus, the whole configuration is reduced to filling in the mask fields. The busbar types are generated automatically, without manual editing of the Ports tab. This makes the block convenient, adaptive and ready for repeated usage.