处理不同维度的信号
矢量化和广播是使用*Engee*中的模型时的重要技术,可以有效地处理不同维度的信号。 使用矢量化,您可以完全对数组执行计算,避免显式元素循环,从而加快计算速度并简化代码。 反过来,Broadcast在执行操作时提供了数组之间的自动维度匹配,使您可以方便地使用不同格式的数据。
在建模中使用矢量化和广播可以有效地处理和分析多维数据。 矢量化通过处理整个数组来减少操作数量,广播消除了手动维度匹配的需要。
建模中的矢量化
建模中的矢量化允许您针对各种参数值立即评估模型的行为,这在灵敏度分析和测试中特别有用。 这意味着,您可以设置参数矩阵并在同一时间获取所有值的结果,而不是为每个值运行单独的运行。
例如,如果设置块的*Amplitude*参数 正弦波 值的矩阵`[[1, 2]; [3, 4]]`, 这意味着该块产生具有矩阵中指定的幅度的几个信号。 下图显示了*正弦波*块如何生成具有给定幅度的多个信号,这使您可以立即看到*幅度参数的不同值的结果。*:
广播
广播允许您协调数组的维度以对其执行操作。 在*Engee*中,这种机制会自动扩展数组的维度,允许在看似不兼容的数组上执行操作。 例如,如果一个数组的大小为"2x2",而另一个数组的大小为"1x2",那么当将数组加在一起时,数组将减少到兼容的尺寸。
考虑具有两个*Constant*块和一个*Add*块的示例。 带有参数的*Constant*块`[3, 4; 5, 6]` 它使用`[2,3]`参数添加到*Constant*块中。 与此同时,广播自动调整数组到兼容的大小,并执行元素添加.:
块的输出结果将是`[5, 7; 7, 9]`, 因为这些线是自动匹配的。 这种方法可以轻松地在不同大小的阵列之间执行操作,并大大简化了建模中多维信号的工作。
定制轮胎类型
在*Engee*中,支持由"BusSignal"类型表示的总线的自定义数据类型。 此类型允许您为处理类似数据的块设置总线结构。 命名元组(`NamedTuple')在*Engee*中用作总线对象,例如:
bus = (s1 = 4, s2 = 5.5, s3 = [1, 2, 3])
'BusSignal’类型由信号名称(Names
),基本类型(BaseTypes
)和尺寸(`Dims')参数化。 例如,三信号总线可以描述为:
bus_type = BusSignal{(:s1, :s2, :s3), Tuple{Int, Float64, Vector{Int}}, ((), (), (3,))}
这里:
-
:s1
,:s2
,`:s3’是信号的名称; -
'元组{Int, Float64, Vector{Int}}—-信号数据类型;
-
(), (), (3,)
— 信号的维度(例如,'s3’是长度为'3’的数组)。信号和总线的名称中允许使用引号( "
)以外的任何字符。
您可以通过函数创建总线对象,也可以将总线类型设置为要在块设置中使用的变量。 为了简化总线类型的使用,提供了提取名称、数据类型和维度的函数。:
get_names_types_dims(::Type{BusSignal{Names, Types, Dimensions}}) where {Names, Types, Dimensions}
get_bus_names(::Type{BusSignal{Names, Types, Dimensions}}) where {Names, Types, Dimensions}
get_bus_types(::Type{BusSignal{Names, Types, Dimensions}}) where {Names, Types, Dimensions}
get_bus_dimensions(::Type{BusSignal{Names, Types, Dimensions}}) where {Names, Types, Dimensions}
第一个函数允许您一次从总线类型中获取有关所有总线参数的信息,接下来的三个函数分别获取有关总线的名称,类型和尺寸的信息。
使用函数的示例
bus_type = BusSignal{(:s1, :s2, :s3), Tuple{Int64, Float64, Int8}, ((), (2,), (2, 2))}
# 此类总线的实例可能如下所示:(s1=5,s2=[4.3,5.4],s3=Int8[1 2;3 4])
get_names_types_dims(but_type) # 结果:((:s1,:s2,:s3),(Int64,Float64,Int8), ((), (2,), (2, 2))) - 一个由三个元组组成的元组,每个元组描述自己的总线类型参数
get_names(but_type) # 结果:(:s1,:s2,:s3)
get_types(but_type) # 结果:Tuple{Int64,Float64,Int8},即参数仍然以原始形式返回,有些不方便。 在下一个任务中,它将被修复,结果将是一个元组(Int64,Float64,Int8)
get_dimensions(but_type) # 结果如何?: ((), (2,), (2, 2))
例如,'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,), ())}
还支持嵌套结构,其中一个总线的元素可以是另一个总线(上面的示例)。 要指定嵌入式总线的类型,请在其元素的类型中指定嵌入式总线的完整类型。 |
尽管*Engee*中的总线对象被命名为元组,但为它们的创建提供了特殊的构造函数。 这些函数允许您创建轮胎对象,确保它们的结构与给定类型的轮胎相匹配。 以下选项可用于创建轮胎对象:
-
具有命名元组:
BusSignal{Names, Types, Dimensions}(x::NamedTuple{TupleNames, TupleTypes}) where {Names, Types, Dimensions, TupleNames, TupleTypes}
-
带有命名参数:
BusSignal{Names, Types, Dimensions}(kwargs...) where {Names, Types, Dimensions}
-
有一个规则的元组:
BusSignal{Names, Types, Dimensions}(x::Tuple) where {Names, Types, Dimensions}
创建总线对象的示例
考虑创建一个总线对象的类型:
bus_type = BusSignal{(:s1, :s2), Tuple{Int64, Float64}, ((), ())}
-
对于命名元组:
bus1 = bus_type((s1 = 5, s2 = 6.4))
这里传递了一个命名元组,其结构完全对应于类型`bus_type'。
-
对于命名参数:
bus2 = bus_type(s1 = 5, s2 = 6.4)
这里,总线结构是由命名参数创建的。 信号的名称('s1',`s2')及其类型必须与`bus_type’的定义匹配。
-
对于一个常规元组:
bus3 = bus_type(5, 6.4)
这里,参数按照`bus_type`类型定义的顺序传递。 参数的数量、类型和大小必须与总线参数匹配。
因此,在每个示例中,将创建相同类型的总线’bus_type'。 但是,应该考虑到:
-
对于"bus1"和"bus2",信号的名称、类型和大小与总线参数匹配。;
-
对于bus3,传递的参数的数量、类型和大小与总线类型要求相对应。
对于块,如 常数,可以通过参数*Output data types*指定总线类型的值,然后在*Output bus type*中设置其结构。
例如,设bus_value=(a=10,b=[2.5,3.5],c=(x=1,y=2))`。 然后它的类型设置为:
bus_type = BusSignal{(:a, :b, :c), Tuple{Int, Vector{Float64}, NamedTuple{(:x, :y), Tuple{Int, Int}}, (), (2,), ((), ())}}