MATLAB S 函数编写示范(基于 MATLABR2010a) 1.M 语言 S 函数 在命令行输入命令“edit sfuntmpl”即可打开 M 语言 s 函数模板。M 语 言 S 函数是以 flag 为标志进行运算的。flag==0 时,初始化参数;flag==1 时, 计算微 分;flag==2 时,状态更新;flag==3 时,计算输出;flag==4 时适用于 变步长结算;其他参数不常用。 (1)flag==0 时,调用 mdlInitializeSizes 函数,sizes 结构及解释如 下: sizes.NumContStates sizes.NumDiscStates sizes.NumOutputs sizes.NumInputs sizes.DirFeedthrough = 0; //连续变量个数 = 0; //离散变量个数 = 0; //输出个数 = 0; //输入个数 = 1; //是否直通,当在输出 里包含了输入时,为直通 sizes.NumSampleTimes = 1; //采样时间 对状态变量进行初始化,如果初始条件是 0 初始条件, 则 x0=[0 0] (2)flag==1 时,调用 mdlDerivatives(t,x,u)函数计算微分,如有一 系统为状态方程为 x'=2x+u,y=5x+u 时,编写如下:sys=2*x+u; (3)flag==3 时,计算输出,如上例系统,则编写如下:sys=5*x+u; ok,下面只需要将编写好的 s 函数名称写入 s-function 模块。 例子:对如下系统(零初始条件) x1'=-3x1-x2+u; x2'=2x1; y=x2;编写 s 函数如下: function [sys,x0,str,ts,simStateCompliance] = sfun_m_hyj(t,x,u,flag) switch flag, case 0, [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes; case 1, sys=mdlDerivatives(t,x,u); case 2, sys=mdlUpdate(t,x,u); case 3, sys=mdlOutputs(t,x,u); case 4, sys=mdlGetTimeOfNextVarHit(t,x,u); case 9, sys=mdlTerminate(t,x,u); otherwise DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag)); end function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes sizes = simsizes; sizes.NumContStates = 2; sizes.NumDiscStates = 0; sizes.NumOutputs = 1; sizes.NumInputs = 1; sizes.DirFeedthrough = 1; sizes.NumSampleTimes = 1; % at least one sample time is needed sys = simsizes(sizes); x0 = [0 0]; str = []; ts = [0 0]; simStateCompliance = 'UnknownSimState'; function sys=mdlDerivatives(t,x,u) sys = [-3*x(1)-x(2)+u;2*x(1)]; //注意此处传递的是 x 向量,包含了 x1 和 x2,引用时使用 x(1),x(2),下标从 1 开始 function sys=mdlUpdate(t,x,u) sys = []; function sys=mdlOutputs(t,x,u) sys = [x(2)]; //x 向量 function sys=mdlGetTimeOfNextVarHit(t,x,u) sampleTime = 1; % Example, set the next hit to be one second later. sys = t + sampleTime; function sys=mdlTerminate(t,x,u) sys = []; 2.C 语言 S 函数 让我们做一个两个输入,两个输出,两个参数的例子。在 MATLAB 命 令行输入 edit sfuntmpl_basic.c 即可打开 C 语言 S 函数模板。 #define #define #define #define S_FUNCTION_NAME test //更改名字 S_FUNCTION_LEVEL 2 INPUT_NUM 2 //输入输出个数 OUTPUT_NUM 2 #include "simstruc.h" ////////////////////////////// //用到的头文件 #include "math.h" #include "stdio.h" static void mdlInitializeSizes(SimStruct *S) { /* See sfuntmpl_doc.c for more details on the macros below */ ssSetNumSFcnParams(S, 2); /* 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); if (!ssSetNumInputPorts(S, INPUT_NUM)) return; ssSetInputPortWidth(S, 0, 3);//设置端口维数,更改为 3x1 ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ //第二个输入端口 ssSetInputPortWidth(S,1,3); ssSetInputPortRequiredContiguous(S,1,true); sSetInputPortDirectFeedThrough(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 1, 1); if (!ssSetNumOutputPorts(S, OUTPUT_NUM)) return; ssSetOutputPortWidth(S, 0, 3);//输出端口维数 3x1 ssSetOutputPortWidth(S, 1, 3);//第二个输出 ssSetNumSampleTimes(S, 0.001);//采样时间 0.001s ssSetNumRWork(S, 0);//设置浮点向量大小,0 表示继承信号大小 ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0);//设置采样点之间的 zero crossing 的模块 的状态个数 /* Specify the sim state compliance to be same as a built-in block */ ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); ssSetOptions(S, 0); 对于输出函数 mdlOutputs,先获得变量,再进行编程 static void mdlOutputs(SimStruct *S, int_T tid) { //获得参数指针 real_T *para1=mxGetPr(ssGetSFcnParam(S,0)); real_T *para2=mxGetPr(ssGetSFcnParam(S,1)); const real_T *u1 = (const real_T*) ssGetInputPortSignal(S,0); const real_T *u2 = (const real_T*) ssGetInputPortSignal(S,1); real_T real_T *y1 = ssGetOutputPortSignal(S,0); *y2 = ssGetOutputPortSignal(S,1); //将输入乘以参数 1 或者参数 2,然后赋值给输出 y1[0] = para1[0]*u1[0]; y1[1] = para1[0]*u1[1]; y1[2] = para1[0]*u1[2]; y2[0] = para2[0]*u2[0]; y2[1] = para2[0]*u2[1]; y2[2] = para2[0]*u2[2]; } ok,使用 mex 编译并加入 s-function 模块,就可以。 3.s-function builder s function builder 可以很方便的自动生成 c 语言 s 函数。 填写 s 函数名,并确定连续状态个数及初始化,采样模式为连续; 编写连续状态程序,注意此处即使只有一个 u0 也要加上 u0[0],且此处的下标是 从 0 开始。 编写输出程序,此处的输入输出定义取默认值。完成后点击 build 按钮生成 s 函数。 最后,总结以上的例子,可得以下仿真结果,从图中看,结果符合逻辑。 MATLAB 调用 C/C++函数的方法 系统分类:科研笔记|关键词:MATLAB C C++ 调用 通过 MATLAB 将 C/C++函数编译成 MEX 函数,在 MATLAB 中就可以调用了。 1,首先装编译器 Matlab 里键入 mex -setup,选择你要编译 C++的编译器 2,写 C++函数 函数的形式必须是 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray * prhs[]) nlhs:输出参数个数 plhs:输出参数列表 nrhs:输入参数个数 prhs:输入参数列表 ,不过函数名可以随便取的。注意:保存的文件名就是将来在 MATLAB 中调用的 函数名,而不是这里的函数名。 下面给出一个例子,目的是想截取数组的部分元素组成新的数组 输入参数 3 个,目标数组,截取的行(向量),截取的列(向量) 输出参数 2 个,截取后数组,数组维数信息 在函数中展示了如何传入传出参数,以及如果从参数列表中取出每一个参数, MATLAB 数据和 C++数据的互相转换,还有一些输出函数等。 新建一个 ResizeArray.cpp 文件(ResizeArray 将作为 MATLAB 调用的函数名), 写入下面代码 #include "mex.h" //author: 汪帮主 2010.05.05 //MATLAB 调用形式: [resizedArr, resizedDims] = ResizeArray(arr, selRows, sekCols) void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs != 3) { mexErrMsgTxt("参数个数不正确!"); } int rowNum = mxGetM(prhs[0]); int colNum = mxGetN(prhs[0]); double* pArr = (double*)mxGetPr(prhs[0]); //得到选择的行列信息 //无论是行向量还是列向量均支持 double* pSelRows = (double*)mxGetPr(prhs[1]); double* pSelCols = (double*)mxGetPr(prhs[2]); int selRowsRowNum = mxGetM(prhs[1]); int selRowsColNum = mxGetN(prhs[1]); if (selRowsRowNum!=1 && selRowsColNum!=1) { mexErrMsgTxt("行参数不正确!"); } int selRowsNum = selRowsRowNum*selRowsColNum; int selColsRowNum = mxGetM(prhs[2]); int selColsColNum = mxGetN(prhs[2]); if (selColsRowNum!=1 && selColsColNum!=1) { mexErrMsgTxt("列参数不正确!"); } int selColsNum = selColsRowNum*selColsColNum; plhs[1] = mxCreateDoubleMatrix(2, 1, mxREAL); double* resizedDims = (double*)mxGetPr(plhs[1]); resizedDims[0] = selRowsNum; resizedDims[1] = selColsNum; plhs[0] = mxCreateDoubleMatrix(selRowsNum, selColsNum, mxREAL); double* pResizedArr =(double*)mxGetPr(plhs[0]); //这里因为 MATLAB 中数据得按列优先 #define ARR(row,col) pArr[(col)*rowNum+row] #define RARR(row,col) pResizedArr[(col)*selRowsNum+row] for(int ri=0; ri<selRowsNum; ri++) { for(int ci=0; ci<selColsNum; ci++) { RARR(ri,ci)=ARR((int)pSelRows[ri]-1,(int)pSelCols[ci]-1); } } mexPrintf("OK!/n"); } 3,编译 C++函数为 MEX 函数 将 ResizeArray.cpp 放在 MATLAB 当前目录中,在 MATLAB 中输入 mex ResizeArray.cpp,编译成功后将会生成 ResizeArray.mexW32 4,调用函数 arr=[11:19;21:29;31:39;41:49;51:59;61:69]; selRows=[1 3]; selCols=[2:4 5 9]; [rarr,rdims]=ResizeArray(arr,rows,cols); arr 中数据: 11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 59 61 62 63 64 65 66 67 68 69 rarr 中数据: 12 13 14 15 19 32 33 34 35 39 rdims 为: 2 5 OK,done!