编写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++编写方法,附个人测试例子:
Ø 编译
(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如
· 写测试例子,调用生成的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导出即可
目的:编写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导出即可
相关文章推荐
- PB8调用使用C++与C#分别编写生成解压缩带有密码的zip压缩文件的动态链接库dll(部分内容转自互联网)
- c++调用matlab生成的Dll动态连接库
- c#调用c++ dll. unable to find an entry point named function in dll
- [2014.1.31] Eclipse、MinGW、JNI编写C++生成dll, Java端调用的完整示例(附java.lang.UnsatisfiedLinkError解决方法)
- Delphi调用C++编写的动态链接库dll的方法
- 用VS2008生成C++代码的dll及在C#中的调用及常见的类型转换
- [编程实例]Dev-C++编写动态调用dll杀进程的程序
- 非托管C++代码调用C#编写的dll方法
- 用VS2008生成C++代码的dll及在C#中的调用及常见的类型转换
- [总结]非托管C++代码调用C#编写的dll方法
- 用VS2008生成C++代码的dll及在C#中的调用及常见的类型转换
- c#调用c++ dll. unable to find an entry point named function in dll
- C# 调用GDAL编写的动态链接库dll,后不能将生成的图像显示到picturebox上,显示内存不足
- 用VS2008生成C++代码的dll及在C#中的调用及常见的类型转换
- C++ 编写DLL 动态及静态调用DLL方法
- 工欲善其事,必先利其器 软件工具开发关键词 protractor自动化测试工具 RegexBuddy正则 CodeSmith,LightSwitch:代码生成 CheatEngine:玩游戏修改内存值必备神器 ApkIDE:Android反编译工具 Reflector:反编译dll动态链接库
- 【经典实例】利用C#反射动态编译代码,创建类的实例,并调用其成员
- 用VS2008生成C++代码的dll及在C#中的调用及常见的类型转换
- Java调用C/C++编写的第三方dll动态链接库
- c++调用matlab生成的Dll动态连接库