环境: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导出即可
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。