Engee 文档
Notebook

使用变量源和变量汇块

在本示例中,我们将展示块Variant SourceVariant Sink 的工作。通过这些区块,您可以在作为输入数据生成器或子系统输出数据消费者的模型的不同实 现方式之间进行切换。

导言

假设您需要计算一个模型在使用不同输入传感器、不同循环图或不同输出数据过滤算法时的性能。为了进行此类测试,您可以建立多个单独的模型,但这些模型的数量很快就会变得非常庞大。或者,您可以将所有模型合并为一个模型,然后使用变量切换条件。

在这个简化示例中,模型配置将由两个标量变量指定:

In [ ]:
Pkg.add(["Combinatorics"])
In [ ]:
V = 1;
W = 1;

该模型有多个由外部变量控制的信号线开关。

image.png

Variant SourceVariant Sink 中的信号选择条件是通过表达式指定的。

首先取真值的表达式决定了数据从哪个子系统流出或流向哪个子系统的端口号。让我们来解释一下本图中实现的系统的不同变体:

  • 如果W==1 为真表达式,则Variant Source1 激活输入端Sine3 ,在V==4 激活输入端Sine4
  • 如果V==1Variant Source 2 跳过来自Sine1 块的信号,如果V==2 跳过来自Add1 块的信号。
  • 如果Add1 块处于非激活状态,Variant Source 1 也将处于非激活状态,然后Sine3Sine4 块将被禁用(Sine3 块在V==2 && W==1 处处于激活状态,而Sine4 块在V==2 && W==2 处处于激活状态)。 Gain3 块在V==1V==2 处处于激活状态;在其他条件下(例如在V=4*),我们将收到错误信息,因为没有输出信号提供给输出端口Out1
  • 输出端Variant Sink1 上的程序块在W==1 (Gain5)W==2 (Gain2, Substract, Terminator) 上处于激活状态。
  • 最后,程序块Sine6SumOut2 始终处于活动状态,不受系统选项条件的限制。为确保这些程序块只在特定条件下执行,可以在它们之前或之后使用具有单一输入和输出的程序块Variant Source/Sink

在某些条件组合下,该模型会返回错误,因为无论子系统选项如何,子系统的输出端口都 必须接收有效信号。任何模块都不可能同时提供有源和无源信号,因此必须使用Variant Source/Sink 模块设置默认值,明确设计此类系统的输出端口。

运行方案

In [ ]:
mName = "variant_source_sink"
model = mName in [m.name for m in engee.get_all_models()] ? engee.open( mName ) : engee.load( "$(@__DIR__)/$(mName).engee" );
data = engee.run( mName )
Out[0]:
Dict{String, DataFrames.DataFrame} with 1 entry:
  "Gain3.1" => 51×2 DataFrame
In [ ]:
plot( data["Gain3.1"].time, data["Gain3.1"].value )
Out[0]:

运行多个情景

现在,我们循环运行模型的多个变体,切换状态变量,以显示系统在不同情景下使用输入条件组合时的表现。

In [ ]:
using Combinatorics
In [ ]:
# Зададим все интересующие нас входные условия
vV = [1,2,4];
vW = [1,2,4];

# Загрузим модель
mName = "variant_source_sink"
model = mName in [m.name for m in engee.get_all_models()] ? engee.open( mName ) : engee.load( "$(@__DIR__)/$(mName).engee" );

# Успех выполнения мы будем хранить в матрице, которую инициализируем пропущенными значениями
run_success = NaN .* zeros(length(vV), length(vW))

# Пройдемся по всем комбинациям входных условий и проверим, выполнится ли модель
for c in combinations( vcat( vV,vW ), 2  )
    V,W = c[1],c[2]
    i = findfirst( vV.==c[1] )
    j = findfirst( vW.==c[2] )
    
    try
        # Запустим модель на выполнение
        data = engee.run( mName )
    catch e
        # Если модель выполнилась с ошибкой, запишем 0 в выходную матрицу
        run_success[i,j] = 0
    else
        # Запишем единицу только если условие catch не сработало
        run_success[i,j] = 1
    end

end

我们将绘制一张图表,显示模型不同变体运行的统计数据。

In [ ]:
gr()
# Вывод не интерактивной карты, отражающей успех выполнения модели
heatmap( run_success, xticks=(range(1,length(vV)), vV), yticks=(range(1,length(vW)), vW),
         xlabel = 'V', ylabel='W', title="Успех выполнения модели", yflip = true, cbar=false, c=:Blues )
# Аннотация поверх каждой ячейки
annotate!( vec(tuple.((1:length(vV))', (1:length(vW)), string.(Int32.(run_success)))) )
Out[0]:

结论

我们已经看到,在一张画布上构建一个系统的多个变体是可能的。这种方法简化了测试,并允许一次生成多个代码变体,从而进一步实现半自然建模的自动化。