Generate C++ Classes for MATLAB Classes That Model Simple and Damped Oscillators
MATLAB® classes provide a natural framework for modeling physical systems:
You can model a simple system as a MATLAB class. The private class properties are the system parameters. The class constructor creates an instance of the system with given parameters. A public method captures the dynamics of the system by returning the final state for a given initial state and a time interval. The class can also contain other helper methods that modularize the mathematical analysis.
You often start your analysis with a simple system and then introduce additional effects (such as mechanical damping) to increase the accuracy of your analysis. In MATLAB, you can model the enhanced system as a subclass that inherits from the original class. The subclass might contain additional private properties for additional system parameters (such as damping constant). Depending on the specifics of the system, the subclass might inherit certain methods from the base class and might overload the other methods.
This example shows how to generate C++ code for a MATLAB function that compares the time evolution of a simple oscillator and a damped oscillator with identical parameters and initial conditions. The two oscillator systems are modeled by using the MATLAB classes simpleOscillator
and dampedOscillator
that are defined inside a MATLAB namespace mySystem
. The generated code contains C++ classes for the source MATLAB classes. The example also shows how the MATLAB classes map to the generated C++ classes and how to use the generated code in a custom C++ main function.
Simple and Damped Oscillators as MATLAB Classes
Governing Equations
A simple harmonic oscillator has two parameters, the mass and the spring constant . The angular frequency of the oscillator is . The position of the oscillator as a function of time is given by:
The amplitude and the phase constant are determined by the initial position and the initial velocity of the simple oscillator. In this example, the MATLAB class simpleOscillator
models this system.
A damped harmonic oscillator has one additional parameter, the damping constant . This example considers the case where the normalized damping parameter is small compared to the angular frequency such that only first-order damping effects are significant. The position of the damped oscillator as a function of time is:
Like before, the amplitude and the phase constant are determined by the initial position and the initial velocity of the damped oscillator. The main effect of damping is to cause the amplitude to decay exponentially. In this example, the MATLAB class dampedOscillator
which is a subclass of simpleOscillator
models the damped system.
MATLAB and C++ Files
This example uses these supporting files that are present in the current working directory:
The namespace folder
+mySystem
contains the two class filessimpleOscillator.m
anddampedOscillator.m
.The function
effectOfDamping
calculates and returns the trajectories of a simple oscillator and a damped oscillator with given parameters and initial conditions.The C++ header and source files
main_damped_oscillator.h
andmain_damped_oscillator.cpp
implement the custom C++ main function and are used to generate an executable in the last part of the example.
Run MATLAB Code
Define a structure params
that has fields for the three oscillator parameters. Make sure the dampingConstant
parameter is small compared to springConstant
and mass
(in normalized units).
params.springConstant = 1; params.dampingConstant = 0.1; params.mass = 1;
Call the effectOfDamping
function to calculate the position vs. time trajectories of the simple and damped oscillators from to . Specify initial position and initial velocity .
[time1,position1,time2,position2] = effectOfDamping(params,1,0,100,0.01);
Plot position vs. time graphs of the simple and damped oscillators. Observe how the amplitude of the damped oscillator decays exponentially with time.
plot(time1,position1)
hold on
plot(time2,position2)
Display the final position of the simple oscillator.
disp(position1(end))
0.8623
Display the final position of the damped oscillator. Observe that damping causes this final position to be close to the mean position .
disp(position2(end))
0.0056
Generate and Run C++ MEX
To check for run-time issues, generate a C++ MEX function for the effectOfDamping
function. Specify the first argument to have the same type and size as params
. Specify the other arguments to be scalar doubles.
codegen -lang:c++ effectOfDamping -args {params,0,0,0,0} -report
Code generation successful: To view the report, open('codegen/mex/effectOfDamping/html/report.mldatx')
Call the generated MEX function effectOfDamping_mex
to calculate the position vs. time trajectories of the simple and damped oscillators from to . Specify initial position and initial velocity .
[time1,position1,time2,position2] = effectOfDamping_mex(params,1,0,100,0.01);
Plot position vs. time graphs of the simple and damped oscillators. Observe that the plot is identical to the one produced by the original MATLAB function.
plot(time1,position1)
hold on
plot(time2,position2)
Display the final positions of the two oscillators. These values are also identical to those produced by the original MATLAB code.
disp(position1(end))
0.8623
disp(position2(end))
0.0056
Clear the MEX file from memory.
clear effectOfDamping_mex
Generate and Inspect Static C++ Library
Create a code configuration object for generating a static C++ library with class interface. Specify the name of the interface class to be 'myOscillators'
. For these settings, the code generator produces the entry-point function as a methods of the C++ class 'myOscillators'
. The constructor and the destructor of this interface class implement the initialize and terminate functions, respectively.
cfg = coder.config('lib'); cfg.TargetLang = 'C++'; cfg.CppInterfaceStyle = 'Methods'; cfg.CppInterfaceClassName = 'myOscillators';
Adjust the global settings for function inlining to:
Preserve the modularity in the code that you wrote for better readability. Set
InlineBetweenUserFunctions
to'Readability'
.Generate highly optimized code for MathWorks® functions, even if that results in less readable code because you are less likely to inspect this part of your code base. Set
InlineBetweenMathWorksFunctions
to'Speed'
.In the generated code, separate functions that you write and MathWorks functions so that the generated code does not look very different from your MATLAB code. Set
InlineBetweenUserAndMathWorksFunctions
to'Readability'
.
cfg.InlineBetweenUserFunctions = 'Readability'; cfg.InlineBetweenUserAndMathWorksFunctions = 'Readability'; cfg.InlineBetweenMathWorksFunctions = 'Speed';
For more information about controlling function inlining behavior of the code generator, see Control Inlining to Fine-Tune Performance and Readability of Generated Code.
Generate a static C++ library by using the codegen
command.
codegen -config cfg effectOfDamping -args {params,0,0,0,0} -report
Code generation successful: To view the report, open('codegen/lib/effectOfDamping/html/report.mldatx')
Open the code generation report and inspect the generated C++ source code:
The files
simpleOscillator.h
andsimpleOscillator.cpp
contain the implementation of the C++ class for the simple oscillator. The filesdampedOscillator.h
anddampedOscillator.cpp
contain the implementation of the C++ class for the damped oscillator. The inheritance structure of the MATLAB classes is flattened in the generated code. So,dampedOscillator
is not a subclass ofsimpleOscillator
and reimplements all the methods that the corresponding MATLAB class inherits. For more information on the mapping between the MATLAB classes and the C++ classes, see Generate C++ Classes for MATLAB Classes.The MATLAB namespace is mapped to a C++ namespace. In the generated code, the
simpleOscillator
anddampedOscillator
classes are defined in themySystem
namespace. For more information, see Organize Generated C++ Code into Namespaces.The files
myOscillators.h
andmyOscillators.cpp
contain the implementation of the interface classmyOscillators
. The entry-point function is implemented in the methodmyOscillators::effectOfDamping
. The initialize and terminate functions are implemented in the class constructor and the class destructor, respectively. The next part of this example shows how to use this class interface in your custom C++ main function. For more information, see Generate C++ Code with Class Interface.The size of output arguments of the
effectOfDamping
function are determined by the run-time inputstimeInterval
andtimeStep
. So, the generated code represents these arguments as dynamic arrays C++ that are implemented by using thecoder::array
class template. The next part of this example shows how to use thecoder::array
class template in your custom C++ main function. For more information, see Use Dynamically Allocated C++ Arrays in Generated Function Interfaces.
For example, here is the declaration of the generated mySystem::simpleOscillator
class contained in the header file simpleOscillator.h
.
type codegen/lib/effectOfDamping/simpleOscillator.h
// // File: simpleOscillator.h // // MATLAB Coder version : 24.2 // C/C++ source code generated on : 05-Sep-2024 13:50:00 // #ifndef SIMPLEOSCILLATOR_H #define SIMPLEOSCILLATOR_H // Include Files #include "rtwtypes.h" #include "coder_array.h" #include <cstddef> #include <cstdlib> // Type Definitions namespace mySystem { class simpleOscillator { public: void init(double m, double k); void evolution(double initialPosition, double initialVelocity, double timeInterval, double timeStep, coder::array<double, 1U> &b_time, coder::array<double, 1U> &position) const; double dynamics(double initialPosition, double initialVelocity, double timeInterval) const; double amplitude(double initialPosition, double initialVelocity) const; double angularFrequency() const; double phase(double initialPosition, double initialVelocity) const; protected: double mass; double springConstant; }; } // namespace mySystem #endif // // File trailer for simpleOscillator.h // // [EOF] //
If you have Embedded Coder®, you can set the VerificationMode
property of the configuration object to 'SIL'
and generate a SIL MEX function effectOfDamping_sil
. This SIL interface allows you to verify the production ready source code inside the MATLAB environment. See Software-in-the-Loop Execution from Command Line (Embedded Coder).
Generate and Run Executable
In the previous part of this example, when you generate library code, the code generator also produces example main files main.h
and main.cpp
in the examples
subfolder of the build folder. The supporting C++ files main_damped_oscillator.h
and main_damped_oscillator.cpp
are modified versions of these example files.
In
main_damped_oscillator.cpp
, themain
function uses the interface classmyOscillators
to interact with the generated code. This function uses the C++new
operator to allocate memory for an instance ofmyOscillators
, invokes themain_effectOfDamping
function, and finally frees the memory by using the C++delete
operator.The
main_effectOfDamping
function performs the same computation that the MATLAB script in the first part of this example does. It uses thecoder::array
API to interact with the dynamic arrays that the generatedeffectOfDamping
function return. At the end of its execution, themain_effectOfDamping
function prints the final positions of the two oscillators.
Create a code configuration object for generating a C++ executable. Use the same settings as in the previous part of this example.
cfg = coder.config('exe'); cfg.TargetLang = 'C++'; cfg.CppInterfaceStyle = 'Methods'; cfg.CppInterfaceClassName = 'myOscillators'; cfg.InlineBetweenUserFunctions = 'Readability'; cfg.InlineBetweenUserAndMathWorksFunctions = 'Readability'; cfg.InlineBetweenMathWorksFunctions = 'Speed';
Specify the custom C++ source file and the custom include folder.
cfg.CustomSource = 'main_damped_oscillator.cpp';
cfg.CustomInclude = {pwd};
Generate an executable by using the codegen
command.
codegen -config cfg effectOfDamping -args {params,0,0,0,0} -report
Code generation successful: To view the report, open('codegen/exe/effectOfDamping/html/report.mldatx')
Run the generated executable. Observe that the final positions of the two oscillators that this execution returns match the outputs of the original MATLAB code.
if isunix system('./effectOfDamping') elseif ispc system('effectOfDamping.exe') else disp('Platform is not supported') end
0.862319 0.00563263
ans = 0