跳到主要内容

S-Function 控制元件

本文档主要介绍自定义 S-Function 元件的创建和实现方法。为实现该功能,用户需提前准备封装好的二进制模型 .so 文件。本文档也将从白盒模型封装和黑盒模型封装两种实现方式介绍生成 .so 的具体步骤,并通过一个白盒模型实现的案例介绍 S-Function 元件的构建、调试方法。

功能定义

该功能支持将封装的二进制模型导入平台,构建自定义 S-Function 电磁暂态仿真元件。

功能说明

自定义 S-Function 元件具有以下几个功能特点:

  • 控制模型构建方便、高效,可降低模型搭建和参数校验的时间成本。

  • 控制策略与真实控制器的保持高度一致,仿真结果更接近实际情况。

  • 控制器开发者不需要公开具体的控制策略和核心算法,可满足保密需求。

适用模型

需提前准备 Linux 64 位系统环境下编译生成的 .so 文件。

编译来源可以有以下两种:

  1. MATLAB/Simulink 子系统编译生成 S-Function 时自动生成的代码文件。

  2. 用户自定义函数和接口的代码文件。

整体流程

自定义 S-Function 元件实现流程
自定义 S-Function 元件实现流程

用户可将 Simulink 白箱模型封装成 S-Function 子系统,利用 MATLAB 的自动代码生成功能,得到 *.c*.h 文件,在 Linux 环境中编译生成 .so 文件;也可以将包含自定义函数和接口的 .c.cpp.h 文件,或 .a 二进制文件,在 Linux 环境中编译生成 .so 文件。

用户需要获取 Simulink 子系统或自定义代码文件的全局参数输入/输出接口信息,并根据信息定义 S-Function 元件的参数和引脚,在平台导入 .so 文件,完成自定义 S-Function 元件的构建。

具体步骤

本文档根据白盒模型封装和黑盒模型封装两种方式介绍自定义 S-Function 元件实现的具体步骤。

若用户需要构建白盒模型的 S-Function 元件,.so 的编译来源为 MATLAB/Simulink 自动生成的代码,请参见白盒模型 S-Function 实现标签。

若用户需要构建黑盒模型的 S-Function 元件,.so 的编译来源为用户自定义的函数和接口代码,请参见黑盒模型 S-Function 实现标签。

  • a. 解算器设置

    模型设置为固定步长,解算器设置为 discrete,确保模型在当前设置下能正常运行。

    Simulink 模型参数配置
    Simulink 模型参数配置

    CloudPSS 中的系统均为离散系统,因此建议 S-Function 也使用离散解算器。

    注意

    若 S-Function 子系统中存在难以离散化的连续状态,也可选用连续积分解算器,目前支持的有 ode1、ode2、ode3、ode4、ode5 和 ode8,不同的积分方式会影响仿真结果准确度和仿真计算时间。

  • b. 子系统封装

    将控制模型封装为一个子系统。子系统中可以引用全局参数,若子系统的顶层有参数封装,并且希望这些参数在生成 S-Function 后可调,请将这些参数也通过全局参数定义,否则将被视为固定值而不可调。

    子系统参数封装
    子系统参数封装

    例如上图中,Parameter1Parameter2 分别用全局参数 ab 定义,则在生成 S-Function 后,这两个参数仍可在子系统顶层设置,而 Parameter3 为固定值 0,在生成 S-Function 时将以固定值写入。

    注意

    S-Function 参数必须以字母开头(不能是数字或下划线),目前仅支持 double 型,若是一个矩阵,在 CloudPSS 中对应表格型参数。

  • c. 生成 S-Function

    右键子系统,依次选择 C/C++ CodeGenerate S-Function 选项。

    子系统的 S-Function 编译
    子系统的 S-Function 编译
  • d. 设置 S-Function 参数

    勾选列出的全局参数中需要可调的,未勾选的参数将以固定值写入。

    勾选可调参数
    勾选可调参数
  • e. S-Function 自动代码生成

    自动代码生成,sfcn_rtw 文件夹中包含 *.c*.h 文件。

    S-Function 自动代码生成
    S-Function 自动代码生成
    提示

    若提示无编译器,则需下载并安装一个 MingGW64 编译器,流程可参考:https://zhuanlan.zhihu.com/p/359962279?ivk_sa=1024320u

    MATLAB 编译器安装与配置
    MATLAB 编译器安装与配置

步骤 2. 在 Linux 环境编译生成 .so 文件

  • a. 添加接口定义

    在步骤 1 生成的 sfcn_rtw 文件夹中找到以 S-Function 名称命名的 .c 文件,在 #include 之后添加如下接口定义并保存:

    #define ssSetInputPortVectorDimension(S, port, d)   \
    (ssSetInputPortWidth(S, port, d))
    #define ssSetOutputPortVectorDimension(S, port, d) \
    (ssSetOutputPortWidth(S, port, d))
    注意

    此函数定义是为识别 S-Function 的输入输出引脚,若每个输入输出引脚维数均为 1,则不用添加;若有引脚维数大于 1,则必须添加。

  • b. 运行编译指令

    sfcn_rtw 文件夹复制到 Linux 环境,在其路径下输入以下编译命令:

    gcc -Wall -DRT -DRT_MALLOC -fPIC -lm -shared *.c -o xxxx.so

    其中,xxxx 为用户自定义的 .so 文件名,与内部函数名(S-Function 名)无关。Linux 环境必须是 64 位系统。

    若出现缺少 *.h 头文件的报错,需要手动添加相应文件。不同版本的 MATLAB 所调用的头文件不同,获取路径可参考:

    安装路径\MATLAB\Rxxxxx\simulink\include
    安装路径\MATLAB\Rxxxxx\extern\include
    安装路径\MATLAB\Rxxxxx\rtw\c\src

    其中,xxxxx 为 MATLAB 版本。

步骤 3:根据全局参数和输入输出接口信息构建 S-Function 实现元件

  • a. 新建空白 S-Function 实现元件

    在工作台点击新建按钮,新建一个空白普通电力系统模型

    新建项目
    新建项目

    选择总览标签页,将模型类型切换为元件

    切换为元件类型
    切换为元件类型

    此时,在实现标签页中将出现拓扑、电磁暂态等子标签页。选中电磁暂态子标签页,点击创建电磁暂态 - S-Function 实现按钮,即可创建自定义 S-Function 元件。

    创建电磁暂态 - S-Function 实现
    创建电磁暂态 - S-Function 实现
  • b. 参数引脚列表定义

    选择接口标签页,在参数列表添加参数,在引脚列表添加引脚,并绘制元件图形。参数键名必须与 S-Function 引用的全局参数名一致;引脚键名不作要求,但顺序必须分别与 S-Function 的输入输出引脚对应。

    添加元件引脚并绘制图形
    添加元件引脚并绘制图形
  • c. 导入 .so 文件

    实现标签页导入步骤 2 生成的 .so 文件,并填写入口函数名

    导入 .so 文件并填写入口函数
    导入 .so 文件并填写入口函数
    注意

    入口函数名是 S-Function 名称,不是 .so 的文件名。

  • d. 元件名称与权限设置

    切换到总览标签页,输入元件的名称,并设置元件的权限元件标签

    元件名称与权限设置
    元件名称与权限设置

调试方法

在完成自定义 S-Function 元件的构建后,可以使用开环测试的方式,调试并验证元件的正确性。

步骤 1:获取 S-Function 正常运行时的输入数据

  • a. 添加示波器

    在 Simulink 中闭环运行原模型,使用示波器观测 S-Function 所有输入引脚。

    输入引脚处添加示波器
    输入引脚处添加示波器
  • b. 保存数据

    设置示波器保存数据到 MATLAB 工作区。

    示波器设置录波
    示波器设置录波

步骤 2:数据处理并导出为 .csv 格式文件

  • a. 数据处理

    在 MATLAB 中处理示波器保存的数据,将每一路引脚的数据按照第一列时间、第二列数据的方式另存。

    注意

    需要在每组数据的第一行添加一个索引号,第一列是 0,第二列是 1。将数据导入 CloudPSS 时,会根据索引号判断数据内容。

    数据格式处理
    数据格式处理
  • b. 导出 .csv

    使用 dlmwrite 命令将每路输入引脚的数据导出为 .csv 格式,命令参考如下:

    dlmwrite('input1.csv', input1, 'delimiter', ',', 'precision', 9);  
    注意

    为保证导出的 .csv 文件中数据的精度,请使用 dlmwrite 而不使用 csvwrite

步骤 3:利用自定义曲线元件导入 .csv 格式文件

  • a. 自定义曲线元件导入 .csv

    使用 CloudPSS 控制-非线性函数库中的自定义曲线元件,在元件参数面板的编辑数据中直接导入刚才生成的 .csv 文件。

    csv 数据导入
    csv 数据导入
  • b. 数据输入

    自定义曲线的输入是控制-基础库中的时间输入元件,输出连到 S-Function 元件的对应引脚。

    开环数据输入
    开环数据输入
  • c. 对比开环测试结果

    将 S-Function 元件的所有输入引脚都以 .csv 导入的形式输入数据。

    运行标签页中,配置电磁暂态仿真方案。

    电磁暂态仿真方案配置
    电磁暂态仿真方案配置

    设置与生成 S-Function 时固定步长相同的积分步长,并根据输入数据的长度,设置合适的仿真结束时间。

    运行仿真得到开环测试结果。

案例

本文档提供一个白盒模型 S-Function 实现的案例,展示自定义 S-Function 元件的创建和使用方法。

  • a. 封装白盒模型

    在 Simulink 中构建一个三相整流器模型,如下图所示。

    三相整流器 Simulink 模型
    三相整流器 Simulink 模型

    将控制部分封装成一个子系统,并命名为 Control 。子系统有 3 个输入,维数分别是 3、3、1,和 1 个输出,维数是 3。

    模型控制部分封装
    模型控制部分封装

    将子系统中的锁相环比例系数 Kp_PLL、锁相环积分系数 Ki_PLL、电压环比例系数 Kp_V、电压环积分系数 Ki_V、电流环比例系数 Kp_I、电流环积分系数 Ki_I、直流电压参考值 Vdc_ref 和交流滤波电感值 Lf 定义为全局参数,并在模型初始化页面赋值。

    定义全局参数
    定义全局参数

    也可以对子系统进行参数封装后再引用全局参数。若封装后的参数未使用全局参数,将作为固定值写入 S-Function,不可调。

    子系统参数封装后引用全局参数
    子系统参数封装后引用全局参数

    本案例中的解算器设置如下图所示,固定步长 50 us,采用 ode1 积分方式(欧拉积分)。

    运行仿真,确认当前设置下模型无报错。

    模型参数配置
    模型参数配置
  • b. 自动代码生成

    右键子系统,选择 C/C++ Code,点击 Generate S-Function,在弹出的对话框中勾选可调参数,点击 Build,开始自动生成代码并编译 S-Function。

    生成S-Function
    生成S-Function

    编译成功后,会弹出封装好的 S-Function 模块,以及自动生成的包含 *.c*.h 文件的 sfcn_rtw 文件夹。

    S-Function 编译成功
    S-Function 编译成功
  • c. 编译生成 .so

    打开 sfcn_rtw 文件夹中的 Control_sf.c 文件,添加接口函数定义。由于引脚维数不为 1,此步骤不可省略。

    添加接口函数定义
    添加接口函数定义

    在 MATLAB 安装路径的 simulink\includeextern\include 文件夹中,将所需 *.h 头文件复制到 sfcn_rtw 文件夹。

    添加头文件
    添加头文件

    将整个 sfcn_rtw 文件夹复制到 64 位 Linux 系统。

    进入 Linux 编译环境
    进入 Linux 编译环境

    在路径下输入命令:

    gcc -Wall -DRT -DRT_MALLOC -fPIC -lm -shared *.c -o Control.so

    完成编译。

    编译代码
    编译代码

    编译成功后,会在路径下生成 .so 文件,将 .so 文件复制到本地。

    编译成功
    编译成功
  • d. 构建自定义 S-Function 元件

    在 CloudPSS 平台新建自定义 S-Function 元件。在工作台点击新建按钮,新建一个空白普通电力系统模型

    新建项目
    新建项目

    选择总览标签页,将模型类型切换为元件

    切换为元件类型
    切换为元件类型

    切换到实现标签页,选中电磁暂态子标签页,点击创建电磁暂态 - S-Function 实现按钮。

    创建电磁暂态 - S-Function 实现
    创建电磁暂态 - S-Function 实现

    接口标签页的参数列表定义栏,新建参数组,并添加参数,参数键名与 S-Function 的可调参数名一致,参数类型设为实数,输入类型为常量,默认值可与 Simulink 模型初始化页面的赋值一致。

    在引脚列表定义栏,添加 input1input2input3output1 引脚,按照对应的数据维数连接类型设置。

    在参数和引脚定义好后,可点击元件图形设计窗口右上角的直接导入按钮,根据引脚类型和数量生成一个默认图形,在默认图形基础上自定义元件图形。

    添加元件参数和引脚并绘制图形
    添加元件参数和引脚并绘制图形

    实现标签页,导入 .so 文件,填写入口函数名。注意,入口函数名不是 .so 文件的名称,而是 S-Function 的名称,本案例中是 Control_sf

    导入 .so 文件并填写入口函数
    导入 .so 文件并填写入口函数
  • e. 开环测试

    在 Simulink 模型的 S-Function 输入引脚处添加示波器,并设置录波。

    闭环数据录波
    闭环数据录波

    运行仿真,整理录波数据,将每一路输入引脚处理成第一列时间、第二列数据,并在第一行添加索引。

    数据整理
    数据整理

    使用 dlmwrite 命令将整理后的数据导出为 .csv 文件。

    导出csv文件
    导出csv文件

    在 CloudPSS 平台利用自定义曲线元件导入每一路输入引脚的数据,导入成功后如下图所示。

    导入数据
    导入数据

    完成所有输入引脚的数据导入后,开环测试模型如下图所示。

    开环测试模型
    开环测试模型

    运行仿真,对比 CloudPSS 与 Simulink 的开环测试结果,验证所构建的 S-Function 元件的正确性。

    开环测试结果对比(output1 A 相)
    开环测试结果对比(output1 A 相)
  • f. 构建电气系统模型,完成闭环测试

    搭建三相整流器的电气系统模型,并添加构建好的 S-Function 控制元件,S-Function 元件的输入引脚连接量测信号,运行仿真完成闭环测试。

    三相整流器 S-Function 闭环模型
    三相整流器 S-Function 闭环模型

    闭环测试结果如下图所示。

    闭环测试结果对比(直流电压)
    闭环测试结果对比(直流电压)
    闭环测试结果对比(交流电流 A 相)
    闭环测试结果对比(交流电流 A 相)

三相整流器控制的 S-Function 实现 算例文件下载:model_admin_MicroGrid_Rectifier_S_Function_withpara.zip

常见问题

如何设置控制器的采样步长?

S-Function 封装的采样步长固定为生成 S-Function 时控制器子系统的采样步长。在某些应用场景,控制器的采样步长可能与仿真步长不一致。Simulink 中,要求控制器采样步长为仿真步长的整数倍,如仿真步长为 10 us,而控制器以 50 us(仿真步长的 5 倍)进行采样和计算。

CloudPSS 中内置了采样倍率参数来应对这种情况。用户可根据控制器需求选择是否添加这个参数,当不添加这个参数时,其值默认为 1,即控制器采样步长与仿真步长一致。

该参数键名为:__SFUNC_STEP,添加方法如下:

添加控制器采样倍率参数
添加控制器采样倍率参数
注意

参数以两个下划线开头。为避免系统识别错误,用户自定义的其它全局参数名只能以字母开头,不能以数字或下划线开头。

如何选择控制器求解的积分方式?

针对 Simulink 中不同阶数的连续积分解算器,CloudPSS 进行了适配,目前支持的有 ode1、ode2、ode3、ode4、ode5 和 ode8。

支持的 Simulink 连续积分解算器
支持的 Simulink 连续积分解算器

在 CloudPSS 中,内置了定义解算器类型的参数,参数键名为:__SFUNC_SOLVER,参数值为与目标解算器类型同名的字符串。例如,可将该参数定义为选择型参数,其键值分别为 ode1、ode2、ode3、ode4、ode5 和 ode8。

添加解算器类型参数
添加解算器类型参数

当模型中不存在连续积分时,解算器默认为离散解算器 discrete,该参数的设置无效;当模型中存在连续积分时,该参数值默认为 ode3

如何输入矩阵类型的参数?

若 S-Function 的全局参数是一个矩阵,在 CloudPSS 中,需要用表格型参数与之对应。

例如,全局参数 a 是一个 1×3 的矩阵,其值为 [1, 2, 3]。在 CloudPSS 中构建自定义 S-Function 元件时,添加一个表格型参数,在列定义选项中新建 1 个列定义,在默认值选项中添加 3 行,并分别设置为 1、2、3,如下图所示。

表格型参数定义矩阵
表格型参数定义矩阵

在元件参数面板设置或修改表格型参数时,也可以点击参数框右侧的 (x) 按钮切换为表达式输入形式,再输入 [1, 2, 3],完成数据编辑。

表达式输入形式编辑参数数据
表达式输入形式编辑参数数据

若全局参数 a 是一个 3×3 的矩阵,其值为 [1, 2, 3; 4, 5, 6; 7, 8, 9],则在 CloudPSS 中,按照先行后列的顺序,填入所有矩阵元素。例如,将表格型参数切换为表达式输入形式,再输入 [1, 2, 3, 4, 5, 6, 7, 8, 9]。