提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
    
    
    前言
   
最近学习S-function封装,以下为学习过程中的总结。
一、代码封装
代码模板
     
   
选择User-Defined Functions –> S-Function Examples –>C-files –>sfuntmpl_basic.c
查阅函数的作用以及使用方法可通过官网查询,如下
    
     配置 C/C++ S-Function 功能 – MATLAB & Simulink – MathWorks 中国
    
   
    
     配置 C/C++ S-Function 功能- MATLAB & Simulink- MathWorks 中国
    
   
- 设置函数名称
#define S_FUNCTION_NAME  sfuntmpl_basic //这里修改函数名称
#define S_FUNCTION_LEVEL 2
2. 配置输入、输出、参数
static void mdlInitializeSizes(SimStruct *S)
{
//(1)参数配置
ssSetNumSFcnParams(S, 0); //设置参数个数  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        /* Return if number of expected != number of actual parameters */
        return;
    }
    ssSetNumContStates(S, 0); //指定 块具有的连续状态数
    ssSetNumDiscStates(S, 0); //指定 块具有的离散状态数
//(2)输入端口配置
if (!ssSetNumInputPorts(S, 1)) return;//配置输出端口个数
    ssSetInputPortWidth(S, 0, 1);//指定输入端口宽度
    ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/
    /*
     * Set direct feedthrough flag (1=yes, 0=no).
     * A port has direct feedthrough if the input is used in either
     * the mdlOutputs or mdlGetTimeOfNextVarHit functions.
     */
    ssSetInputPortDirectFeedThrough(S, 0, 1);
//(3)输出端口配置
    if (!ssSetNumOutputPorts(S, 1)) return;//配置输入端口个数
    ssSetOutputPortWidth(S, 0, 1);//指定输出端口宽度
    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);
    /* Specify the sim state compliance to be same as a built-in block */
    ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
    ssSetOptions(S, 0);
}
    
     
      3.指定此 C MEX S 函数运行的采样率
     
    
   
static void mdlInitializeSampleTimes(SimStruct *S)
    4.
    
     
      初始化 此 C MEX S 函数的状态向量
     
    
   
static void mdlStart(SimStruct *S)
    
     
      5.
     
    
    
     计算输出模块的输出信号
    
   
static void mdlOutputs(SimStruct *S, int_T tid)
{
//获取输入端口的指针/地址
const void *ssGetInputPortSignal(SimStruct *S, int_T inputPortIdx)
const real_T *u0 = (const real_T*) ssGetInputPortSignal(S,0);
//获取输出端口的指针/地址
void *ssGetOutputPortSignal(SimStruct *S, int_T port)
real_T       *y = ssGetOutputPortSignal(S,0);
//获取参数指针/地址
const mxArray *ssGetSFcnParam(SimStruct *S, int_T index)
    //获取参数1,double类型
    const real_T  *param1  = (const real_T *)mxGetData(ssGetSFcnParam(S, 0));
    double a = (double) *param1;
    //获取参数2,string类型
    const unsigned char  *param2  = (const unsigned char *)mxArrayToString(ssGetSFcnParam(S, 1));
    const int_T   p_width  = mxGetNumberOfElements(ssGetSFcnParam(S, 1));
    unsigned char *str = (unsigned char *)mxCalloc(p_width, sizeof(unsigned char));
    memcpy(str, param1, p_width);
}
    
     6.
    
    
     
      更新块的状态
     
    
   
static void mdlUpdate(SimStruct *S, int_T tid)
    7.
    
     
      计算 C MEX S 函数的导数
     
    
   
static void mdlDerivatives(SimStruct *S)
    8.
    
     
      执行仿真终止时所需的任何操作
     
    
   
static void mdlTerminate(SimStruct *S)- 代码编译
- 环境准备
查看matlab是否安装编译器MinGW-w64
mex -setup环境安装步骤
将TDM-GCC-64.zip 解压在C盘,注意路径不能有空格
配置环境变量
     
   
2.编译指令
mex filename -I./链接其他库的时候
mex filename -I./ -L./编译成功后会生成64位Windows版本的动态链接库
     
   
     
   
- 关联模型
- 编写m文件
修改slblocks.m文件
function blkStruct = slblocks
blkStruct.Name = ['add'];
blkStruct.OpenFcn = 'add;
blkStruct.MaskDisplay = '';
Browser(1).Library = 'add';
Browser(1).Name = 'add';
Browser(1).IsFlat = 0;
blkStruct.Browser = Browser;
- 
     
 打开Simulink,新建Model
 
    
     添加S-Function 模型
    
   
     
   
    如图 双击
    
     S-Function 模型 后,弹出 Block Parameter窗口 ,点击 Edit 后选择Browser 关联代码封装的 .c文件。
    
   
     
   
    
     S-Function name 填入S-function的函数名称,这样就建立了S-function模块与M文件形式的S-function之间的对应关系;
    
   
    
     S-Function parameters  填入S-function需要输入的外部参数的名称,如果有对各变量,则变量中间用逗号隔开,如a,b,c;
    
   
    
     S-Function modules  仅当S-function是用C语言编写并用MEX工具编译的C-MEX文件时,才需要填写该参数;
    
   
     
   
- Mask封装
    右键点击
    
     S-Function 模块,选中 Mask选项 –> Create Mask Editor 创建模板界面
    
   
     
   
     
   
lcon &Ports 页面填写模块界面输出
%参数显示
showInfo = sprintf('a: %s\nb: %s\nc: %s\n',get_param(gcb,'a'),get_param(gcb,'b'),get_param(gcb,'c'));
disp(showInfo);
%输入端口名称显示
port_label('input',1,'DataInput1');
%输出端口名称显示
port_label('output',1,'DataOutput1');
    
     Parameters & Dialog 界面
    
   
    
     设置和绑定参数控件
    
   
Initialization页面
可以添加参数初始化命令
Documentation 页面
可以添加模型说明
最后将模块的名称 S-Function更改;
效果如下:
     
   
- 将S-Function添加到simulink库中
将 模型复制和保存为Library 文件
     
   
设置路径
     
   
打开Simulink Library Browser库文件
右键选中 Refresh Library Browser 刷新界面然后就可以出来封装的模型。
     
   
 
