在设备模块中使用用户总线 "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{Names, Types, Dimensions}
在哪里?
-
Names
- 信号名元组((:a, :b, :c)
); -
Names
- 信号名称元组((:a, :b, :c)
);Types
- 相应类型(Tuple{Int, Float64, Vector{Float64}}
); -
Names` - 信号名称元组(
(:a, :b, :c)
);Dimensions
- 每个元素的尺寸(), (), (3,
表示标量和长度为 3 的矢量)。
一个简单的使用示例:
MyBus = BusSignal{(:a, :b), Tuple{Int, Float64}, ((), ())}
data = MyBus((a = 5, b = 6.4))
允许以命名元组和参数的顺序指定值:
MyBus(5, 6.4) # по позициям
MyBus(a = 5, b = 6.4) # по именам
轮胎可以嵌套,例如
Inner = BusSignal{(:x, :y), Tuple{Int, Int}, ((), ())}
Outer = BusSignal{(:a, :b), Tuple{Float64, Inner}, ((), ())}
有分析类型的功能:
get_bus_names(type) # Возвращает кортеж имен сигналов шины
get_bus_types(type) # Возвращает кортеж типов данных каждого сигнала
get_bus_dimensions(type) # Возвращает кортеж размерностей каждого сигнала
get_names_types_dims(type) # Возвращает три кортежа: имена, типы и размерности одновременно
get_bus_signal_type(value) # Определяет тип BusSignal по значению NamedTuple (автоматический вывод типа)
函数`get_bus_signal_type`特别方便:它可以根据数值自动确定总线类型,如
bus = (a = 5, b = [1.2, 3.4])
bus_type = get_bus_signal_type(bus)
# → BusSignal{(:a, :b), Tuple{Int64, Vector{Float64}}, ((), (2,))}
下面我们将讨论该方案的工作原理:从掩码参数到设备块内自动形成的 "总线信号"。
设备模块中的用户总线
让我们来看一个例子—在 UM Cosimulation 设备模块中动态形成`BusSignal`总线类型。该模块的参数如下
为了自动生成总线类型,只需通过掩码设置输入和输出信号的数量和名称。
为此,请打开程序块掩码(程序块/掩码/视图掩码上的 PCM),进入 "代码编辑器" -> 全局选项卡,在回调blockChangedCallback 中输入以下代码:
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))}")
在此代码中
-
m_num_input_signals
- 输入信号的数量; -
m_num_output_signals` - 输出信号的数量;
-
m_input_signal_names
- 输入信号的名称; -
m_output_signal_names` - 输出信号名称。
代码使用 gcb()
函数设置当前程序块的路径,然后读取掩码参数 m_input_signal_names
、m_num_input_signals
、m_output_signal_names
和 m_num_output_signals`的值。这些值将被用来组成一个字符串表示类型为 `BusSignal
的信号,其中包含给定的信号名称、类型为 Float64
、维数为 ()
。要读取这些值,必须在程序块 功能 中声明参数名。为此,请进入设备块的设置,点击 看看面具下面 打开 功能 。然后在 Parameters 标签中指定掩码中参数的程序名称:
然后,函数engee.set_param! 会自动更新 Ports 选项卡上 Input 端口 1 的参数 Output bus type (程序名 InputPort1BusType
)和 Output 端口 1 的参数 Output bus type (程序名 OutputPort1BusType
),将生成的总线类型替换为输入和输出端口:
这样,整个配置过程就简化为填写掩码字段。母线类型自动生成,无需手动编辑*端口*选项卡。这使得该装置方便、适应性强并可重复使用。