⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s_function_ch.c

📁 matlab中simulink中用C语言编写S函数模板的翻译版本
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * 文件名: sfuntmpl_doc.c
 * 摘要: ...
 * Copyright 1990-2002 The MathWorks, Inc.
 * 版本: 1.50.4.1 $
 */
// 第一段用来说明函数的内容,包括函数文件名以及大致内容 
 

/*
 * You must specify the S_FUNCTION_NAME as the name of your S-function.
 */

#define S_FUNCTION_NAME  your_sfunction_name_here
#define S_FUNCTION_LEVEL 2
// 第二段中包括函数名称的定义以及级别的控制

/* 
 *  需要包括simstrc.h用来定义SimStruct和它相关的宏定义
 * 
 * 以下几个头文件在被编译成MEX文件时被matlabroot/simulink/include/simstruc.h调用
 * 
 * matlabroot/extern/include/tmwtype.h    - 普通类型,如real_T
 *  matlabroot/extern/include/mex.h         - MATLAB MEX 文件 API 程序api  API(Application Programming Interface,应用程序编程接口)
 *  matlabroot/extern/include/matrix.h      - MATLAB MEX 文件 API 程序
 * 
 * 以下几个头文件在用RTW编译时被matlabroot/simulink/include/simstruc.h调用
 * 
 *  matlabroot/extern/include/tmwtypes.h    - 普通类型,如real_T
 *  matlabroot/rtw/c/libsrc/rt_matrx.h      -  MATLAB API 程序 宏定义
 */

#include "simstruc.h"



/*  错误处理
 *  -------------
 *  采用以下技术报告在s-function碰到的错误
 *       ssSetErrorStatus(S,"error encountered due to ...");
 *       return;       
 *   
 *  注意ssSetErrorStatus中第二个参数必须是存在于静态存储区内。
 *  它不能是程序中的一个局部变量。例如下列程序导致不可预测的错误
 *
 *      mdlOutputs()
 *      {
 *         char msg[256];         {非法: 修正为 "static char msg[256];"}
 *         sprintf(msg,"Error due to %s", string);
 *         ssSetErrorStatus(S,msg);
 *         return;
 *      }
 *
 *  ssSetErrorStatus错误处理机制是mexErrMsgTxt函数的替代物。mexErrMsgTxt
 *  利用"异常处理"立即中止S-function的运行并返回simulink控制权。为了在S-function
 *  支持异常处理机制 。Simulink必须设置每个S-function的异常处理优先级
 *  给仿真带来了额外的开销。
 *  
 *  如果不调用mexErrMsgTxt或者其他可能导致异常发生的程序,应该采用SS_OPTION_EXCEPTION_FREE_CODE
 *  选项。这个功能选择在紧跟的命令中在mdlInitializeSizes函数体内完成。
 *         ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
 *
 *  设置该选项,将提高S-function的性能,Simulink将跳过异常处理设置。应该特别留意修改代码当
 *  通过设置SS_OPTION_EXCEPTION_FREE_CODE不在使用异常处理时。如果此时S-function产生异常,不可预测的结果将发生
 *
 *  异常取消的代码是指从不"long jumps"代码也就是远跳转的。如果它包括有任何调用可能产生"long jumps"的代码,
 *  那么S-function不是异常取消的代码。例如调用mexErrMsgTxt时抛出异常,将结束S-function的执行。
 *  使用mxCalloc可能导致不可预测的问题。当memory分配产生错误将产生远跳转。如果需要分配内存,
 *  应该直接使用stdlib.h calloc程序并且执行自己的错误处理函数。
 *
 *  所有的mex程序都有远距离跳转的可能性(或者产生异常)。例外集中mx程序也有产生远距离跳转的可能性。
 *  为了避免复杂度太高,只有获取指针和确定参数个数的程序可以被使用。例如以下几者永远不会抛出异常
 *  :mxGetPr, mxGetData,mxGetNumberOfDimensions, mxGetM, mxGetN, mxGetNumberOfElements.
 *  
 *  如果你的实时方法中不含有可能产生异常的代码,你可以使用下面的选项
 *    ssSetOptions(S, SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE); 
 * 另外一些方法在S-function是有可能产生异常的代码,包括以下几种方式
 *   mdlGetTimeOfNextVarHit, mdlOutputs, mdlUpdate, and mdlDerivatives
 *
 * 警告&打印字符串
 * -------
 * 使用ssWarning(S,msg)显示警告
 * -当S-function在Simulink中编译为mex时,ssWarning等效于ssWarning
 *  —当S-function在Real-Time Workshop时,ssWarning等效于
 *    printf("Warning: in block '%s', '%s'\n", ssGetPath(S),msg);
 * 如果目标有标准输入和输出设备。否则它会变为一个注释并且不在执行
 * 
 * 使用ssPrintf(fmt, ...)打印一条信息
 * -当S-function在Simulink中编译为mex时,ssPrintf 等效于 mexPrintf。
 * -在S-function在Real-Time Workshop中使用时,如果有标准输入和输出设备时,ssPrintf等效于printf,
 *  否则变为调用一个空函数(rtPrintfNoOp)。
 * -在Real-Time Workshop时可能有也可能没有标准输入和输出设备,产生最有效率的代码使用
 *        #if defined(SS_STDIO_AVAILABLE)
 *              ssPrintf("my message ...")
 *        #endif
 *  —可以使用该种技术做相关的标准I/O相关的工作
 *   例如:
 *    #if defined(SS_STDIO_AVAILABLE)
 *            if ((fp=fopen(file,"w"))==NULL)
 *          { 
 *           ssSetErrorStatus(S,"open failed");
 *            return ;}
 *             ...
 *       #endif
 */
 

 /*===================*
 * S-function方法   *
 *====================*/

/* 
 * Level 2 S-function 方法
 *  --------------------------
 *     注意: "=>"表示方法是必须的
 *      [method]表明该方法是可选的
 *   注意,很多以下的方法只有在level 2 C-MEX S-functions环境下才能使用
 *
 * Simulink初始化模型
 * ---------
 * => mdlInitializeSizes           - 初始化 SimStruct 大小向量
 *   [mdlSetInputPortFrameData]   -可选的方法。检查并设置输入、输出数据的frame类型
 * 
 *    注意:在一个S-function中不能同时使用mdlSetInput(Output)PortWidth和mdlSetInput(Output)PortDimensionInfo。
 *    单独使用宽度和维度都是可以的,但同时使用是不可以的
 * 
 *     [mdlSetInputPortWidth]       -可选的方法。
 *                                          检查并设置输入的端口宽度
 *       [mdlSetOutputPortWidth]    -  可选的方法。 
 *                                    检查并设置输出的端口宽度
 *
 *       [mdlSetInputPortDimensionInfo]
 *                              -  可选的方法。
 *                                 检查并设置输入的端口维度 
 *       [mdlSetOutputPortDimensionInfo]    
 *                              -  可选的方法.
 *                                  检查并设置输出的端口维度
 *       [mdlSetDefaultPortDimensionInfo]    -可选的方法,设置所有未知纬度输入和输出端口的纬度
 *       [mdlSetInputPortSampleTime]         -可选的方法,检查设置输入端口的采样时间
 *       [mdlSetOutputPortSampleTime]        -可选的方法,检查设置输出端口的采样时间
 *  =>mdlInitializeSampleTimes       -初始采样时间和任意设置function-call连接
 *  
 *    [mdlSetInputPortDataType]   -可选的方法,检查设置输入端口的数据类型。察看SS_DOUBLE到SS_BOOEAN
 *                                 ,其在simstruc_type.h中内置的类型
 *    [mdlSetOutputPortDataType]  -可选的方法,检查设置输出端口的数据类型。察看SS_DOUBLE到SS_BOOEAN
 *                                 ,其在simstruc_type.h中内置的类型
 *    [mdlSetDefaultPortDataTypes]  -可选的方法,设置所有动态输入和输出的端口数据类型
 *
 *    [mdlInputPortComplexSignal]   -可选的方法,检查和设置输入端口的复数类型(COMPLEX_YES,COMPLEX_NO)
 *    [mdlOutputPortComplexSignal]   -可选的方法,检查和设置输出端口的复数类型(COMPLEX_YES,COMPLEX_NO)
 *    [mdlSetDefaultPortComplexSignals]   -可选的方法,设置所有动态复数类型COMPLEX_INHERITED输入和输出端口的复信号标志。
 *   
 *    [mdlSetWorkWidths]  -可选的方法,设置state,iwork,rwork, pwork, dwork等尺度。
 *
 *    [mdlStart]        -可选的方法,执行像分配内存和存放pwork的动作
 *    
 *    [mdlInitializeConditions]   -初始模型的参数(通常的状态)。如果S-function没有初始情况方法时,将不会调用。
 *   
 *    ['constant' mdlOutputs]     -在一个常数的时间执行该模块,它将执行一次
 *
 *   Simulink模型仿真循环 
 *   _______________________
 *    [mdlCheckParameters]        -可选项,在仿真中当参数改变时调用
 *    
 *   仿真循环SimulationLoop:
 *        [mdlProcessParameters]   -可选项,仿真中如果参数改变并且mdlCheckParameters验证通过后
 *                                    调用。该过程在仿真循环中最开始执行。
 *        [mdlGetTimeOfNextVarHit]  -可选项,如果S-function有可变的采样时间,这个方法就会被调用。
 *         
 *        [mdlInitializeConditions]  -可选项,如果S-function在一个使能子系统,并且有重置状态,并且子系统刚被使能时
 *                                     才调用
 *
 *    =>   mdlOutputs               -主要是输出函数的调用(通常是更新输出信号)
 *             [mdlUpdate]           -更新离散状态等
 *
 *         综合Integration(主要时间步骤)
 *          [mdlDerivatives]        -计算导数,或者说偏差
 *          DO
 *             [mdlOutputs]
 *             [mdlDerivatives]        
 *          EndDo           -迭代次数跟solver解算机有关
 *          Do 
 *            [mdlOutputs]
 *            [mdlZeroCrossings]
 *          EndDo             -迭代次数跟零相交信号有关
 *       EndIntegration  
 *     EndSimulationLoop
 *   => mdlTerminate    -释放模型占用的资源 -释放内存等
 *  
 *  模型在代码产生时的初始化(rtwgen=real time shop?)
 *  ----------------------------------------
 *     <Initialization. 查看上述 "Model Initialization in Simulink" >
 *     [mdlRTW]      -可选项。仅在Real-Time Workshop中添加信息到model.rtw文件时产生代码时调用
 *    
 *     mdlTerminate    -释放模型占用的资源 -释放内存等
 *  
 *   在Real-Time Workshop中非嵌入式的S-function执行过程
 *   --------------------------
 *   1) 绝大部分的初始化方法结果被编译到生成的代码中并且很多的方法没有被调用
 *   2) 非嵌入式的S-function在以下几个方面受到限制。例如,参数必须是实复数向量或者字符串,
 *       更多的能力由目标语言编译器提供。查看目标语言编译器使用指导
 *
 * => mdlInitializeSizes    -初始SimStruct尺寸数组
 * => mdlInitializeSampleTimes -初始化采样时间和任意设置调用函数连接
 *    [mdlInitializeConditions]  -初始化模型参数(常用的状态),如果没有初始方法将不会调用
 *     [mdlStart]               -可选的方法,执行分配内存和分配pwork元素的赋值
 *
 *   执行循环ExecutionLoop:
 *     => mdlOutputs            -  主要的output调用(通常是更新输出信号)
 *        [mdlUpdate]           - 更新离散状态
 *      
 *     Integration (Minor time step)
 *          [mdlDerivatives]         -  计算导数
 *          Do
 *            [mdlOutputs]
 *            [mdlDerivatives]
 *          EndDo - 迭代取决于solver解算机
 *          Do 
 *            [mdlOutputs]
 *            [mdlZeroCrossings]
 *          EndDo -迭代次数取决于零相交信号
 *   EndExecutionLoop
 *   mdlTerminate               -  释放模型占用资源,释放内存
 *                                 etc.
 */

/*====================================================================*
 * 参数处理方法。RTW不支持这些方法                                      *
 *====================================================================*/

#define MDL_CHECK_PARAMETERS   /* 改为 #undef 去掉函数 */
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
  /* 函数: mdlCheckParameters =============================================
   * 摘要:
   *    mdlCheckParameters 在仿真过程中,当参数改变和重新求值时,修改新的参数设置。
   *    当仿真运行时,S-function的参数改变可以发生在仿真循环中任何时间。
   *
   *    该方法可以在mdlInitializeSizes后任何地方调用。
   *    应增加一个调用函数在 mdlInitalizeSizes中来检查参数的合法性。
   *    通过ssSetNumSFcnParams(S,n) 设置参数的个数后,应该添加以下代码:
   *
   *     #if defined(MATLAB_MEX_FILE)
   *       if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
   *           mdlCheckParameters(S);
   *           if (ssGetErrorStatus(S) != NULL) return;
   *       } else {
   *           return;     Simulink 将报告一个参数匹配错误
   *       }
   *     #endif
   *
   *     当Simulation运行时,S-function 的参数即可以在一个simulation开始或者
   *     simulation过程中. 当在simulation过程中,S-function 参数改变时,对于同样的参数改变
   *     这个方法两次调用。 第一次调用用来校验参数的正确性。在验证通过后,当前仿真继续使用当前的参数,
   *     下一个仿真过程将使用新参数。多余的调用应该保持仿真的坚固性,注意在这种方法下你不能访问
   *     work,state,input,output,等向量。这个方法仅用来验证参数。参数的执行应该在mdlProcessParameters方法中。
   *
   *     查看例程 matlabroot/simulink/src/sfun_errhdl.c。 
   */
  static void mdlCheckParameters(SimStruct *S)
  {
  }
#endif /* MDL_CHECK_PARAMETERS */


#define MDL_PROCESS_PARAMETERS   /*  改为#undef取出函数体 */
#if defined(MDL_PROCESS_PARAMETERS) && defined(MATLAB_MEX_FILE)
  /* 函数体: mdlProcessParameters ===========================================
   * 摘要:
   *    当参数改变或者重新求值后,这个方法在mdlCheckParameters后调用。该方法的目的是
   *    执行新改变的参数。例如在work vector工作向量中"caching"缓存参数的改变。在Real-Time Workshop中
   *    不能使用该函数。因此如果想要在Real-Time Workshop使用含有此方法的S-function,必须重写S-function
   *    使其不依靠该方法。这个可以通过在目标语言编译器中内嵌该S-function来实现
   */
 
  static void mdlProcessParameters(SimStruct *S)
  {
  }
#endif /* MDL_PROCESS_PARAMETERS */



/*=====================================*
 * 配置和执行方法                       *
 *=====================================*/

/* Function: mdlInitializeSizes ===============================================
 * 摘要:
 *    Simulink使用尺寸信息来决定S-function模块的特征(例如输入,输出,状态的个数)
 *    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -