WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
Spacecraft.h
/******************************************************************************
* Copyright (c) ATTX INC 2025. All Rights Reserved.
*
* This software and associated documentation (the "Software") are the
* proprietary and confidential information of ATTX INC. The Software is
* furnished under a license agreement between ATTX and the user organization
* and may be used or copied only in accordance with the terms of the agreement.
* Refer to 'license/attx_license.adoc' for standard license terms.
*
* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
* transmitted in any form or by any means, for any purpose, without the express
* written permission of ATTX INC.
******************************************************************************/
/*
Spacecraft model header file

Author: Alex Reynolds
*/
/*
Metadata for MS GUI:
imdata = {"displayname" : "Spacecraft",
          "exclude" : False,
          "category" : "Assemblies"
}
aliases = {"initial_position" : "Initial Position",
           "initial_velocity" : "Initial Velocity",
           "pos_vel_init_frame" : "EXCLUDE",
           "initial_attitude" : "Initial Attitude",
           "initial_ang_vel" : "Initial Ang. Vel.",
           "att_init_frame" : "EXCLUDE",
           "planet_configuration" : "Planet Information",
           "planet_inertial_frame" : "Planet Inertial Frame",
           "planet_rotating_frame" : "Planet Rotating Frame",
           "body" : "Spacecraft Body",
           "lvlh" : "Spacecraft LVLH Frame",
           "pos_sc_pci" : "Position",
           "vel_sc_pci" : "Velocity",
           "quat_sc_pci" : "Attitude",
           "ang_vel_sc_pci__body" : "Ang. Vel.",
           "latitude_detic" : "Latitude",
           "longitude" : "Longitude",
           "altitude_detic" : "Altitude",
           "planet_ptr" : "Planet",
           "inertia" : "EXCLUDE",
           "mass" : "Mass"
}
*/

#ifndef MODELS_ASSEMBLIES_SPACECRAFT_H
#define MODELS_ASSEMBLIES_SPACECRAFT_H

#include "core/CartesianVector.hpp"
#include "frames/Body.h"
#include "frames/Node.h"
#include "models/states/FrameStateSensorModel.h"
#include "models/environment/AsphericalGravityModel.h"
#include "models/environment/SphericalHarmonicsGravityModel.h"
#include "models/assemblies/CustomPlanet.h"
#include "models/assemblies/SpicePlanet.h"
#include "models/states/PlanetRelativeStatesModel.h"
#include "models/environment/GravityGradientModel.h"
#include "models/support/LvlhFrameManagerModel.h"
#include "models/actuators/TimedImpulsiveBurnModel.h"
#include "constants/planetdefaults.h"
#include "models/environment/MSISAtmosphereModel.h"
#include "models/actuators/FlatPlateDragModel.h"

namespace warptwin {

    class Executive;

    /**
     * @brief   Spacecraft Model
     *
     * The spacecraft model is a convenient wrapper around a set of high-fidelity
     * models to make building space-based simulation easy. This class is ideal
     * for configuring a simple planet orbiter.
     *
     * Default models wrapped into the spacecraft model include:
     * - Gravity with J2 and J3 effects
     * - Gravity gradient torque
     * - Planet rotating state sensor (latitude/longitude/altitude state)
     * - Earth only: MSIS atmospheric drag
     *
     * Spacecraft comes with two frames
     *
     * To configure spacecraft, users must assign the spacecraft planet_ptr to
     * point to a valid instance of CustomPlanet or SpicePlanet.
    */
    MODEL(Spacecraft)
    public:
        // Model params
        //         NAME                     TYPE                    DEFAULT VALUE
        START_PARAMS
            /** This is the mass of the spacecraft, in the same units as the rest of the
             *  simulation. Default is 1 kg. */
            SIGNAL(mass,                    double,                 1.0)
            /** This is the body inertia tensor of the spacecraft, in the same units as the rest of the
             *  simulation. Default is identity matrix. */
            SIGNAL(inertia,                 Matrix3,               Matrix3({{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}))
            /** The position of the spacecraft in the initialization frame, expressed in init frame.
            Default behavior is to take input in meters. */
            SIGNAL(initial_position,        CartesianVector3,      CartesianVector3({0.0,0.0,0.0}))
            /** The velocity of the spacecraft in the initialization frame, expressed in init frame
                Default behavior is to take input in meters/sec. */
            SIGNAL(initial_velocity,        CartesianVector3,      CartesianVector3({0.0,0.0,0.0}))
            /** The frame in which position and velocity are initialized. If not set, defaults to planet inertial frame */
            SIGNAL(pos_vel_init_frame,      Frame*,                nullptr)
            /** The attitude of the spacecraft relative to the initialization frame. */
            SIGNAL(initial_attitude,        clockwerk::Quaternion, clockwerk::Quaternion({1.0,0.0,0.0,0.0}))
            /** The angular velocity of the spacecraft relative to the initialization frame, expressed
             *  in spacecraft body frame.*/
            SIGNAL(initial_ang_vel,         CartesianVector3,      CartesianVector3({0.0,0.0,0.0}))
            /** The frame in which attitude and angular velocity are initialized. If not set, defaults to planet inertial frame */
            SIGNAL(att_init_frame,          Frame*,                nullptr)
            /** A pointer to the planet object, which may be either CustomPlanet or SpicePlanet.
             *  This variable must be set, and is cast to a planet internally within the spacecraft
             *  model. From the planet, all configuration parameters for gravity and planet relative
             *  state models are set. */
            SIGNAL(planet_ptr,              GraphTreeObject*,       nullptr)
        END_PARAMS

        // Model inputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_INPUTS
        END_INPUTS

        // Model outputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_OUTPUTS
            /** Accessor to the inertial frame of the planet. Set to point to _planet_inertial in constructor. */
            SIGNAL(body,                    Frame*,                nullptr)
            /** Accessor to the rotating frame of the planet. Set to point to _planet_inertial in constructor. */
            SIGNAL(lvlh,                    Frame*,                nullptr)
            /** Position wrt planet centered inertial frame. Default is in meters. */
            SIGNAL(pos_sc_pci,              CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** Velocity wrt planet centered inertial frame. Default is in meters/sec */
            SIGNAL(vel_sc_pci,              CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** Attitude quaternion wrt planet inertial frame */
            SIGNAL(quat_sc_pci,             clockwerk::Quaternion, clockwerk::Quaternion({1.0, 0.0, 0.0, 0.0}))
            /** Angular velocity of the spacecraft wrt planet, output in body frame. In rad/s */
            SIGNAL(ang_vel_sc_pci__body,    CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** The latitude of the spacecraft wrt planet rotating frame, in radians */
            SIGNAL(latitude_detic,          double,                 0.0)
            /** The longitude of the spacecraft wrt the planet rotating frame, in radians */
            SIGNAL(longitude,               double,                 0.0)
            /** The altitude of the spacecraft wrt planet ellipsoid. Default is in meters */
            SIGNAL(altitude_detic,          double,                 0.0)
            /** The total power input from all sources, in Watts */
            SIGNAL(total_power_in,          double,                 0.0)
            /** The total power output from all sources, in Watts */
            SIGNAL(total_power_out,         double,                 0.0)
        END_OUTPUTS

        /// @brief Initialize position and velocity of the spacecraft body frame
        /// @param position_sc_frame__frame The desired position of the spacecraft body wrt frame_ptr
        /// @param velocity_sc_frame__frame The desired velocity of the spacecraft body represented in frame frame_ptr
        /// @param frame_ptr The frame relative to which state is initialized. Default (nullptr) will init wrt sim root frame
        /// @return Error code corresponding to success/failure
        /// @note Overloaded to init via string or frame
        int initializePositionVelocity(CartesianVector3 position_sc_frame__frame,
                                       CartesianVector3 velocity_sc_frame__frame,
                                       Frame* frame_ptr=nullptr);

        /// @brief Initialize position and velocity of the spacecraft body frame
        /// @param position_sc_frame__frame The desired position of the spacecraft body wrt frame_ptr
        /// @param velocity_sc_frame__frame The desired velocity of the spacecraft body represented in frame frame_ptr
        /// @param frame_name The name of the frame relative to which state should be initialized
        /// @return Error code corresponding to success/failure
        /// @note Overloaded to init via string or frame
        int initializePositionVelocity(CartesianVector3 position_sc_frame__frame,
                                       CartesianVector3 velocity_sc_frame__frame,
                                       const std::string &frame_name);

        /// @brief Function to initialize the spacecraftrelative to planet from orbital elements
        /// @param a Semimajor axis, m
        /// @param e Orbit eccentricity
        /// @param i Orbit inclination, radians
        /// @param RAAN Orbit RAAN, radians
        /// @param w Orbit argument of periapsis, radians
        /// @param f Orbit true anomaly, radians
        /// @return Error code corresponding to success/failure
        /// @note Assumes that the spacecraft planet has been set and initializes using orbital elements
        ///       relative to the configured planet.
        /// @note Sets the spacecraft's parent to the planet inertial frame implicitly. Do not use this
        ///       function if you are not ok with that.
        int initializeFromOrbitalElements(double a, double e, double i, double RAAN, double w, double f);

        /// @brief Initialize attitude and angular velocity of the spacecraft body frame
        /// @param quat_sc_frame__frame The desired attitude of the spacecraft body wrt frame_ptr
        /// @param ang_vel_sc_frame__sc The desired angular velocity of the spacecraft body wrt frame_ptr in the sc body frame
        /// @param frame_ptr The frame relative to which state is initialized. Default (nullptr) will init wrt sim root frame
        /// @return Error code corresponding to success/failure
        /// @note Overloaded to init via string or frame
        int initializeAttitude(clockwerk::Quaternion quat_sc_frame__frame,
                               CartesianVector3 ang_vel_sc_frame__sc,
                               Frame* frame_ptr=nullptr);

        /// @brief Initialize attitude and angular velocity of the spacecraft body frame
        /// @param quat_sc_frame__frame The desired attitude of the spacecraft body wrt frame_ptr
        /// @param ang_vel_sc_frame__sc The desired angular velocity of the spacecraft body wrt frame_ptr in the sc body frame
        /// @param frame_name The name of the frame relative to which state should be initialized
        /// @return Error code corresponding to success/failure
        /// @note Overloaded to init via string or frameFrame* frame_ptr=nullptr
        int initializeAttitude(clockwerk::Quaternion quat_sc_frame__frame,
                               CartesianVector3 ang_vel_sc_frame__sc,
                               const std::string &frame_name);

        /// @brief Function to program a timed impulsive burn into the spacecraft
        /// @param delta_v__f The impulsive burn vector to execute
        /// @param time_string Time string in an acceptable SPICE format at which burn should occur
        /// @param force_frame_ptr The frame in which the burn should be executed
        /// @return Pointer to the impulse model
        warptwin::TimedImpulsiveBurnModel* programManeuver(CartesianVector3 delta_v__f,
                                                             std::string time_string,
                                                             Frame* force_frame_ptr);
        /// @brief Function to program a timed impulsive burn into the spacecraft
        /// @param delta_v__f The impulsive burn vector to execute
        /// @param sim_time The time at which the burn should occur
        /// @param force_frame_ptr The frame in which the burn should be executed
        /// @return Pointer to the impulse model
        warptwin::TimedImpulsiveBurnModel* programManeuver(CartesianVector3 delta_v__f,
                                                             double sim_time,
                                                             Frame* force_frame_ptr);

        /// @brief Add a power load to the spacecraft
        /// @param power_load_ptr Pointer to the power load (Watts) to add
        /// @return Error code corresponding to success/failure
        /// @note The value within the DataIOBase pointer must be a double
        int addPowerLoad(clockwerk::DataIO<double>* power_load_ptr);

        /// @brief Clear the list of power loads
        void clearPowerLoads() {_power_load_ptrs.clear();}

        /// @brief Add a power source to the spacecraft
        /// @param power_source_ptr Pointer to the power source (Watts) to add
        /// @return Error code corresponding to success/failure
        /// @note The value within the DataIOBase pointer must be a double
        int addPowerSource(clockwerk::DataIO<double>* power_source_ptr);

        /// @brief Clear the list of power sources
        void clearPowerSources() {_power_source_ptrs.clear();}

        // Accessor for our spacecraft body
        clockwerk::DataIO<Body*> body = clockwerk::DataIO<Body*>(this, "body", &_body);

        // Accessor for our spacecraft lvlh frame
        clockwerk::DataIO<Body*> lvlh = clockwerk::DataIO<Body*>(this, "lvlh", nullptr);

        /// @brief Function to get a handle to the frame state sensor relative to the planet inertial frame
        /// @return Pointer to the planet inertial frame state sensor
        warptwin::FrameStateSensorModel* planetInertialStateSensor() {return &_planet_inertial_state_sensor;}
        /// @brief Function to get a handle to the frame state sensor relative to the planet rotating frame
        /// @return Pointer to the planet rotating frame state sensor
        warptwin::FrameStateSensorModel* planetRotatingStateSensor() {return &_planet_rotating_state_sensor;}
        /// @brief Function to get a handle to the LVLH frame manager contained within this model
        /// @return Pointer to the LVLH frame manager
        warptwin::LvlhFrameManagerModel* lvlhFrameManager() {return &_lvlh_frame_manager;}
        /// @brief Function to get a handle to the aspherical gravity model contained within this model
        /// @return Pointer to the aspherical gravity model
        /// @note Returns nullptr if aspherical gravity is not the active gravity model
        warptwin::AsphericalGravityModel* asphericalGravityModel() {return _asp_ptr;}
        /// @brief Function to get a handle to the spherical harmonics gravity model contained within this model
        /// @return Pointer to the spherical harmonics gravity model
        /// @note Returns nullptr if spherical harmonic gravity is not the active gravity model
        warptwin::SphericalHarmonicsGravityModel* sphericalHarmGravityModel() {return _sph_ptr;}
        /// @brief Function to get a handle to the planet relative state model contained within this model
        /// @return Pointer to the planet relative state sensor model
        warptwin::PlanetRelativeStatesModel* planetRelativeModel() {return &_planet_relative;}
        /// @brief Function to get a handle to the gravity gradient model contained within this model
        /// @return Pointer to the gravity gradient model
        warptwin::GravityGradientModel* gravityGradientModel() {return &_gravity_gradient;}
        /// @brief Function to get a handle to the MSIS atmosphere model contained within this model
        /// @return Pointer to the MSIS atmosphere model
        /// @note Returns nullptr if MSIS atmosphere model is not active
        warptwin::MSISAtmosphereModel* msisModel() {return _msis_ptr;}
        /// @brief Function to get a handle to the flat plate drag model contained within this model
        /// @return Pointer to the flat plate drag model
        warptwin::FlatPlateDragModel* atmosDrag() {return &_atmos_drag;}
    protected:
        int16 start() override;
        int16 execute() override;

        /// @brief Configure the spacecraft class to map to planet
        /// @return Error code corresponding to success/failure
        int _configureFromPlanet();

        /// @brief Function to internally map relationships between sensors
        void _mapInternal();

        /// @brief Sum the power loads and sources to calculate power accumulation
        void _calculatePowerAccumulation();

        // Spacecraft body
        Body _body;
        Node _gravity_node;
        Node _drag_node;

        // Models included within the Spacecraft class
        FrameStateSensorModel _planet_inertial_state_sensor;
        FrameStateSensorModel _planet_rotating_state_sensor;
        LvlhFrameManagerModel _lvlh_frame_manager;
        GravityGradientModel _gravity_gradient;
        PlanetRelativeStatesModel _planet_relative;
        FlatPlateDragModel _atmos_drag;

        // Pointers to models which are declared on the basis of the spacecraft
        // model type
        AsphericalGravityModel* _asp_ptr = nullptr;
        SphericalHarmonicsGravityModel* _sph_ptr = nullptr;
        MSISAtmosphereModel* _msis_ptr = nullptr;

        // Internal signals for the mapping of planet values to spacecraft
        SIGNAL(_mu, double, warpos::earth_wgs84.mu);
        SIGNAL(_eq_radius, double, warpos::earth_wgs84.eq_radius);
        SIGNAL(_flattening, double, warpos::earth_wgs84.flattening);
        SIGNAL(_J2, double, warpos::earth_wgs84.J2);
        SIGNAL(_J3, double, warpos::earth_wgs84.J3);
        std::string _planet_name = "earth";

        // Vector of programmed burn models
        std::vector<TimedImpulsiveBurnModel*> _planned_burn_ptrs;

        // Vector of power loads from components (Watts)
        std::vector<clockwerk::DataIO<double>*> _power_load_ptrs;

        // Vector of power sources from components (Watts)
        std::vector<clockwerk::DataIO<double>*> _power_source_ptrs;
    };

}

#endif