simulink仿真
simulink
仿真中需要使用S-Function
模块,可以实现调用C程序进行仿真,下面先建立一个简单的仿真;
具体如下图所示;
创建C程序
需要在S-Function
模块的S-Function name
一栏填写需要调用C程序文件名,注意不需要带文件名后缀;
之后,新建文件sfun_myc.cpp
和sfun_myc.h
,放置在simulink
仿真的同一级目录下,如下图所示;
sfun_myc.h
如下;
/* Copyright 2003-2004 The MathWorks, Inc. */
#ifndef _SFUN_MYC_CPP_
#define _SFUN_MYC_CPP_
// Define a generic template that can accumulate
// values of any numeric data type
template <class DataType> class GenericAdder {
private:
DataType Peak;
public:
GenericAdder() {
Peak = 0;
}
DataType AddTo(DataType Val) {
Peak += Val;
return Peak;
}
DataType GetPeak() const {
return Peak;
}
void SetPeak(DataType v) {
Peak = v;
}
};
// Specialize the generic adder to a 'double'
// data type adder
class DoubleAdder : public GenericAdder<double> {};
#endif
sfun_myc.cpp
如下;
/* Copyright 2003-2004 The MathWorks, Inc. */
// *******************************************************************
// **** To build this mex function use: mex sfun_cppcount_cpp.cpp ****
// *******************************************************************
#include "sfun_myc.h"
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME sfun_myc
// Need to include simstruc.h for the definition of the SimStruct and
// its associated macro definitions.
#include "simstruc.h"
#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)
{
// No expected parameters
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
DoubleAdder *da = new DoubleAdder();
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
DoubleAdder *da = static_cast<DoubleAdder *>(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->AddTo(*u[0]);
y[0] = *u[0] + 100;
}
/* Define to indicate that this S-Function has the mdlG[S]etSimState mothods */
#define MDL_SIM_STATE
/* Function: mdlGetSimState =====================================================
* Abstract:
*
*/
static mxArray* mdlGetSimState(SimStruct* S)
{
// Retrieve C++ object from the pointers vector
DoubleAdder *da = static_cast<DoubleAdder*>(ssGetPWork(S)[0]);
return mxCreateDoubleScalar(da->GetPeak());
}
/* Function: mdlGetSimState =====================================================
* Abstract:
*
*/
static void mdlSetSimState(SimStruct* S, const mxArray* ma)
{
// Retrieve C++ object from the pointers vector
DoubleAdder *da = static_cast<DoubleAdder*>(ssGetPWork(S)[0]);
da->SetPeak(mxGetPr(ma)[0]);
}
// 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
DoubleAdder *da = static_cast<DoubleAdder *>(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
最终在static void mdlOutputs(SimStruct *S, int_T tid)
函数中对输入的数据进行处理即可;
static void mdlOutputs(SimStruct *S, int_T tid)
{
// Retrieve C++ object from the pointers vector
DoubleAdder *da = static_cast<DoubleAdder *>(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->AddTo(*u[0]);
y[0] = *u[0] + 100; //增加100的偏移量
}
编译C程序
查看当前路径下是否已经存在C
文件,sfun_myc.h
,sfun_myc.cpp
;
使用mex
指令编译sfun_myc.cpp
;
运行结果
最终的运行结果,经过S-Function
模块处理的波形比原来的波形偏移了100了,期望结果符合程序的逻辑,具体如下图所示;
链接:百度云下载
提取码:jnmg