Документация Engee
Notebook

Использование блоков Variant Source и Variant Sink

В этом примере мы покажем работу блоков Variant Source и Variant Sink. Эти блоки позволяют переключаться между разными реализациями моделей, являющимися генераторами входных данных или потребителями выходных данных некоторой подсистемы.

Введение

Предположим, вам нужно просчитать работу модели с разными входными датчиками, разными циклограммами или различными алгоритмами фильтрации данных на выходе. Для такого тестирования можно собрать несколько отдельных моделей, число которых быстро станет непрактично большим. Или можно собрать все модели в одну и переключать условия при помощи переменных.

В этом упрощенном примере конфигурация модели будет задана двумя скалярными переменными:

In [ ]:
V = 1;
W = 1;

В модели есть несколько переключателей сигнальных линий, управляемых внешними переменными.

image.png

Условия выбора сигнала в каждом блоке Variant Source или Variant Sink заданы при помощи выражений.

Выражение, которое первым принимает истинное значение, определяет номер порта, по которому пойдут данные от или к некоторой подсистеме. Проинтерпретируем разные варианты систем, которые реализованы на этой схеме:

  • Если W==1 является истинным выражением то Variant Source1 активирует вход Sine3, а при V==4 активируется вход Sine4.
  • При V==1 блок Variant Source 2 пропускает сигнал от блока Sine1, а при V==2 – сигнал от блока Add1.
  • Если блок Add1 неактивен, то Variant Source 1 тоже будет неактивным, и тогда будут отключены блоки Sine3 и Sine4 (блок Sine3 активен при V==2 && W==1, а блок Sine4 активен при V==2 && W==2).
  • Юлок Gain3 активен либо при V==1, либо при V==2; при других условиях (например при V=4) мы получим ошибку, потому что на выходной порт Out1 не будет подано никакого выходного сигнала.
  • Блоки на выходе Variant Sink1 становятся активными при W==1 (Gain5) либо при W==2 (Gain2, Substract, Terminator).
  • Наконец, блоки Sine6, Sum и Out2 всегда активны, на них не распространяются условия по выбору вариантов системы. Чтобы эти блоки выполнялись только при некоторых условиях, можно поставить перед и после них блоки 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]:

Заключение

Мы убедились в том, что на одном холсте можно собрать несколько вариантов системы. Этот метод упрощает тестирование и позволяет генерировать сразу много вариантов кода для еще большей автоматизации полунатурного моделирования.

Блоки, использованные в примере