Uploaded by meee.potato

MATLAB S函数编写示范

advertisement
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!
Download