Generate and Use C++ Classes from Entry-Point Classes That Model a Physical System (Tech Preview)
This example shows how to generate C++ classes for two entry-point MATLAB® classes. The entry points consist of a base class that represents a simple oscillator and a subclass that adds mechanical damping to the simple oscillator. This example also shows how to use the generated C++ classes in your custom C++ main function and then build an executable.
Note
Using a MATLAB® class as an entry point for code generation is a tech preview. This
feature is in active development and may change between the tech preview and the general
release. The primary purpose of the tech preview is to solicit feedback from users. To
enable the feature, enter enableCodegenForEntryPointClasses at the
command line before calling the codegen function or creating a coder.Type object in a MATLAB session. To provide feedback, email the
development team or participate
in a survey.
Generate C++ Classes That Model Simple and Damped Oscillators
When you use a MATLAB class to represent a physical system, you can:
Specify the system parameters by using private class properties.
Create an instance of the system by using the class constructor.
Capture the time evolution of the system by using a public method that returns the trajectory of the system for a given initial state.
Modularize the mathematical analysis by creating private or protected helper methods.
When you model a physical system, you often begin 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 simple system as a base class and model the enhanced system as a subclass that inherits from the base class. The subclass can define private properties for additional system parameters. Additionally, the subclass can inherit certain methods from the base class and can overload the other methods.
Examine the Oscillator Base Class
A simple harmonic oscillator has two parameters, the mass and the spring constant . The angular frequency of the oscillator is . This equation defines the position of the oscillator as a function of time :
The initial position and initial velocity determine the amplitude and the phase constant .
Examine the MATLAB class simpleOscillator. This class models a one-dimensional simple harmonic oscillator in the MATLAB namespace mySystem. This class has two properties, mass and springConstant. The dynamics method returns the final position of the oscillator after a specified time interval. To evolve the system over a specified number of time steps, the evolution method calls the dynamics method iteratively.
type +mySystem/simpleOscillator.mclassdef simpleOscillator
properties (SetAccess = private, GetAccess = protected)
mass
springConstant
end
methods
function obj = simpleOscillator(m,k)
obj.mass = m;
obj.springConstant = k;
end
function [time,position] = evolution(obj,initialPosition,initialVelocity,timeInterval,timeStep)
numSteps = floor(timeInterval/timeStep);
position = zeros(numSteps + 1,1);
time = zeros(numSteps + 1,1);
position(1) = initialPosition;
for i = 1:numSteps
currentTime = i*timeStep;
position(i+1) = obj.dynamics(initialPosition,initialVelocity,currentTime);
time(i+1) = currentTime;
end
end
end
methods (Access = protected)
function omega = angularFrequency(obj)
omega = sqrt(obj.springConstant/obj.mass);
end
function amplitudeValue = amplitude(obj,initialPosition,initialVelocity)
omega = obj.angularFrequency;
positionSquared = initialPosition^2;
velocityTerm = (initialVelocity / omega)^2;
amplitudeValue = sqrt(positionSquared + velocityTerm);
end
function phi = phase(obj,initialPosition,initialVelocity)
omega = obj.angularFrequency;
phi = atan2(omega*initialPosition,initialVelocity);
end
function finalPosition = dynamics(obj,initialPosition,initialVelocity,timeInterval)
omega = obj.angularFrequency;
amplitudeValue = obj.amplitude(initialPosition, initialVelocity);
phi = obj.phase(initialPosition,initialVelocity);
finalPosition = amplitudeValue*sin(omega*timeInterval+phi);
end
end
end
Examine the Damped Oscillator Subclass
To model the effects of mechanical damping on a harmonic oscillator, you need one additional parameter, the damping constant . The equation represents the damping parameter. Because the damping parameter is small compared to the angular frequency , only the first-order damping effects are significant. The position of the damped oscillator as a function of time is:
.
Like the simple oscillator, the initial position and initial velocity determine the amplitude and the phase constant . The damping constant causes the amplitude to decay exponentially.
Examine the MATLAB class dampedOscillator. This class is a subclass of the simpleOscillator base class and is in the MATLAB namespace mySystem. The dampedOscillator subclass has one additional property compared to the simpleOscillator base class, dampingConstant. The subclass overloads the phase and dynamics methods to include the effects of damping and defines an additional method, dampingParameter, that calculates the normalized damping parameter in the dynamical equation.
type +mySystem/dampedOscillator.mclassdef dampedOscillator < mySystem.simpleOscillator
properties (SetAccess = private, GetAccess = protected)
dampingConstant
end
methods
function obj = dampedOscillator(m,b,k)
obj@mySystem.simpleOscillator(m,k);
obj.dampingConstant = b;
end
end
methods (Access = protected)
function gamma = dampingParameter(obj)
gamma = obj.dampingConstant/(2*obj.mass);
end
function phi = phase(obj,initialPosition,initialVelocity)
omega = obj.angularFrequency();
gamma = obj.dampingParameter();
phi = atan2(omega*initialPosition,initialVelocity+gamma*initialPosition);
end
function finalPosition = dynamics(obj,initialPosition,initialVelocity,timeInterval)
gamma = obj.dampingParameter();
omega = obj.angularFrequency();
amplitudeValue = obj.amplitude(initialPosition, initialVelocity);
phi = obj.phase(initialPosition, initialVelocity);
expDecay = exp(-gamma * timeInterval);
finalPosition = amplitudeValue*expDecay*sin(omega*timeInterval+phi);
end
end
end
Run MATLAB Script That Uses The Oscillator Classes
Specify the parameters for the simple and damped oscillators in normalized units.
springConstant = 1; dampingConstant = 0.1; mass = 1;
Create a simple oscillator object with this spring constant and mass. Evolve this oscillator from an initial position of 1 and an initial velocity of 0. Specify the time period to be 100 and the time step to be 0.01.
myOscillator = mySystem.simpleOscillator(springConstant,mass); [time_simple,position_simple] = myOscillator.evolution(1,0,100,0.01);
Create a damped oscillator object with these parameters. Evolve this oscillator from the same initial state as the simple oscillator over the same time period and by using the same time step.
myDampedOscillator = mySystem.dampedOscillator(springConstant,dampingConstant,mass); [time_damped,position_damped] = myDampedOscillator.evolution(1,0,100,0.01);
Plot the position of each oscillator over time. Observe that the amplitude of the damped oscillator decays exponentially with time.
plot(time_simple,position_simple)
hold on
plot(time_damped,position_damped)
Display the final position of the simple oscillator.
disp(position_simple(end))
0.8623
Display the final position of the damped oscillator. Damping causes the final position of this oscillator to be closer to the mean position, 0.
disp(position_damped(end))
0.0056
Generate C++ Classes for Entry-Point Classes
If you enable the classes as entry points tech preview, you can use a MATLAB value class or handle class as an entry point for standalone code generation. You can access the generated C or C++ representation of the class directly from your custom C or C++ code. The class interface remains stable, even if you change the way the class is used in the MATLAB code. So, you can rely on the generated interface for use with custom C or C++ code.
First, enable code generation for entry-point classes.
enableCodegenForEntryPointClasses
=== Code generation for entry-point classes is ENABLED === For a feature overview and example usage, see the R2026a pre-release Release Notes. To send feedback or questions directly to the development team, email entrypointclassfeedback@groups.mathworks.com or click here to take survey.
Create a coder.ClassSignature object for the mySystem.simpleOscillator class. Use the addMethod object function to specify the public methods that you want to be present in the generated C++ class.
classSig1 = coder.ClassSignature("mySystem.simpleOscillator"); addMethod(classSig1,"simpleOscillator",{0,0}); addMethod(classSig1,"evolution",{classSig1,0,0,0,0});
Create class signature object for the mySystem.dampedOscillator class. Use the addMethod object function to specify the public methods that you want to be present in the generated C++ class.
classSig2 = coder.ClassSignature("mySystem.dampedOscillator"); addMethod(classSig2,"dampedOscillator",{0,0,0}); addMethod(classSig2,"evolution",{classSig2,0,0,0,0});
Create a code configuration object for generating executable code:
Set the target language to C++.
Optimizations in the code generation process can result in the inlining of the protected methods in the generated C++ classes. For this example, prevent the code generator from inlining these methods by setting the
InlineBetweenUserFunctionsproperty to"Never".
Generate code for the two entry-point classes by using the codegen command with the -class option. Because you must examine the generated source code before you can create your custom main function, use the -c option with the codegen command. This option that instructs the code generator to produce only the source code.
cfg = coder.config("exe"); cfg.TargetLang = "C++"; cfg.InlineBetweenUserFunctions = "Never"; codegen -c -config cfg -class classSig1 -class classSig2 -report
Code generation successful: To view the report, open('codegen\exe\mySystem_simpleOscillator\html\report.mldatx')
Examine Generated C++ Classes
Open the code generation report and inspect the declarations of the C++ classes mySystem::simpleOscillator and mySystem::dampedOscillator in the generated header files. Because the generated code does not preserve the inheritance structure of the MATLAB class and subclass, dampedOscillator is not a subclass of simpleOscillator. Instead, the dampedOscillator class reimplements the methods that the corresponding MATLAB class inherits.
file = fullfile("codegen","exe","mySystem_simpleOscillator","mySystem_simpleOscillator.h"); coder.example.extractLines(file,"namespace mySystem {","#endif",1,0)
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;
simpleOscillator(double m, double k);
simpleOscillator();
~simpleOscillator();
protected:
double dynamics(double initialPosition, double initialVelocity,
double timeInterval) const;
double angularFrequency() const;
double amplitude(double initialPosition, double initialVelocity) const;
double phase(double initialPosition, double initialVelocity) const;
private:
double mass;
double springConstant;
};
} // namespace mySystem
file = fullfile("codegen","exe","mySystem_simpleOscillator","mySystem_dampedOscillator.h"); coder.example.extractLines(file,"namespace mySystem {","#endif",1,0)
namespace mySystem {
class dampedOscillator {
public:
void init(double m, double b, double k);
void evolution(double initialPosition, double initialVelocity,
double timeInterval, double timeStep,
coder::array<double, 1U> &b_time,
coder::array<double, 1U> &position) const;
dampedOscillator(double m, double b, double k);
dampedOscillator();
~dampedOscillator();
protected:
double dynamics(double initialPosition, double initialVelocity,
double timeInterval) const;
double dampingParameter() const;
double angularFrequency() const;
double amplitude(double initialPosition, double initialVelocity) const;
double phase(double initialPosition, double initialVelocity) const;
private:
void b_simpleOscillator(double m, double k);
double mass;
double springConstant;
double dampingConstant;
};
} // namespace mySystem
Examine C++ main function That Uses Generated C++ Classes
Examine the main_oscillators.cpp file that contains a C++ main function that uses the generated classes mySystem::simpleOscillator and mySystem::dampedOscillator. This function performs the same computation as the MATLAB script you ran at the beginning of this example. The main function uses the coder::array API to interact with the dynamic arrays that the generated evolution methods return. At the end of its execution, the main function prints the final positions of the two oscillators.
type main_oscillators.cpp#include "mySystem_simpleOscillator.h"
#include "mySystem_dampedOscillator.h"
#include "coder_array.h"
#include <cstddef>
#include <cstdlib>
#include <iostream>
int main(int, const char * const [])
{
coder::array<double, 1U> position1;
coder::array<double, 1U> position2;
coder::array<double, 1U> time1;
coder::array<double, 1U> time2;
double springConstant = 1;
double dampingConstant = 0.1;
double mass = 1;
mySystem::simpleOscillator obj1(mass,springConstant);
mySystem::dampedOscillator obj2(mass,dampingConstant,springConstant);
obj1.evolution(1, 0, 100, 0.01, time1, position1);
obj2.evolution(1, 0, 100, 0.01, time2, position2);
std::cout << position1[position1.size(0) - 1] << std::endl;
std::cout << position2[position2.size(0) - 1] << std::endl;
return 0;
}
Generate and Run C++ Executable
Generate C++ executable named myExe. To the configuration object cfg you created when generating only the source code, add the name of the custom C++ source file you created.
cfg.CustomSource = "main_oscillators.cpp"; codegen -config cfg -class classSig1 -class classSig2 -o myExe -report
Code generation successful: To view the report, open('codegen\exe\myExe\html\report.mldatx')
Run the generated executable. Verify that the output matches the output of your original MATLAB script.
if isunix system('./myExe'); elseif ispc system('myExe.exe'); else disp('Platform is not supported'); end
0.862319 0.00563263
See Also
coder.ClassSignature | addMethod | codegen | coder.config