menu
info Documentation

Custom Model Development

A model object in D2S2 is an instance of a class, where that class confirms to a specific type or interface, as required by the parent model object to which it is assigned.

A user-coded model can inherit from any of the existing classes in the D2S2.Model namespace, to override or extend the functionality of it.

The main code parts of a custom model class is:

  • private members
  • public members visible to the user interface
  • initialisation
  • kinetic feedback functions
  • update functions

Creating a Custom Satellite Component

The most common use of custom model development is to implement simulation models for custom payloads or satellite components where there is no built-in equivalent or additional functionality is needed. A template structure of a new satellite component can be seen below. The generic Electrical Power System is used as an example.

namespace D2S2.Model.Satellite
{
    public class ElectricalPowerSystem : SatellitePhysicalComponent, IInitialisable
    {
        // private members
        // properties for dependent object binding
        // read-only properties for exposing model state
        // adjustable/input properties

        public ElectricalPowerSystem()
        {}

        public void Initialise(DateTime time)
        {}

        public override Vector3d GetForce(SatelliteEnvironmentState environment)
        {return Vector3d.Zero;}

        public override Vector3d GetTorque(SatelliteEnvironmentState environment)
        {return Vector3d.Zero;}

        public override void UpdateEnvironment(DateTime time, SatelliteEnvironmentState environment, SatelliteKinematicState state, SurfaceModel surfaceModel)
        {}

        public override void UpdateEnd(TimeSpan timeDelta)
        {}
    }
}

Base Inheritance

D2S2 uses types to define which model objects may be used at various dependency points in the model. It is thus required to either inherit from the appropriate base class, or to implement a required interface. In the example above the Electrical Power System inherits from SatellitePhysicalComponent which is the class that contains the fundamental physical parameters for a component that can be attached to a satellite. This is suitable for majority of custom components.

Other options are SatelliteElectricalComponent which is an extention of the SatellitePhysicalComponent which requires the custom component to also implement functions that define its power usage.

Private Members

Similar to any class, private variables are used to store state or settings internal to the model. The member variables needed by the example EPS class is

private double powerIn = 0.0;
private double powerOut = 0.0;

private double currentBatteryPower = 0.0;
private double initialBatteryPower = 0.0;
private double maximumPowerStorage = 22.5;
private double powUsage = 0;

Dependencies

Model objects can be linked to one another creating a dependency. In the example there are two dependency lists:

private ModelList<D2S2.Model.Satellite.SolarPanel> solarPanels;
private ModelList<D2S2.Model.Satellite.SatelliteElectricalComponent> consumers;

[ModelDependency(DependencyType.Link, false)]
[Description("List of all power generating components")]
public ModelList<D2S2.Model.Satellite.SolarPanel> SolarPanels { get { return solarPanels; } }

[ModelDependency(DependencyType.Link, false)]
[Description("List of all power consuming components")]
public ModelList<D2S2.Model.Satellite.SatelliteElectricalComponent> PowerConsumers { get { return consumers; } }

One of the defined dependencies is for a list of all solar panels in the simulation and another of all components that will use power from the Electrical Power System. This is done by creating a private member list of a certain class. These dependencies can then be used to gain access to change the state or gain information from other models in the simulation. Dependencies are indicated in the scenario files.

The SolarPanels and PowerConsumers dependencies above are examples of Link type dependencies. It is allowed to assign existing model objects to these dependencies, but the EPS does not 'own' these dependent objects. Owner type dependencies require that a new simulation object is created prior to assigning it. Removing an Owner type dependent object will also delete it. The type of dependency, Link or Owner is spcified using the ModelDependency attribute. The second argument to this attribute is a boolean parameter indicating if the dependency must be assigned before the model may be run (it will result in a model validation error otherwise).

Public Parameters

Each model can have multiple public parameters. These are the values that can be changed or read by the user interface. These are created by defining a public property with at least get access:

[ModelValue(ModelValueType.State)]
[DisplayName("Generated Power")]
[Description("Total power generated [W]")]
[Category("Measurement")]
public UDouble<W> PowerInUnit { get { return new UDouble<W>(powerIn); } }

[ModelValue(ModelValueType.Initial)]
[DisplayName("Maximum Energy Storage")]
[Category("Battery Settings")]
[Description("Maximum energy storage capacity of batteries [W.hr]")]
public double MaximumPowerStorage
{ 
    get
    {
        return maximumPowerStorage; 
    }
    set
    {
        maximumPowerStorage = value;
        OnPropertyValueChanged(GetProperty((ElectricalPowerSystem m) => m.MaximumPowerStorage));
    }
}

The ModelValue attribute defines the type of property. ModelValueType can be one of the following:

  1. Initial - these are properties that can be set by the user, or other model objects, to change the model behaviour. Initial properties can only be changed if the simulation is in reset state.
  2. Input - these are properties that can be set by the user, or other model objects, to change the model behaviour. Input properties can be changed while the simulation is already underway.
  3. State - these are read-only properties (get access only) that report the state of the model
  4. Statistic - these are read-only properties (get access only) that report the state of the model. This is typically used for states where only the final value is important.

DisplayName and Description Attributes

Properties may be decorated using DisplayName and Description attributes. The display name and descrption defined here will be presented to the user in the UI, and can be used for user-friendly property names.

The DisplayName and Description attributes can also be applied to the model class itself.

Initialisation

The Initialise function is a required function from the IInitialisable base interface and can be used to initialise the internal state of the model..

Force and Torque Functions

The base SatellitePhysicalComponent class has virtual methods for GetForce() and GetTorque(). The values that are returned by these methods will influence the attitude and orbit dynamics of the satellite. Custom models that inherit from SatellitePhysicalComponent can override these methods to simulate the spacecraft dynamics effect that payloads may have.

Update Functions

The logic or custom function that the model object must fulfil is usually contained in an Update method. In the case of the SatelliteComponent base class, there are three such methods which may be overridden in inheriting classes.

void UpdateEnvironment(DateTime time, SatelliteEnvironmentState environment, SatelliteKinematicState state, SurfaceModel surfaceModel)

void Update(TimeSpan timeDelta)

void UpdateEnd(TimeSpan timeDelta)

All components in the satellite will have their UpdateEnvironment method called initially. Following this, the Update method for all components will be called, and finally all components' UpdateEnd method will be called. The sequence makes it useful to control the order of actions, especially where satellite components interact with each other and the order in which component update methods are called are not guaranteed. It is up to the developer to best decide how to use these methods for custom logic.

The complete code of the generic ElectricalPowerSystem can be found here.