您的位置:首页 > 编程语言 > C语言/C++

编写S-Function,创建Simulink模型并生成C++代码,编译生成可调用的动态库dll(From Simulink model to DLL A tutorial)

2014-03-04 10:38 3051 查看
环境:matlab2012b, windows8.1 x64,vs2010
目的:编写S-Function,创建Simulink模型并生成C++代码,编译生成可调用的动态库dll
操作步骤:
·        编写S-Function
Ø 寻找一个S-Function模板
(1) 打开matlab主窗口,命令行中输入sfundemos,
(2) 会弹出一个S-Function
Examples的窗口,选择C++,选择C++ Objects
(3) 双击sfun_counter_cpp.cpp打开matlab编辑器
(4) 将代码copy一份并保存为add_my.cpp至自己的工作空间中,如E:\Workspace\MatlabWorkSpace\add\
Ø 修改为自己的S-Function 具体可参考相关S-Function
C++编写方法,附个人测试例子:

*******************************************************************
// **** To build this mex function use: mex add.cpp ****
// *******************************************************************

#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME  add_my

// Need to include simstruc.h for the definition of the SimStruct and
// its associated macro definitions.
#include "simstruc.h"

//define self class
class Adder{
double count;
public:
Adder()
{
count = 0;
}

double getSum(double a, double b)
{
count = a + b;
return count;
}

void setSum(double c)
{
count = c;
}
};

#define IS_PARAM_DOUBLE(pVal) (mxIsNumeric(pVal) && !mxIsLogical(pVal) &&\
!mxIsEmpty(pVal) && !mxIsSparse(pVal) && !mxIsComplex(pVal) && mxIsDouble(pVal))

// Function: mdlInitializeSizes ===============================================
// Abstract:
//    The sizes information is used by Simulink to determine the S-function
//    block's characteristics (number of inputs, outputs, states, etc.).
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0);

// Parameter mismatch will be reported by Simulink
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return;
}

// Specify I/O
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);

ssSetNumSampleTimes(S, 1);

// Reserve place for C++ object
ssSetNumPWork(S, 1);

ssSetSimStateCompliance(S, USE_CUSTOM_SIM_STATE);

ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE |
SS_OPTION_EXCEPTION_FREE_CODE);

}

// Function: mdlInitializeSampleTimes =========================================
// Abstract:
//   This function is used to specify the sample time(s) for your
//   S-function. You must register the same number of sample times as
//   specified in ssSetNumSampleTimes.
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}

// Function: mdlStart =======================================================
// Abstract:
//   This function is called once at start of model execution. If you
//   have states that should be initialized once, this is the place
//   to do it.
#define MDL_START
static void mdlStart(SimStruct *S)
{
// Store new C++ object in the pointers vector
Adder *da  = new Adder();
ssGetPWork(S)[0] = da;
}

// Function: mdlOutputs =======================================================
// Abstract:
//   In this function, you compute the outputs of your S-function
//   block.
static void mdlOutputs(SimStruct *S, int_T tid)
{
// Retrieve C++ object from the pointers vector
Adder *da = static_cast<Adder *>(ssGetPWork(S)[0]);

// Get data addresses of I/O
InputRealPtrsType  u = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S, 0);

// Call AddTo method and return peak value
y[0] = da->getSum(*u[0], *u[1]);
}

// Function: mdlTerminate =====================================================
// Abstract:
//   In this function, you should perform any actions that are necessary
//   at the termination of a simulation.  For example, if memory was
//   allocated in mdlStart, this is the place to free it.
static void mdlTerminate(SimStruct *S)
{
// Retrieve and destroy C++ object
Adder *da = static_cast<Adder *>(ssGetPWork(S)[0]);
delete da;
}

// Required S-function trailer
#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif


Ø 编译
(1) 在命令行输入mex
–setup,选择需要的编译器(已选择则无需此操作)
(2) 选择自己需要的Visual
Studio版本
(3) Matlab切换工作空间至E:\Workspace\MatlabWorkSpace\add\
(4) 在命令行输入
mex add_my.cpp,会编译成add_my.mexw64

·        创建simulink模型
Ø 在主面板点击Simulink
Library,File->New->Model,会出现一个新的模型窗口,向此界面拖拽你的模型的元素,此处拖一个基本的加法模型 “a+b=c”
(1) 首先拖一个s-function到此窗口,目录为Simulink->User-Defined
Functions->S-Function
(2) 拖入a,b的输入模块,目录为Simulink->Commonly
Used Blocks->Constant,
(3) 拖入结果c显示模块,目录为Simulink->Sinks->Display
(4) 模块连线
(5) 关联界面到可执行文件,双击s-function,在s-functionname处填写自定义的s-function名称,此名称位于s-function文件add_my.cpp中,”#defineS_FUNCTION_NAME
add_my”
(6) 填写输入参数,双击constant,在Constantvalue输入要计算加法运算的a,b,以一个向量的方式输入,[100123.123]
Ø 保存模型,如add_model.slx
·        生成C++代码,生成可调用的动态库dll
Ø 配置编译参数
(1) 在菜单选择Code->C/C++
Code->Code GenerationOptions
(2) 选择Code
Generation,目标文件grt.tlc,语言C++
(3) 选择Solver,开始时间0.0,结束时间1,Solver
options选择Type:Fixed-step,固定步长设为1(默认为1s)
Ø 生成C++代码
(1) 在菜单选择Code->C/C++
Code->Build Model编译生成的C++工程
(2) 在matlab主窗口会有相关打印log,有错误时会有错误窗口,根据提示修改即可
(3) 可打开VS工程调试一下生成的代码
Ø 生成可调用的动态库dll
(1) 通过分析生成的代码工程发现,工程里的一些文件并非是生成的代码,而是matlab下的代码,如rt_matrx.c,rt_main.c(linux下可能为grt_main.c,具体根据前面生成代码选项的选择)等
(2) 新建一个VS动态库dll工程,把上述代码copy到新的工程下,修改rt_main.c文件,将mian()函数改名为mymain()
(3) 修改工程配置项,如包含的头文件目录,编译选项,连接的库等,具体可参考生成代码的工程
(4) 添加dll导出文件,编译通过,即可生成dll如
#ifndef ModelExport_H_
#define ModelExport_H_

#ifdef _WIN32
#if defined(ADD_MODEL_EXPORTS)
#define ADD_MODEL_API __declspec(dllexport)
#else
#define ADD_MODEL_API __declspec(dllimport)
#endif
#endif

#ifdef _LINUX
#ifdef MESSAGEBOARD_EXPORTS
#define ADD_MODEL_API __attribute__(visibility("default"))
#else
#define ADD_MODEL_API
#endif
#endif

/* Function: main =============================================================
*
* Abstract:
*   Execute model on a generic target such as a workstation.
*/
ADD_MODEL_API int mymain(int argc, const char *argv[]);

#endif

·        写测试例子,调用生成的dll
Ø 创建可执行程序工程,
在主函数文件中
#include “ModelExport.h”
int main(int argc, const char* argv[])
{
     Mymain(argc,argv);
     Return 0;
}
 
 
注:本测试验证只是调用dll可行性,具体如何动态向simulink模型传递参数,并从simulink模型取参数还需要进一步详细分析。
参考:”From Simulink model to DLLA tutorial”   by Roland Pfeiffer

2014-3-5更新:
获取输入输出参数的方法为:
1,首先在grt_shell.c中添加相关matlab API调用,以下为输出参数例子代码:
SimStruct *S = add_model_M->childSfunctions[0];
int outputNum = ssGetNumOutputPorts(S);
printf("outputNum=%d\n",outputNum);

double *outputP = (double *)ssGetOutputPortRealSignal(S,0);

double outputValue = *outputP;

printf("outputNum=%f\n",outputValue);

2,封装相关API,从dll导出即可
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐