天天看點

Simulink之S-function函數筆記之三(sfuntmpl_doc.c)s-function學習之sfuntmpl_doc.c

s-function學習之sfuntmpl_doc.c

本文章用來做simulink的S-function函數的學習筆記:

#define S_FUNCTION_NAME your_sfunction_name_here 
#define S_FUNCTION_LEVEL 2

// simstruc.h包含tmwtypes.h(general types)、mex.h、matrix.h
#include "simstruc.h"

//異常處理:
//   ssSetErrorStatus(S, "error encountered due to ...");
//   return;
// ssSetErrorStatus的處理方法建議使用mexErrMsgTxt,mexErrMsgTxt立即終止s-function的執行和傳回。如果不使用mexRrrMsgTxt或任何其他引起異常的方式,則應該使用SS_OPTION_EXCEPTION_FREE_CODE。
//   ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
//設定此選項會允許simulink繞過異常處理的設定。但當使用這個選項時,必須格外小心驗證代碼是無異常的。如果s函數生成異常的時候該選項開啟,将出現不可預測的結果。
// 在記憶體配置設定的問題上使用mxCalloc可能會照成不可預知的問題,如果必須使用記憶體配置設定,建議直接使用stdlib.h配置設定
//以下不會抛出異常:mxGetPr, mxGetData, mxGetNumberOfDimensions, mxGetM, mxGetN, mxGetNumberOfElements.
//如果你所有使用的方法都不會抛出異常,則可以使用:
//  ssSerOptions(S, SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE);

// 警告 & Printf's
// 輸出警告: ssWarning(S, msg), 當s-function編譯之後,ssWarning等同于mexWarnMsgTxt。
//Printf's: ssPrintf(fmt, ...), 當s-function編譯之後,ssPrintf等同于mexPrintf。
//你可以通過這種方法來實作标準I/O:
    #if defined(SS_STDIO_AVAILABLE)
        if ((fp=fopen(file, "w")) == NULl){
            ssSetErrorStatus(S, "open failed");
            return ;
        }
        ...
    #endif  


//s-function methods:
注意: 以下許多方法隻适用于level  C-MEX S-function
**表示該函數必須存在 , []表示該函數可供選擇。
           

Model Initialization in Simulink:

**mdlInitializeSizes: 初始化Simstruct數組大小

**mdlInitializeSampleTimes: 初始化采樣時間和可選擇的函數調用連接配接

[mdlInputPortComplexSignal]/[mdlOutputPortComplexSignal]: 檢查并設定輸入/輸出端口複雜屬性(COMPLEX_YES,C OMPLEX_NO)。

[mdlSetWorkWidths]: 設定狀态,iwork,rwork,pwork,dwork etc.

[mdlSetSimState]: 當初始化模拟狀态時,s-function将ssSetSimStateCompliance 設定為 UES_CUSTOM_SIM_STATE,并把完整的模拟狀态加載到此子產品中。see also mdlGetSimState。

Model simulation loop in simulink:

**mdlOutputs: 更新輸出信号。

**mdlTerminate: 終止模型管理,如釋放記憶體等。

參數處理方法(這些方法不适用于RTW):

#define MDL_CHECK_PARAMETERS //#undef則去除函數方法
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
//mdlCheckParameters:   這個函數應該在mdlInitalizeSizes後被調用。如果你想使用ssSetNumSFcnParams(S, n): 
         #if  defined(MATLAB_MEX_FILE)
             if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
             mdlCheckParamters(S);
             if (ssGetErrorStatus(S) != NULL) return;
             }
             else{
              return;//simulink will report a parameter mismatch error
              }
         #endif
詳例見 Matlabbroot/simulink/src/sfun_errhdl.c 

static void mdlCheckParameters(SimStruct *S)
{
}
#endif //MDL_CHECK_PARAMETERS
           
#define MDL_PROCESS_PARAMETERS 
#if defined(MDL_PROCESS_PARAMETERS) && defined(MATLAB_MEX_FILE)
//mdlProcessParameters:     這個函數将在mdlCheckParameters之後被調用,處理新更新的參數。

static void mdlProcessParameters(SimStruct *S)
{
}
#endif //MDL_PROCESS_PARAMETERS
           

Configuration and execution methods:

//mdlInitializeSizes:
     Direct Feedthough: 
         直接回報的值可以為或者,如果為輸入,則必須置為,‘u’可被用于mdlOutput或者mdlGetTImeOfNextVarHit()。若置為,‘u’則不能被用于這兩個函數。如:要使用ssGetInputPortSignal(S, inputPortIndex),則需要ssSetInputPortDirectFeedThrough(S, inputPortIdx, );

//如果需要debug s-function則:mex -g sfunction_name.c

static void mdlInitializeSizes(SimStruct *S)
{
    int_T nInputPorts = ;//輸入端口的參數個數
    int_T nOutputPorts = ;//輸出端口的參數個數
    int_T needsInput = ;//直接回報?

    int_T inputPortIdx = ;
    int_T outputPortIdx = ;

    ssSetNumSFcnParams(S, );//預期參數個數
    if (ssGetNumSFcnParams(S) != ssGetNumParamsCount(S)) {
        //如果預期參數個數與所獲參數個數不一樣,則傳回參數不比對錯誤。
        return;
    }

    //任何參數在模拟中是可以更改的,但若想将參數設定為不可更改,則使用:
        ssSetSFcnParamTunable(S, , );

    ssSetNumContStates( S, );//連續參數的個數
    ssSetNumDiscStates( S, );//離散參數的個數

    //設定輸入端口的個數:

    if(! ssSetNumInputPorts(S, nInputPorts)) return;


     if(!ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION))  return;
     // 1.若輸入端口維數未知,則用:ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION)。
       若輸入信号是無定向矢量,輸入端口寬度為w(DYNAMICALLY_SIZED或大于),則用:ssSetInputPortVectorDimension(S, inputPortIdx, w)或 ssSetInputPortWidth(S, inputPortIdx, w)。
       若輸入信号為m*n的矩陣,m,n(DYNAMICALLY_SIZED或大于),則用: ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n)。
       其他情況,則用:ssSetInputPortDimensionInfo(S, inputPortIdx, dimsInfo)。dimsInfo結構體包含:width, number of dimensions, dimensions of the port。


    ssSetInputPortDirectFeedThrough(S, inputPortIdx, needsInput);
      // mdlOutputs,mdlGetTimeOfNextVarHit
      //詳見 sfuntmpl_directfeed.txt

    if(!ssSetNumOutputPorts(S, nOutputPorts)) return; 
    //設定輸出端口的個數

    if(!ssSetOutputPortDimensionInfo(S, outputPortIdx, DYNAMIC_DIMENSION))  return; 
    //與input相似

    ssSetNumSampleTimes( S, );
    //設定采樣時間(大于0的整數或PORT_BASED_SAMPLE_TIMES)

    ssSetNumRWork(  S, );//number of real work vector elements
    ssSetNumIWork(  S, );//number of integer work vector elements
    ssSetNumPWork(  S, );//number of pointer work vector elements
    ssSetNumModes(  S, );//number of mode work vector elements
    ssSetNumNonsampledZCs( S, );//number of nonsampled zero crossings

    ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
    //詳見sfun_simstate.c

    ssSetOptions(  S, );
    //ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2))
}//mdlInitializeSizes結束
           
#define MDL_SET_INPUT_PORT_FRAME_DATA
#if defined(MDL_SET_INPUT_PORT_FRAME_DATA) && defined(MATLAB_MEX_FILE)

static void mdlSetInputPortFrameData(SimStruct *S,
                                     int   portIndex,
                                     Frame_T  frameData)
{
//這個函數為輸入端口的候選框設定(FRAME_YES,FRAME_NO),如果設定成功,則函數可繼續并設定ssSetInputPortFrameData(S, portIndex, frameData);如果設定失敗,則通過ssSetErrorStatus生成錯誤。任何的其他動态輸入輸出都會調用ssSetInputPortFrameData,ssSetOutputPortFrameData。
}

#endif //MDL_SET_INPUT_PORT_FRAME_DATA
           
#define MDL_SET_INPUT_PORT_WIDTH
#if defined(MDL_SET_INPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE)

 static void mdlSetInputPortWidth(SimStruct *S, int portIndex, int width)
 {
 //端口寬度動态調節ssSetInputPortWidth,ssSetOutputPortWidth
 }  
#endif //MDL_SET_INPUT_PORT_WIDTH
           
#define MDL_SET_OUTPUT_PORT_WIDTH
#if defined(MDL_SET_OUTPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE)

 static void mdlSetOutputPortWidth(SimStruct *S, int portIndex, int width)
 {
 //端口寬度動态調節ssSetInputPortWidth,ssSetOutputPortWidth
 }  
#endif //MDL_SET_OUTPUT_PORT_WIDTH
           
#define MDL_SET_INPUT_PORT_DIMENSION_INFO
#if defined(MDL_SET_INPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)

static void mdlSetInputPortDimensionInfo(SimStruct    *S,
                                         int_T    portIndex,
                                         const DimsInfo_T)
{
//為未知次元的輸入端口做備選設定。例詳見:matlabroot/simulink/src/sfun_matadd.c
}
#endif //MDL_SET_INPUT_PORT_DIMENSION_INFO
           
#define MDL_SET_OUTPUT_PORT_DIMENSION_INFO
#if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)

static void mdlSetOutputPortDimensionInfo(SimStruct    *S,
                                         int_T    portIndex,
                                         const DimsInfo_T)
{
//為未知次元的輸入端口做備選設定。例詳見:matlabroot/simulink/src/sfun_matadd.c
}
#endif //MDL_SET_OUTPUT_PORT_DIMENSION_INFO
           
#define MDL_SET_INPUT_PORT_SAMPLE_TIME
#if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE)

static void mdlSetInputPortSampleTime(SimStruct    *S,
                                      int_T     portIdx,
                                      real_T    sampleTime,
                                      real_T    offsetTime)
{
//
}
#endif //MDL_SET_INPUT_PORT_SMAPLE_TIME
           
#define MDL_SET_OUTPUT_PORT_SAMPLE_TIME
#if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE)

static void mdlSetOutputPortSampleTime(SimStruct    *S,
                                      int_T     portIdx,
                                      real_T    sampleTime,
                                      real_T    offsetTime)
{
//
}
#endif //MDL_SET_OUTPUT_PORT_SMAPLE_TIME
           
static void mdlInitializeSampleTimes(SimStruct  *S)
{
    //設定采樣時間,如果未設定,則假定有個繼承的采樣時間。
    //格式:[sample_time, offset_time]
    //ssSetSampleTime(S, sampleTimePairIndex, sample_time)
    //ssSetOffsetTime(S, offsetTimePairIndex, offset_time)

    ssSetSampleTime(S, , CONTINUOUS_SAMPLE_TIME);
    ssSetOffsetTime(S, , );
}//end mdlInitializeSampleTimes
           
#define MDL_SET_INPUT_PORT_DATA_TYPE
#if defined(MDL_SET_INPUT_PORT_DATA_TYPE)  && defined(MATLAB_MEX_FILE)

static void mdlSetInputPortDataType(SimStrcut *S, 
                                    int portIndex,
                                    DTypeId  dType)
{
// 該方法和動态的輸入端口候選資料一起調用。詳見matlabroot/simulink/include/simstruc_types.h 中的内置類型定義:SS_DOUBLE, SS_BOOLEAN, etc; 例詳見:matlabroot/simulink/src/sfun_dtype_io.c 。
}
#endif//MDL_SET_INPUT_PORT_DATA_TYPE
           
#define MDL_SET_OUTPUT_PORT_DATA_TYPE
#if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE)  && defined(MATLAB_MEX_FILE)

static void mdlSetOutputPortDataType(SimStrcut *S, 
                                    int portIndex,
                                    DTypeId  dType)
{
// 同上
}
#endif//MDL_SET_OUTPUT_PORT_DATA_TYPE
           
#define MDL_SET_DEFAULT_PORT_DATA_TYPE
#if defined(MDL_SET_DEFAULT_PORT_DATA_TYPE) && defined(MATLAB_MEX_FILE)

static void mdlSetDefaultPortDataTypes(SimStruct *S)
{
//當你的資訊不足以确定唯一的輸入輸出資料類型時調用此函數。
}
#endif //MDL_SET_DEFAULT_PORT_DATA_TYPE
           
#define MDL_SET_INPUT_PORT_COMPLEX_SIGNAL
#if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE)

static void mdlSetInputPortComplexSignal(SimStruct *S,
                                         int  portIndex,
                                         CSignal_T cSignalSetting)
{
//用于候選複雜信号設定(COMPLEX_YES,COMPLEX_NO)。
//ssSetInputPortComplexSignal , ssSetOutputPortComplexSignal
}

#endif //MDL_SET_INPUT_PORT_COMPLEX_SIGNAL
           
#define MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL
#if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE)

static void mdlSetOutputPortComplexSignal(SimStruct *S,
                                         int  portIndex,
                                         CSignal_T cSignalSetting)
{
//同上。
//ssSetInputPortComplexSignal , ssSetOutputPortComplexSignal
}

#endif //MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL
           
#define MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS
#if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS) && defined(MATLAB_MEX_FILE)

static void mdlSetDefaultPortComplexSignals(SimStruct *S)
{
//當資訊不足時調用
}

#endif// MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS
           
#define MDL_INITIALIZE_CONDITIONS
#if defined(MDL_INITIALIZE_CONDITIONS)

static void mdlInitializeConditions(SimStruct *S)
{
//初始化連續變量和離散變量。
}

#endif //MDL_INITIALIZE_CONDITIONS
           
#define MDL_START
#if defined(MDL_START)

static void mdlStart(SimStruct *S)
{
//在子產品執行時調用一次(初始化)。
}
#endif //MDL_START
           
#define MDL_SIM_STATE
#if defined(MDL_SIM_STATE)

static mxArray* mdlGetSimState(SimStruct *S)
{
//inSinState MATLAB data structure
}
#endif//MDL_SIM_STATE
           
#define MDL_GET_TIME_OF_NEXT_VAR_HIT
#if defined(MDL_GET_TIME_OF_NEXT_VAR_HIT) && (defined(MATLAB_MEX_FILE)) || defined(NRT))

static void mdlGetTimeOfNextVarHit(SimStruct *S)
{
    time_T timeOfNextHit = ssGetT(S)
    ssSetTNext(S, timeOfNextHit);
}
#endif//MDL_GET_TIME_OF_NEXT_VAR_HIT
           
static void mdlOutputs(SimStruct *S, int_T tid)
{
}
           
#define MDL_UPDATE
#if defined(MDL_UPDATE)

static void mdlUpdate(SimStruct *S, int_T tid)
{
//更新離散變量
}
#endif //MDL_UPDATE
           
static void mdlTerminate(SimStruct *S)
{
//在這個函數中,執行模拟終止所需操作。如釋放記憶體。
}
           

}

#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
           

如果有什麼錯誤望指教。

參考Matlab官方文檔sfuntmpl_doc.c

繼續閱讀