Engee 文档

恩吉的面具

面罩 - 是一个可定制的用户界面,用于创建自己的模块。可根据任何Engee 库子系统 块创建块。

面罩 Engee Block "简化了块的使用和重复使用。屏蔽块(带有覆盖屏蔽)有自己的设置窗口,可以在窗口中更改块的参数。通过掩码,您不仅可以将参数传递给程序块或子系统,还可以将参数传递给程序块*Engee Function* 和*C Function* 的源代码。

掩码允许

  • 创建自己的参数对话框,快速配置程序块/子系统;

  • 改变程序块/子系统的外观;

  • 隐藏程序块/子系统的内容。

例如,有一个信号发生器模型,由块*Switch,*Sine Wave,Pulse Generator,Constant 和*Out1* 组成:

mask subsystem example 2

利用子系统中的掩码,创建一个自定义模块,通过控制参数切换信号类型。掩码将值传递给 Constant 模块的常量参数,从而改变 Switch 模块中接收信号的类型。因此,模型会根据所选掩码值("矩形脉冲 "或 "正弦波")在*正弦波*和*脉冲发生器*信号之间切换。为方便起见,子系统的图标会显示所选信号的类型。

mask subsystem 1

掩码可以轻松配置,当其参数值发生变化时,程序块参数值也会自动改变。但是,不可能出现相反的效果:程序块参数值不能改变掩码参数值。这种限制可通过掩码控制块设置,并防止掩码本身发生意外更改。

掩码编辑器*是自定义掩码的工具。要打开编辑器,请右键单击程序块,然后选择 面罩 -> 添加面具

masks 1

编辑器会在新的浏览器窗口中打开:

mask editor 1

应用遮罩后,区块设置会显示遮罩的参数。要查看区块本身的参数,请单击 看看面具下面 。要返回,请单击 查看面具

masks switching 1

对于子系统, 看看面具下面 选项将带您进入子系统,而不是显示块参数。使用模型导航栏 退出子系统。

要编辑或删除掩码,请右键单击已创建掩码的程序块图标,然后选择 编辑掩码取下面具

masks main 1

遮罩编辑器界面

掩码编辑器包含两组选项卡:

  • *界面编辑器

  • *代码编辑器

界面编辑器

界面编辑器 - 在设置窗口中添加控件遮罩、结构元素和选项卡的部分。

mask editor 1 2

  1. 结构元素 - 用于放置和隐藏控件的容器: ..1.1. 隐藏部分 hidden section masks - 可通过点击隐藏或显示的容器,允许您同时控制多个元素的显示。

    隐藏部分 没有添加的控件将不会显示在遮罩中。默认部分可以重命名。
  2. 控件 - 主界面组件是块屏蔽的基础。每个控件都有三个参数:

    • 参数名称 - 必须与要定制的掩码中的变量名称相匹配;

    • 字段名称 - 将显示在设置窗口中;

    • 值或列表项—​定义默认值。

    除参数外,还可以配置属性:

    • 隐藏 - 隐藏控件;

    • 计算 - 分析输入值,解释输入值并存储适当的数据类型(如数字、字符串或数组)。如果输入的数据类型不合适,系统将产生错误。

.2.1. 输入字段 text input masks - 使用输入文本或数值添加掩码参数。数据类型:任意;

+

.2.2. 复选框 checkbox masks - 勾选复选框的区域。数据类型:Bool;

+ ..2.3. 下拉列表 dropdown masks - 显示可用选项列表,从中选择一个。要在下拉列表中添加项目,请在 List items 字段中逐个输入,并在每个值后按 Enter 键。数据类型:字符串;

+

不带参数的下拉列表会出错,并且不会保存掩码。
  1. 遮罩空间 - 使用控件和结构元素创建遮罩的区域。保存后,添加到该区域的所有元素都将准确地转移到遮罩中。要添加元素,请用鼠标拖放:

    masks drag and drop

    要删除项目,请选中该项目并按Delete

    要添加新标签,请按掩码空间右角的 +

    new tab mask

  2. 保存按钮—​保存掩码。也可以使用热键Ctrl+S (Win/Linux) 和+S (macOS)。

  3. 回调编辑器按钮 - 打开 代码编辑器

  4. 隐藏左窗格/显示左窗格。

  5. 隐藏右窗格/显示右窗格。

代码编辑器

代码编辑器 - 部分,用于使用回调函数(callbacks)自定义控件。每个控件都有自己独特的回调函数。

mask editor 1 3

  1. 屏蔽参数名称(可在界面编辑器中更改)。

  2. 字段名称 - 表示参数的标签或字段类型(可在界面编辑器中更改)。它更详细地说明了参数的目的或功能。

  3. 回调代码空间 - 为特定掩码参数设置回调的区域。

  4. 保存按钮 - 保存掩码。也可使用热键Ctrl+S (Win/Linux)和+S (macOS)。

  5. 隐藏左窗格/显示左窗格。

  6. 隐藏右窗格/显示右窗格。

回调

回调是针对特定操作自动调用的函数。在 Engee 中,回调函数是用Julia 语言编写的,在仿真过程中不执行,用于控制单个参数和整个掩码。局部回调用于控制单个参数,而全局回调用于控制整个掩码:

  • 全局回调(Global)-- 与整个掩码相关联,独立于特定参数执行。全局回调包括 iconDrawCallbackblockChangedCallback 。全局回调可访问所有本地回调并对其进行控制。例如,您可以将数据从本地回调传递到全局回调 blockChangedCallback 。这样,全局回调就可以用来定制本地回调的操作。

  • 本地回调与特定掩码参数绑定,只有当这些参数发生变化时才会触发。除 iconDrawCallbackblockChangedCallback 外,所有回调都是本地回调。本地回调只能在界面编辑器中使用与之绑定的参数,不能直接更改其他回调的参数( 复选框 不能控制下拉列表,全局回调用于此目的)。

要使用掩码参数,必须先获取该参数。为此,需要使用一个特殊的参数对象,该对象存储在 mask 变量中。例如,要获取名为 text_input_1 的参数 输入字段 text input masks ,可使用以下代码:

mask.parameters.text_input_1

参数对象有三个主要属性:

  • name::String - 字段名称(只读);

  • value::Any - 参数值(可读可写);

  • hidden::Bool - 参数的可见性(可读写)。

要更改参数,必须为 value 属性赋一个新值。不要直接修改现有值,因为这不会被视为更改。例如

  • 正确:

    mask.parameters.text_input_1.value = [1, 2, 3]
  • 不正确:

    append!(mask.parameters.text_input_1.value, 4)

gcb() "函数用于获取屏蔽区块的路径。路径以字符串形式返回。这样,你就可以用代码来控制区块及其内部组件。假设你想从参数 下拉列表 dropdown masks (dropdown_1) 传递一个值到内部块LDL Factorization

LDLPath = gcb() * "/LDL Factorization"
engee.set_param!(LDLPath, "NonPositive" => mask.parameters.dropdown_1.value)

在这里,gcb() 获取当前程序块的路径。在将 dropdown_1 中的值传递给模块的 NonPositive 参数后,路径将用于查找 LDL 因式分解模块。通过这种方式,gcb() 函数有助于将掩码参数与模型的其他部分联系起来。

engee.gcb()`和`engee.gcm()`方法不能在程序控制 内部的回调中使用。

回调概述

运行掩码回调的顺序:

  1. 每修改一个参数,就会调用 validateCallback .。首先执行,以确保在执行任何进一步操作前参数值有效;

  2. 每修改一个参数,都会调用 valueChangedCallback .。每次回调后,都会为每个新更改的参数调用 validateCallback ,因为更改值可能会影响其他参数;

  3. 启动 blockChangedCallback .对于每个新更改的参数, validateCallback 都会被调用; Starts .

  4. 启动 iconDrawCallback

了解回调的运行顺序对块掩码的正常工作非常重要,因为更改一个参数会影响其他参数。顺序不正确会导致值验证错误或图标更新错误。遵守正确的顺序可确保考虑到所有依赖关系,并确保程序块正常工作。


iconDrawCallback - 塑造设备外观

Details

要使用 iconDrawCallback ,必须使用`engee.show()`函数。带有错误 iconDrawCallback 的图标如下所示:

display callback 5

iconDrawCallback 可以显示文本、数字、图表、图片或公式(LaTeX)。例如

  • 数字输出(与文本类似):

    engee.show(text_input_1)

    display callback 1->display callback 2

  • SVG 输出:

    engee.show(
        svg"""
        <svg xmlns:ns0="http://www.w3.org/2000/svg" width="78%" height="80%" viewBox="0 0 26 27" fill="none">
            <path vector-effect="non-scaling-stroke" d="M13 0.5L13 25.7282" stroke="#DDDDDD" stroke-linecap="round" />
            <path vector-effect="non-scaling-stroke" d="M0.5 13H25.5" stroke="#DDDDDD" stroke-linecap="round" />
            <path vector-effect="non-scaling-stroke" d="M24.1894 8.46273L13 8.46273L13 17.4628L2.18942 17.4627" stroke="#212121" stroke-linecap="round" />
        </svg>
        """
    )

    custom block 1

    建议在区块中使用 SVG 图标,因为 SVG 图标占用空间较少,而且会自动调整到区块大小,不会降低质量。
  • LaTeX 公式输出。为此,请使用大写字母 和倒逗号`""`。公式按照经典的 LaTeX 语法写在引号中:

    engee.show(L"\lvert u \rvert")

    custom block 2

  • 图表输出:

    x = range(0, 2*pi, 1000);
    y = sin.(x);
    engee.show(plot(x, y))

    display callback 3

  • 图像输出:

    using Base64
    
    img = "...base64-text..."
    engee.show(Images.load(IOBuffer(base64decode(img))))

获取图片的 "base64 "表示法有多种方式:

  • 通过 Julia 脚本

    using Base64
    image_data = read("path_to_file")
    base64_encoded = base64encode(image_data)
    println(base64_encoded)
  • 通过命令行img 41 1 2 (通过点击; 预取进入 shell 模式):

    base64 --wrap 0 "path_to_file"
  • 通过外部服务,例如base64decode.org

您可以使用`engee.port_label()`函数通过回调机制更改区块端口签名。下面的示例展示了如何在区块图标上显示文本并为不同的端口设置签名:

engee.show("Some text")                 # Вывод текста на иконку блока
engee.port_label("input", 1, "foo_1")    # Подпись 'foo_1' для первого входного порта
engee.port_label("input", 2, "foo_2")    # Подпись 'foo_2' для второго входного порта
engee.port_label("output", 1, "bar")    # Подпись 'bar' для выходного порта

sum mask 1

还可以为非定向端口设置签名。您可以指定一个空名:

engee.port_label("acausal", 1, "")      # Пустое имя для ненаправленного порта

可以在端口签名中显示 SVG 文件和 LaTeX 公式:

engee.port_label("input", 1, svg="...")
engee.port_label("input", 1, L="...")

端口编号与软件控制相同。如果指定的端口号或类型不正确,功能将被忽略。

blockChangedCallback - 在更改任何掩码参数后执行

Details

在更改任何掩码参数时运行,但要在所有其他回调执行后。作为全局回调,它可以访问变量和掩码对象。

示例

  • 更改子系统中的参数:

    LDLPath = gcb() * "/LDL Factorization"
    
    mode = dropdown_1
    if mode == "Ignore"
        engee.set_param!(LDLPath, "NonPositive" => "Ignore")
    elseif mode == "Warning"
        engee.set_param!(LDLPath, "NonPositive" => "Warning")
    elseif mode == "Error"
        engee.set_param!(LDLPath, "NonPositive" => "Error")
    end

    这里掩码参数的值与 LDL 因式分解 块的参数同步。mode "是一个变量,用于存储 "ddropdown_1 "参数的当前值。例如,如果将下拉列表中的参数值从 "警告 "改为 "错误",子系统中的 LDL 因式分解 块中的同一参数也会发生类似变化。

valueChangedCallback - 在更改参数值时会执行

Details

valueChangedCallback 需要使用`gcb()`函数隐藏参数或更改子系统的状态。当链接参数的值发生变化时,将运行回调。如果相应控件的参数名称与回调代码一致,例如

valuechangedfcn callback 1->valuechangedfcn callback 2

示例

  • 隐藏参数

    mask.parameters.text_input_1.hidden = checkbox_1

    此处,当按下 复选框 时,参数被隐藏(hidden),当松开 复选框 时,参数被显示(visible)。

  • 更改子系统状态(使用程序控制功能):

    if checkbox
        mask.parameters.checkbox.hidden = false
        engee.add_block("/Basic/Ports & Subsystems/Model", gcb() * "/Model")
    else
        mask.parameters.checkbox.hidden = true
        engee.delete_block(gcb() * "/Model")
    end

    此处设置了与 复选框 (复选框_1)的链接,当开启时(复选框激活),会在子系统中添加*模型*块,而当关闭时(复选框未勾选),则会删除该块。

validateCallback - 检查参数值是否正确(验证)

Details

回调会检查 validateCallback 的值是否正确,如果值不正确,则会显示错误。除 AssertionError 外,所有错误信息都将被视为回调本身的错误,而不是输入数据的错误:

validatorcallback 1 1

validateCallback 总是以宏@assert 开始,使用 value 变量检查参数值的正确性。

validateCallback 仅适用于控件 输入字段 text input masks ,并与其回调 valueChangedCallback 绑定。

示例:

  • 检查数值的正确性:

    @assert value > 0 "Значение должно быть больше нуля"
  • 检查输入的类型

    @assert value isa Number "Значение должно быть числом"

例子

在使用掩码程序块(例如程序块3DOF (Body Axes) )时,必须考虑到掩码参数和工作区变量之间相互作用的特殊性:

  1. 某些屏蔽参数名称可能与工作区变量重叠。在这种情况下,掩码中的值将优先于工作区中的同名变量。

  2. 如果在工作区定义参数变量之前打开模型,掩码参数值可以重置为默认值。随后的变量声明不会自动更新掩码中的值。

  3. 屏蔽块参数的验证不在模型初始化阶段进行,而是在手动修改参数时进行。例如

    validateCallback
      @assert value isa Number "Значение должно быть 标量ом"
      @assert value isa Float64 "Значение должно иметь тип Float64"

如果使用了未知变量或参数包含无效值(如未声明变量或数据类型不合适),界面就会报错—​参数用红框突出显示,并附有解释:

mask debugger 1

将掩码参数传递给 C 功能块源代码_的示例
  1. Engee 工作区中放置 C Function 程序块。右键单击程序块,选择 面罩 -> 添加面具

  2. 在掩码界面编辑器中添加*输入字段*text input masks

  3. 转到掩码编辑器,在左侧参数菜单中选择参数 输入字段 (默认为 text_input_1)并将其移动到掩码空间。这样做两次,使 C 功能 块的每个参数都有自己的输入字段:

    blockchanged c function 4

  4. 在回调blockChangedCallback 中使用以下代码:

    # Установка пути к текущему блоку
    CFunctionPath = gcb()
    
    # Получение значений параметров масок
    param1 = text_input_1
    param2 = text_input_2
    
    # Формирование кода на Cи в зависимости от значений параметров
    c_code = """
    int add_numbers(int param1, int param2) {
        return param1 + param2;
    }
    int result = add_numbers($param1, $param2);
    """
    
    # Установка параметра "OutputCode" в блоке C Function
    engee.set_param!(CFunctionPath, "OutputCode" => c_code)

    blockchanged c function

    这段代码使用 gcb() 函数设置当前 C Function 块的路径,然后从 text_input_1text_input_2 中读取与 param1 和 param2 块参数相对应的值。然后创建一行 C 代码,定义 add_numbers 函数,将两个整数相加,并使用输入的值计算结果。engee.set_param!"用于更新 *C 功能*块的 "OutputCode "参数,设置生成的代码。

  5. 现在,在编辑掩码参数时,C Function 块的参数也会随之更改,更改后的值将包含在 OutputCode 选项卡中的源代码中:

blockchanged c function 1

blockchanged c function 3

对于 *C 功能*块的其他源代码标签--"StartCode "和 "TerminalCode",以及 *Engee 功能*块的标签--"ExeCode "和 "InhMethodsCode",也采用了类似的方法。

不仅可以使用数值,例如:

engee.set_param!(gcb(), "OutputCode"=>"print($text_input_1)")

为此,在掩码界面编辑器中创建或编辑参数时,必须指定一个数据类型随后将改变的值。如果数据类型不匹配,系统将显示错误:

error mask 1

确保选中 "计算 "复选框非常重要,因为这将允许掩码在保存后保留参数数据类型:

mask param save

将掩码参数传递给 Engee 函数_ 块源代码的示例。
  1. 如图所示,由块Sine WaveEngee FunctionTerminator 组成模型,并包括recordsignal logging 1 信号:

    engee function mask model 1

  2. Engee Function 块的源代码中,添加以下代码:

    engee function mask model 2

    struct Block <: AbstractCausalComponent end
    
    function (c::Block)(t::Real, x)
        return gain .* x
    end
  3. 点击 Engee Function 程序块,打开掩码编辑器,选择 面罩 -> 添加面具 。在掩码编辑器中添加 输入字段 text input masks ,命名增益参数并设置其值,例如 3:

    engee function mask model 3

  4. Engee Function 块参数中,设置增益参数,如图所示:

    engee function mask model 4

    通过这种方法,您可以使用程序块设置中的掩码参数值,将其添加到源代码中,并应用参数名称来获取指定值:

    engee function mask model 5

  5. 让我们通过运行模型模拟来测试这种方法:

    engee function mask model 6

  6. 增益参数的值确实是 3,这意味着掩码与 Engee Function 块的源代码配合得很好。

可定制子系统(模块 子系统)_ 示例

掩码可以叠加在区块之上Subsystem 。让我们考虑一下需要控制子系统块参数的情况。例如,块Sine Wave 的参数:

  • 默认情况下,子系统除了*作为原子单元*外没有其他参数:

    without mask 1

    转到子系统并为其添加一个*正弦波*单元。

  • 右键单击子系统图标,选择 面罩 -> 添加面具

  • 在掩码界面编辑器中添加 下拉列表 dropdown masks 。在列表中添加基于采样和基于时间的参数:

    sine wave mask example 2

  • 在掩码代码编辑器中,转到全局选项卡,在回调iconDrawCallback中添加以下代码:

    engee.show(dropdown_1)

    这段代码将在子系统图标上显示 dropdown_1 参数(下拉列表参数)的当前值。

  • 在回调blockChangedCallback 中使用以下代码:

    SinePath = gcb() * "/Sine Wave"
    
    mode = dropdown_1
    if mode == "Time based"
    engee.set_param!(SinePath, "SineType" => "Time based")
    elseif mode == "Sample based"
    engee.set_param!(SinePath, "SineType" => "Sample based")
    end

    这段代码将根据下拉菜单_1 掩码参数的值更改子系统中 Sine Wave 块的 "SineType "参数:如果选择 "Time based"(基于时间),则设置 "SineType"=>"Time based"(基于时间);如果选择 "Sample based"(基于采样),则设置 "SineType"=>"Sample based"(基于采样)。

通过更改屏蔽子系统中 Sine type 参数的值,Sine Wave 块中的该参数也会自动更改。

选择基于时间

选择基于采样

sine wave mask example 1

sine wave mask example 3 1

sine wave mask example 3

sine wave mask example 1 1

将掩码参数传递给图表_块的示例

掩码参数可以传递给图块Chart 。例如,如图所示,由图块ConstantSubsystemTo CSV 创建一个模型:

chart mask model 1

Chart 块添加到子系统中。要将其连接到子系统的输入 (In1) 和输出 (Out1),请打开 Chart 块,通过设置窗口debug article icon 1 创建输入) 和 (输出 端口。同时添加两个本地变量:

  • local_input 的值为 input

  • local_c 值为 c

这些变量将接收子系统掩码的值。

创建statestateflow state 后,为其命名,并使用局部变量、输入和输出写一个表达式。确保状态中变量的名称与 Chart 块设置中指定的名称一致。结果将是一个配置了输入、输出和变量的有限自动机模型:

chart mask model 6

现在,子系统内的模型将是这样的

chart mask model 4

使用遮罩为 Chart 块创建以下 输入字段 text input masks

chart mask model 5

使用导航栏 进入模型的顶层,并为*子系统*块创建一个掩码,内容如下: 输入字段 text input masks

chart mask model 2

运行模型start button 。模拟完成后,将在文件浏览器file browser 7 中创建一个 CSV 文件,显示随时间变化的模拟结果:

time,1
0.0,22.0
0.01,22.0
0.02,22.0
0.03,22.0
0.04,22.0
0.05,22.0
0.06,22.0
0.07,22.0
0.08,22.0
...
9.96,22.0
9.97,22.0
9.98,22.0
9.99,22.0
10.0,22.0

结果为`22`,这证实了*图表*块状态下表达式计算的正确性:local_c = c = 6(来自*子系统*掩码),local_input = input = 15(来自*图表*程序块掩码),它们的和等于`21`,*常数*程序块再加上`1`,得到最终值`22`。