FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
Create a new SimObject

SimObjects are time domain simulation models which are loaded by FhSim at runtime. Herein, a sketch of the procedure for creating a new SimObject is presented. It is practical to use existing implementations as starting point for new developments.

Steps for creating a new SimObject

Suppose you have an existing SimObject library and want to add a new SimObject. To create new SimObject, simply inherit from the SimObject class and implement necessary functions:

  • Create new source and header files, usually by taking an existing SimObject implementation as starting point. The new class should inherit the SimObjectclass, and the header file should include <fhsim/simobject/SimObject.h>.
  • Extend appropriate variables in CMakeLists.txt with the new file names.
  • Add an include directive for your new header file to the SimObject library's module header file and add ADD_SIMOBJECT_REF(<Class name>, <Object reference name>); or ADD_SIMOBJECT_REF3(<Namespace>, <Class name>, <Object reference name>); in the getSimObject function of the corresponding cpp file.
  • Compile and load its configuration using your newly defined object reference name. Build with either cmake --build . --config Release, conan build ., or via your IDE.

    Note
    If your SimObject library is created from the SimObject template tool, the generated project directory contains a DEVELOPING.md file with a step-by-step cheat sheet. See SimObject template tool.

Central methods to implement for a new SimObject

A SimObject can implement a range of methods, some optional and some required:

 SimObject(const string& simObjectName)
 void OdeFcn(double T, const double* X, double* XDot) const
 void InitialConditionSetup(const double T, const double* const currentIC, double* const updatedIC, ISimObjectCreator* const creator)
 void FinalSetup(double T, const double* X, ISimObjectCreator* creator)
 void PreOdeFcn(double T, const double* X, IStateUpdater* updater)
 void AcceptedStep(double T, const double* X)
 bool HasJacobians() const
 void OdeJacobian(double T, const double* X, double* J, int nStates)
 int GetJacobianSparsity(int nStates, int* rowPtr, int* colIdx)
 void RenderInit(Ogre::Root* ogreRoot, ISimObjectCreator* creator)
 void RenderUpdate(double T, const double* X)

The HasJacobians(), OdeJacobian(), and GetJacobianSparsity() methods are optional but enable analytical Jacobian support for implicit integration methods. See Implicit Integration with Analytical Jacobians for details.

Their calling sequence is given in the figure below.

The FhSim call sequence.

Detailed information about these methods and their use is found in:

Minimal SimObject skeleton

The header declares your class and its interface:

#pragma once
#include <fhsim/simobject/SimObject.h>
class CMass : public SimObject
{
public:
CMass(std::string sSimObjectName, ISimObjectCreator* pCreator);
virtual void OdeFcn(const double T, const double* const X,
double* const XDot) const;
protected:
virtual const double* Position(const double T, const double* const X);
virtual const double* Velocity(const double T, const double* const X);
double m_dMass;
ISignalPort* m_pInForce;
};
Class containing a 3dof mass simObjec without gravity.
Definition CMass.h:19
virtual const double * Velocity(const double dT, const double *const adX)
Returns the current velocity state.
int m_IStateVel
The index of the velocity state.
Definition CMass.h:54
virtual const double * Position(const double dT, const double *const adX)
Returns the current position state.
virtual void OdeFcn(const double dT, const double *const adX, double *const adXDot) const
Calculates the state derivatives.
double m_dMass
The mass of the object.
Definition CMass.h:50
int m_IStatePos
The index of the position state.
Definition CMass.h:53
ISignalPort * m_pInForce
A pointer to the input force.
Definition CMass.h:52

The constructor registers ports, states, and reads parameters:

#include "CMass.h"
CMass::CMass(std::string sSimObjectName, ISimObjectCreator* pCreator)
: SimObject(sSimObjectName)
{
// Input ports
pCreator->AddInport("Force", 3, &m_pInForce);
// Output ports (bound to member functions)
pCreator->AddOutport("Pos", 3, PORT_FUNCTION(CMass::Position));
pCreator->AddOutport("Vel", 3, PORT_FUNCTION(CMass::Velocity));
// States
m_IStatePos = pCreator->AddState("Pos", 3);
m_IStateVel = pCreator->AddState("Vel", 3);
// Parameters from XML
pCreator->GetDoubleParam("Mass", &m_dMass);
if (m_dMass <= 0)
pCreator->ReportParameterError("Mass", "Must be greater than zero.");
}
CMass(std::string sSimObjectName, ISimObjectCreator *pCreator)
The constructor sets the pointer to the output object and the parser object.

The OdeFcn computes state derivatives:

void CMass::OdeFcn(const double T, const double* const X,
double* const XDot) const
{
const double* force = m_pInForce->GetPortValue(T, X);
for (int i = 0; i < 3; i++) {
XDot[m_IStatePos + i] = X[m_IStateVel + i]; // dx/dt = v
XDot[m_IStateVel + i] = force[i] / m_dMass; // dv/dt = F/m
}
}

Output port functions return pointers into the state vector:

const double* CMass::Position(const double T, const double* const X)
{
return X + m_IStatePos;
}
const double* CMass::Velocity(const double T, const double* const X)
{
return X + m_IStateVel;
}

Example SimObjects

To better understand the implementation of SimObjects, view the implementation of a linear spring and a mass object. The following files are disclosed:

Note
These two examples keep their historical C-prefixed class names (CLinearSpring, CMass) so their documentation and cross-references stay stable. The C prefix is a legacy FhSim 2.x convention and must not be used for new code — name new SimObjects without it (e.g. LinearSpring, Mass). The examples are illustrative of the SimObject structure, not of current naming style.