6
Object oriented C++ programming in SIMULINK®. A reengineered simulation architecture for the control algorithm code view. Søren Top(*), Hans Jørgen Nørgaard(**),Bo Nørregaard Jørgensen(*) (*)Southern University of Denmark (**)Msc. control engineer at Danfoss Drives E-mail:[email protected] Abstract By the use of MATLAB tools Simulink® models of control algorithms can be translated into an equivalent C-program. This paper treats a different approach of building control algorithm block components in C++ for use both in Simulink® models and in application code development. The object oriented reengineering has been applied to a subset of the present simulation library of control algorithms at Danfoss Drives, one of the world’s largest producers of frequency converters. A frequency converter is an electronic device controlling the rotational speed of an electrical AC motor. By the use of object orientation, the chosen subset of control algorithms was transformed from a collection of C- functions into a collection of C++ components. Thus by confining control algorithm state variables and functions to objects and Simulink® specific code to Simulink® S-function wrapper files an entangling of the code has been achieved. Thus control algorithm clarity has improved. By utilizing advanced features in C++ the same control code text could be simulated using a fixed-point calculation library and a library of calculations with physical units (Volt, Ampere, Ohm, Radians etc), where improper use of physical units are caught on compile-time. Furthermore calculations can be monitored on runtime for overflow, underflow and the degree of precision when dealing with fixed-point calculations. As control algorithm blocks are represented as C++ objects, inter connected control algorithm blocks can be synthesized in a new class, which in turn becomes a building block of a higher abstraction level. Such high level building blocks can be handed out to be used in customer’s simulations without revealing Danfoss Drives business secrets, because the blocks are compiled code comprised in a DLL – component (Dynamic Linked Library component). The software development process benefits from improved interfaces between control engineers and software engineers, faster and shorter development cycles and earlier testing. Maintenance of the control algorithms becomes easy because control algorithm code irrelevant details are factored out and handled safely in other parts of the architecture. 1. Introduction Many embedded systems deals with some sort of regulation of a physical system. So eventually the start of application development is often control engineering. In the realm of control engineering simulation tool plays an increasingly dominant role in the development of a regulation system. Simulink® also offer code generation facilities. In our industrial case and in many other big scale embedded applications, where the regulation code constitutes a minor part of the overall embedded program code, an integration of control engineering into the normal software and hardware engineering is a preferable approach, we believe. In our industrial setting control algorithm code part is approximately 20%. Simulink® offers inclusion of legacy code components in simulations. In this way algebraic equations can be confined to a so Simulink® S-function to be used in the drawing of a design. This is the approach taken at Danfoss Drives [1] and in the following sections a reengineered simulation architecture for the control algorithm code will be presented. The outline is as follows: Section 2 gives a short introduction to the problem domain at Danfoss Drives. Section 3 explains the future vision. Section 4 describes the application of strategies. Section 5 treats the impact on the maintenance and development process. Section 6 gives some conclusions. 2. The Frequency Converter Problem Domain In this section we elaborate on the problems identified in section 1.1. A frequency converter is a device used to control shaft speed or torque of a three-phase induction motor to match the need of a given application. A frequency converter is often called a “drive”. Typical applications are speed control of conveyer belts, torque control of extruders or control of a fan as shown on Figure 1.

Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Embed Size (px)

DESCRIPTION

By the use of MATLAB tools Simulink® models of control algorithms can be translated into an equivalent C-program.This paper treats a different approach of building control algorithm block components in C++ for use both in Simulink® models and in application code development.

Citation preview

Page 1: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Object oriented C++ programming in SIMULINK®. A reengineered simulation architecture for the control algorithm code view.

Søren Top(*), Hans Jørgen Nørgaard(**),Bo Nørregaard Jørgensen(*)

(*)Southern University of Denmark (**)Msc. control engineer at Danfoss Drives

E-mail:[email protected]

Abstract

By the use of MATLAB tools Simulink® models of control algorithms can be translated into an equivalent C-program. This paper treats a different approach of building control algorithm block components in C++ for use both in Simulink® models and in application code development.

The object oriented reengineering has been applied to a subset of the present simulation library of control algorithms at Danfoss Drives, one of the world’s largest producers of frequency converters. A frequency converter is an electronic device controlling the rotational speed of an electrical AC motor. By the use of object orientation, the chosen subset of control algorithms was transformed from a collection of C-functions into a collection of C++ components. Thus by confining control algorithm state variables and functions to objects and Simulink® specific code to Simulink® S-function wrapper files an entangling of the code has been achieved. Thus control algorithm clarity has improved.

By utilizing advanced features in C++ the same control code text could be simulated using a fixed-point calculation library and a library of calculations with physical units (Volt, Ampere, Ohm, Radians etc), where improper use of physical units are caught on compile-time. Furthermore calculations can be monitored on runtime for overflow, underflow and the degree of precision when dealing with fixed-point calculations.

As control algorithm blocks are represented as C++ objects, inter connected control algorithm blocks can be synthesized in a new class, which in turn becomes a building block of a higher abstraction level. Such high level building blocks can be handed out to be used in customer’s simulations without revealing Danfoss Drives business secrets, because the blocks are compiled code comprised in a DLL – component (Dynamic Linked Library component).

The software development process benefits from improved interfaces between control engineers and software engineers, faster and shorter development cycles and earlier testing. Maintenance of the control algorithms becomes easy because control algorithm code irrelevant details are factored out and handled safely in other parts of the architecture.

1. Introduction Many embedded systems deals with some sort of regulation of a physical system. So eventually the start of application development is often control engineering. In the realm of control engineering simulation tool plays an increasingly dominant role in the development of a regulation system. Simulink® also offer code generation facilities. In our industrial case and in many other big scale embedded applications, where the regulation code constitutes a minor part of the overall embedded program code, an integration of control engineering into the normal software and hardware engineering is a preferable approach, we believe. In our industrial setting control algorithm code part is approximately 20%. Simulink® offers inclusion of legacy code components in simulations. In this way algebraic equations can be confined to a so Simulink® S-function to be used in the drawing of a design. This is the approach taken at Danfoss Drives [1] and in the following sections a reengineered simulation architecture for the control algorithm code will be presented. The outline is as follows: Section 2 gives a short introduction to the problem domain at Danfoss Drives. Section 3 explains the future vision. Section 4 describes the application of strategies. Section 5 treats the impact on the maintenance and development process. Section 6 gives some conclusions. 2. The Frequency Converter Problem Domain

In this section we elaborate on the problems identified

in section 1.1. A frequency converter is a device used to control shaft

speed or torque of a three-phase induction motor to match the need of a given application. A frequency converter is often called a “drive”. Typical applications are speed control of conveyer belts, torque control of extruders or control of a fan as shown on Figure 1.

Page 2: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Figure 1 A frequency converter used for controlling the speed of a fan

Modern frequency converters contain digital signal processors (DSP’s) for executing the control algorithms that maintain the desired motor speed.

These algorithms are developed and tested by simulation. A library of simulation components is created to facilitate the simulation of different motor control algorithms. The top-level components are divided into groups of motor models, control models, and load models. The lower level models components implement different aspects of the top level components such as the electrical and mechanical parts of an induction motor. The models are created in Matlab/Simulink® using Simulink® blocks, Matlab® scripts and coded in the C programming language. Simulink® is a graphical simulation tool build on top of a Matlab® calculation engine. The simulation models are constructed in the following way: A model comprises models or basic building blocks defined as Simulink® S-functions. A S-function is user written code (in this case written in C or m-scripts (matlabs own interpreted language)) put in a wrapper file template, which in turn is compiled into a windows DLL component and used by Simulink® in performing simulations. 3. The Vision. The vision is to retain the same control algorithm source code through out the entire development process. This source code should be invariant to changes in surrounding tools and environments and even invariant to change of object-oriented language. The same control algorithm code should be present in both the simulation environment and in the runtime environment. The necessary adjustments should not afflict the original control algorithm code, but should be done in other parts of the resulting program. This could be termed as “white box” compliance as opposed to the normal “black box” compliance assured by testing. As the control algorithms

represent substantial know-how of Danfoss Drives, this vision is of big importance. 4. Strategies Applied The first strategy was introduction of object orientation. The strategies of the code file sandwich hen follows. It comprises 3 levels (not layers) of files. Subject orientation as the upper part of the code sandwich, algorithm control block code in the middle and wrapper techniques as the lower part. Use of the code file sandwich strategy is depicted in the figure 2 below. The last strategy introduced is synthesis of interconnected basic blocks into bigger building blocks

4.1. Object orientation and decoupling from simulation tool

In section 2 the old simulation code architecture was described. Simulink® when dealing with legacy code act as a framework based on the “Hollywood principle” – do not call us – we call you. This means that pieces of legacy code placed in DLLs are dynamically linked into a simulation model and called during simulation by the Simulink® framework. The functions in the Simulink® C legacy code wrapper file is call back functions used by Simulink® during simulation. Some functions are used to initialize state variables and parameter variables. Some are input functions used for updating state variables in a simulation step. Others are output functions used for calculating outputs. And finally an activate function and a destructor function is also defined. Several other callback functions are available, but are not used in this context. Instead of writing the blocks of the control algorithm in the above-mentioned call back functions, we build an object comprising the control algorithm block functionality and the control state variables. Then the call back functions will call the methods in this objects interface. In this way the control algorithm code is

Setup.h Variation point types are defined In this include file.-------------------------------------------------------------------------------------------------------------------------------------- Volt , Ampere, Ohm = unit types or just floats types ? Numbers = fix point numbers or floats ?

RL.h #includes Setup.h-------------------------------------- Limiter function

Uf.h #includes Setup.h----------------------------------------------- UF Controller

wrapper.cpp This file adapts the control algorithm to a certain environment.-------------------------------------------------------------------------------------------------------------------------------------- #includes RL.h #includes UF.h

Figure 2 The sandwich code file structure

Page 3: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

factored out, and what is left behind in the Simulink® S-function wrapper file is Simulink® specific code.

before after

control specific codesimulink wrapper code

Figure 3 Out factoring

Example: Listing 1 (at the end of the article) shows an example of such out-factored control code and listing 2 is an excerpt from the according S-function wrapper file showing how the output function is called. This gives the following immediate benefits: -Simulation tool independence: All the major simulation tools in the market are capable of handling C++ legacy code. Thus if all simulation blocks were implemented as C++ components, then these components could be utilized in different simulation tools. What should be done in this transformation is writing specific component wrappers for each simulation tool. - Control algorithm clarity. Now the control algorithm blocks are readable to control engineers without experience in programming Simulink® S-functions. Both the calculation formulas and the relevant control states for a control code algorithm building block are gathered in a class. As a rough estimate only 1/5 of the Simulink® C S-function source code lines originated directly from the control code algorithm - the rest being Simulink® specific code. - Division of labor When Simulink® specific code has been factored out, division of labor amongst control engineers will be facilitated, not all of them will have to know all about Simulink® S-functions. Division of labor between control engineers and software engineers is improved as well, because these C++ components are readable for both parties.

4.2. Subject orientation – the upper part of the code file sandwich

This strategy is about moving architectural variation points to a namespace, where meaning of named entities (such as types) can be defined in accordance with a

particular subject. This is a very simple example of subject oriented programming. In this case the meaning of arithmetic operators and variable types is defined in an include file (which is used as a namespace here – it works fine with older C++ compilers). The types in control algorithm block classes are defined as physical units (such as Volt, Ampere, Ohm etc.). Thus a variable in a control algorithm block class is defined as a Volt type or as an Ampere type or as another physical unit type. See listing 3. In the floating-point version of the “setup.h” include file a typedef declaration defined the unit types as the type double. This is just as it was in old days. In the fixed-point version of the “setup.h” include file the unit types was defined to be the fixed_point class. See listing 4. This class defines its own arithmetic operator functions. In this way the same control algorithm block class code text can perform floating-point calculations, if the first version of the setup include file is used, and fixed-point calculations, if the second version of the setup include file is used. Calculations in simulations are normally done in floating point variables, whereas calculations done in the embedded program in the frequency converter are fixed point calculations. The benefit is that fixed-point calculation inaccuracies in the run-time target can be studied in simulations. In the physical unit version of the “setup.h” include file the unit types are implemented as instances of the Unit class template. See listing 5. In this way physical unit errors in calculations are caught on compile time! Addition of two Volt variables is OK, but addition of a Volt variable to an Ampere variable generates a compile time error. Multiplication of an Ampere variable and a Volt variable gives you a Watt variable, a Volt variable divided with an Ampere variable gives you an Ohm variable and so on. The implementation in the “setup.h” include-file follows the principles given in [3]. The Simulink® framework can perform unit check too. In listing 6 RadPerSec is defined as a signal type and an output port and an input port is defined to be RadPerSec. Before simulation starts Simulink® performs type matching checks of outputs connected to inputs. 4.3. Wrapping – the lower part of the sandwich code file structure Simulation environments and execution environments have different characteristics. Thus the control algorithm block classes has to be adapted (wrapped) in order to suit the different environments This could be done by sub classing in the case of the run-time environment. In the case of the Simulink® simulation tool environment the wrapping is done by declaring a control algorithm block object in the Simulink® S-function wrapper file for a

Page 4: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Simulink® block. A company internal standard wrapper file has been developed. 4.4. Synthesis of control algorithm blocks

A group of interconnected control algorithm block

objects could be defined in a new class, which now becomes a larger building block.

Limiter object UF controller object

Before After

Limited UF controller object

Figure 4 Synthesis of control algorithm blocks

This gives a lot of new possibilities. Once the simulation blocks are built as objects a whole range of component composition techniques from the realm of software emerge. As a first little example: we could have defined the limited UF controller object from figure 4 as an object from a subclass of class UF controller object instead. Thus an inheritance hierarchy of controller classes can be established. Entire control loops could be represented in such a class. Existing software components could be tested and verified in Simulink® simulations upfront in the system development process. Thus a decision of reusing legacy code can be investigated upfront. 5. Process of development and maintenance.

The use of simulations as means of verification gives improvements to the process of development. This process is divided into 3 stages. First the control engineers build the control algorithm model, then software engineers implement it in the embedded environment and finally hardware engineers perform the final integration tests in laboratory. If errors are discovered in the later stages, then an extra (costly) long (involving 2 or 3 stages) iteration can take place – see the figure 5 below.

Regarding 3 stages iterations: In Simulink® a windows DLL component could be made for an object of a control loop class built by synthesis of low level components as explained in section 4.3. As this DLL component is compiled code, it could be handed over to a customer’s simulation model without revealing any of Danfoss Drives secrets (Danfoss Drives holds a number of patents for its control algorithms). Likewise the costumer could, without revealing her secrets, in return hand over application simulation components to be used

in Danfoss Drives simulations. In this way some of the laboratory application tests can be moved up front to the realm of simulations. .

Before

After

SoftwareEngineering

HardwareEngineering

ControlEngineeringSimulation

SoftwareEngineering

HardwareEngineering

ControlEngineringSimulation

dll-files

Customer

Customer

ApplicationKnowledge

Figure 5 Stages of development 6. Conclusions The vision about retaining the same control algorithm code throughout the development process has shown to be viable. Control engineers easily adapt to object orientation and the clear division between control algorithm code and simulation code has been appreciated. A simulation tool independent representation of the control algorithms has been achieved. The new opportunities for checking inaccuracies of fixed-point calculations and for unit compile-time check are being explored. The combined use of object orientation, subject orientation and wrapping techniques has resulted in an code architecture with a clear division of stable and variable parts suitable for the future development and maintenance of control applications at Danfoss Drives. 7. References [1] http://www.danfoss.com/drives. [2] The book: “Applied Software Architecture” by Christine Hoffmeister, Robert Nord, Dilip Soni. Addison-Wesley,1999 [3] “Applied Template Metaprogramming in Siunits: the Library of Unit-Based Computation”, Walther E. Brown, august-2001

Page 5: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Listing 1 #include "math.h" class UF_control { public: UF_control(double ts,double un,double rs, double isNom,double fsNom) : Usy(0), theta(0), theta_old(0), Ts(ts), Ws(0) { ufgain = 1.06*1.5*(un/sqrt((double)3)-rs*isNom)* sqrt((double)2)/(fsNom*2*pi); ufoffset = rs*isNom*sqrt((double)2)*1.5; } void update(double ref) { theta_old = theta; theta = ref * Ts + theta_old; Usy = ufgain * ref + ufoffset; Ws = (theta - theta_old) / Ts ; } // this function returns the length of the voltage vector double getUsy(){ return Usy; } //this function returns the angle of the voltage vector double getTheta(){ return theta; } //this function returns the angle speed of the voltage vector double getWs(){ return Ws; } private: double Ts,Usy,ufgain, ufoffset, theta, theta_old,Ws; };

Listing 2 #define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) static void mdlUpdate(SimStruct *S, int_T tid) {// retrieve input pointer vector InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); double ref=*uPtrs[0] ; // reference input signal is retrieved // retrieve pointer to C++ object from Simulinks pointer work //vector UF_control *UF_control_ptr = (UF_control *) ssGetPWork(S)[0]; // call of the function update in the C++ object UF_control_ptr->update( ref ); } /* End of mdlUpdate */ #endif

Listing 3 #include "math.h" #include "setup.h" class UF_control { public: UF_control(Sec ts,V un,Ohm rs,A isNom, RadPerSec fsNom) :Usy(0),theta(0),theta_old(0),Ws(0), Ts(ts); { // same as in listing 1} void update(RadPerSec ref) { // same as in listing 1} V getUsy(){ return Usy; } Rad getTheta(){ return theta; } RadPerSec getWs(){ return Ws; } private: Sec Ts; V Usy,ufoffset; VsecPerRad ufgain; Rad theta, theta_old; RadPerSec Ws; };

Listing 4const long scale_factor=256*256;// 2^16 const long long twoto32=(long long)256*256*256*256;// 2^32 enum init_operator {sum_fix,dif_fix,mul_fix,div_fix}; class Fix_point_number { friend double to_double(const Fix_point_number & fp); public: Fix_point_number(){ value=0;} Fix_point_number(double d){ value = d * (double)scale_factor;} Fix_point_number(long d) { value = d * scale_factor;} Fix_point_number(int d) { value = d * scale_factor;} Fix_point_number(init_operator kind_of,const Fix_point_number & a, const Fix_point_number & b) { switch( kind_of ) {case sum_fix: value = a.value + b.value; break; case dif_fix: value = a.value - b.value; break; case mul_fix: value = (long)(( (long long) a.value * (long long) b.value )/ (long long) scale_factor); break; case div_fix: value = (long)(((((long long)a.value)*twoto32)/(long long)b.value)/ (twoto32/(long long)scale_factor) ); break; } } double getdouble(){ return (double)value / scale_factor; } private: long value; }; Fix_point_number operator+( Fix_point_number a, Fix_point_number b) { return Fix_point_number(sum_fix,a,b); } Fix_point_number operator-( Fix_point_number a, Fix_point_number b) { return Fix_point_number(dif_fix,a,b); } Fix_point_number operator*( Fix_point_number a, Fix_point_number b) { return Fix_point_number(mul_fix,a,b); } Fix_point_number operator/( Fix_point_number a, Fix_point_number b) { return Fix_point_number(div_fix,a,b); } double to_double(const Fix_point_number & fp) { return (double)fp.value / scale_factor; } double to_double(const double & d){ return d;} typedef Fix_point_number Scalar; typedef Fix_point_number V; typedef Fix_point_number A; typedef Fix_point_number Rad; typedef Fix_point_number Sec; typedef Fix_point_number Ohm; typedef Fix_point_number RadPerSec; typedef Fix_point_number VsecPerRad; // und so weiter

Page 6: Object oriented C++ programming in SIMULINK - A reengineered simulation architecture for the control algorithm code view

Listing 5 enum init_operator {sum_op,dif_op,mul_op,div_op}; template<int u1,int u2, int u3, int u4> class Unit { template<int a1,int a2, int a3, int a4> friend class Unit; public: explicit Unit(){ value=0;} explicit Unit(double d){ value = d;} explicit Unit(long d) { value = d ;} explicit Unit(int d) { value = d ;} template<int ua1,int ua2, int ua3, int ua4, int ub1,int ub2, int ub3, int ub4 > Unit(init_operator kind_of, Unit<ua1,ua2,ua3,ua4> a, Unit<ub1,ub2,ub3,ub4> b) { switch( kind_of ) {case sum_op: value = a.value + b.value; break; case dif_op: value = a.value - b.value; break; case mul_op: value = ( a.value * b.value ); break; case div_op: value = a.value / b.value; } } double getdouble(){ return value; } private: double value; }; template<int u1,int u2,int u3,int u4> Unit<u1,u2,u3,u4> operator+( Unit<u1,u2,u3,u4> a, Unit<u1,u2,u3,u4> b) { return Unit<u1,u2,u3,u4>(sum_op,a,b); } template<int u1,int u2,int u3,int u4> Unit<u1,u2,u3,u4> operator-( Unit<u1,u2,u3,u4> a, Unit<u1,u2,u3,u4> b) { return Unit<u1,u2,u3,u4>(dif_op,a,b); } template<int u11,int u12,int u13,int u14, int u21,int u22,int u23,int u24> Unit<u11+u12,u12+u22,u13+u23,u14+u24> operator*( Unit<u11,u12,u13,u14> a, Unit<u21,u22,u23,u24> b ) { return Unit<u11+u12,u12+u22,u13+u23,u14+u24>(mul_op,a,b); } template<int u11,int u12,int u13,int u14> Unit<u11,u12,u13,u14> operator*( Unit<u11,u12,u13,u14> a, double b ) { return Unit<u11,u12,u13,u14>(mul_op,a,Unit<0,0,0,0>(b)); } template<int u11,int u12,int u13,int u14> Unit<u11,u12,u13,u14> operator*( double a, Unit<u11,u12,u13,u14> b ) { return Unit<u11,u12,u13,u14>(mul_op,Unit<0,0,0,0>(a),b); } template<int u11,int u12,int u13,int u14, int u21,int u22,int u23,int u24> Unit<u11-u12,u12-u22,u13-u23,u14-u24> operator/( Unit<u11,u12,u13,u14> a, Unit<u21,u22,u23,u24> b ) { return Unit<u11-u12,u12-u22,u13-u23,u14-u24>(div_op,a,b); } template<int u11,int u12,int u13,int u14> Unit<-u11,-u12,-u13,-u14> operator*(double a,Unit<u11,u12,u13,u14> b ) { return Unit<-u11,-u12,-u13,-u14>(div_op,Unit<0,0,0,0>(a),b); } template<int u11,int u12,int u13,int u14> Unit<u11,u12,u13,u14> operator/( Unit<u11,u12,u13,u14> a, double b ) { return Unit<u11,u12,u13,u14>(div_op,a,Unit<0,0,0,0>(b)); } typedef Unit<0,0,0,0> Scalar; typedef Unit<1,0,0,0> V; typedef Unit<0,1,0,0> A; typedef Unit<0,0,1,0> Rad; typedef Unit<0,0,0,1> Sec; typedef Unit<1,-1,0,0> Ohm; typedef Unit<0,0,1,-1> RadPerSec; typedef Unit<1,0,-1,1> VsecPerRad; // und so weiter

Listing 6 // from UF_control S-function wrapper file: static void mdlInitializeSizes(SimStruct *S) { … nt_T status; DTypeId idRadPerSec; idRadPerSec = ssRegisterDataType(S, "RadPerSec"); if(idRadPerSec == INVALID_DTYPE_ID) { ssPrintf("INVALID_DTYPE_ID"); return; } status = ssSetDataTypeSize(S, idRadPerSec, sizeof(RadPerSec) ); if(status == 0) { ssPrintf("status 0");return;} ssSetInputPortDataType(S, 0, idRadPerSec); … }; #define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) static void mdlUpdate(SimStruct *S, int_T tid) { // retrieve array of input pointers InputPtrsType u = ssGetInputPortSignalPtrs(S,0); // retrieve input parameter RadPerSec speed_reference(*(RadPerSec*)u[0]); // retrieve pointer to C++ object from Simulinks pointer work vector UF_control *UF_control_ptr = (UF_control *) ssGetPWork(S)[0]; // call of the function update in the C++ object UF_control_ptr->update( speed_reference ); } /* End of mdlUpdate */ #endif --------------------------------------------------------- // from rate_limiter S-function wrapper file: static void mdlInitializeSizes(SimStruct *S) { … int_T status; DTypeId idRadPerSec; idRadPerSec = ssRegisterDataType(S, "RadPerSec"); if(idRadPerSec == INVALID_DTYPE_ID) { ssPrintf("INVALID_DTYPE_ID"); return; } status = ssSetDataTypeSize(S, idRadPerSec, sizeof(RadPerSec) ); if(status == 0) { ssPrintf("INVALID_DTYPE_ID");return;} ssSetOutputPortDataType(S, 0, idRadPerSec) … }; static void mdlOutputs(SimStruct *S, int_T tid) { // retrieve pointer to output port signal RadPerSec *Outputptr = (RadPerSec *)ssGetOutputPortSignal(S,0); // retrieve pointer to C++ object from Simulinks pointer work vector rate_limiter *rate_limiter_ptr = (rate_limiter*) ssGetPWork(S)[0]; // call of the C++ objects output function : RadPerSec ref=rate_limiter_ptr->get_rate_limited_value() ; // store it in output signal (*Outputptr) = ref; }