WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
SunSensor.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.
******************************************************************************/
/*
Sun Sensor model header file

Author: James Tabony
*/
/*
Metadata for MS GUI:
imdata = {"displayname" : "Sun Sensor",
          "exclude" : False,
          "category" : "Sensors"
}
aliases = {"pointing_bias" : "EXCLUDE",
           "fov_horizontal" : "Horizontal FOV (degrees)",
           "fov_vertical" : "Vertical FOV (degrees)",
           "mount_frame" : "Spacecraft Body",
           "mount_position__mf" : "EXCLUDE",
           "mount_alignment_mf" : "EXCLUDE",
           "rate_hz" : "EXCLUDE",
           "seed_value" : "RNG Seed",
           "sun_inertial_frame" : "Sun Inertial Frame",
           "primary_inertial_frame" : "Earth Inertial Frame",
           "primary_radius" : "EXCLUDE",
           "latency" : "EXCLUDE",
           "operational_power_draw" : "Operational Power Draw",
           "mass" : "Mass",
           "gaussian_noise" : "One-Sigma Noise (radians)",
           "meas_sun_vector__ss" : "Measured Sun Vector",
           "truth_sun_vector__ss" : "Truth Sun Vector",
           "is_valid" : "Measurement Validity Boolean",
           "current_power_draw" : "Current Power Draw",
}
*/

#ifndef MODELS_SENSORS_SUN_SENSOR_H
#define MODELS_SENSORS_SUN_SENSOR_H

#include "simulation/Model.h"
#include "frames/Frame.h"
#include "models/support/BiasNoiseModel.h"
#include "monitors/RateMonitor.h"
#include "utils/LatencyUtil.hpp"
#include "models/environment/OccultationModel.h"
#include "models/states/FrameStateSensorModel.h"
#include "simulation/UniformRandom.hpp"
#include "simulation/NormalRandom.hpp"

namespace warptwin {

    /**
     * @brief   Model of sun sensor which produces look vector to the sun
     * 
     * TODO: [add description here]

     * Centered in the center of the reference image
     * X is "right" in the image or focal plane horizontal
     * Y is "up" in the image or focal plane veritcal
     * Z is "out" the image completing the right hand frame and represents the boresight
     * 
     * |----------------------|
     * |         y^           |
     * |          |-->x       |
     * |                      |
     * |----------------------|
     * 
     * Author: James Tabony <james.tabony@attx.tech>
     * TODO: Add Albedo Effects (Iff occulting object is in FOV, there is an additional noise term that pulls the sun pointing vector towards the occulter)
    */

    /// @brief Sensor output struct for latency model, its members are the same as the model outputs. Its default constructor populates members with defualt output values 
    struct _sunsensor_output_struct {
        CartesianVector3 meas_sun_vector__ss;
        bool is_valid;
        // Default constuctor (should populate with model defualt outputs)
        _sunsensor_output_struct()
            : meas_sun_vector__ss(CartesianVector3({0.0, 0.0, 0.0})),
              is_valid(false) {}
        // Custom constructor
        _sunsensor_output_struct(CartesianVector3 meas_sun_vector__ss, bool is_valid)
            : meas_sun_vector__ss(meas_sun_vector__ss),
              is_valid(is_valid) {}
    };

    MODEL(SunSensor)
    public:
        // Model params
        //         NAME                     TYPE                    DEFAULT VALUE
        START_PARAMS
            /** The fixed bias of the sun sensor. This could be a mixture of a misalignment error and/or 
             *  measurement noise offset. */
            SIGNAL(pointing_bias,           clockwerk::Quaternion,  clockwerk::Quaternion({1.0, 0.0, 0.0, 0.0}))
            /** The field of view respective to the horizontal of the focal plane. This is defined as full FOV
             *  NOT the half angle measured from boresight. (degrees) */
            SIGNAL(fov_horizontal,          double,                 0.0)
            /** The field of view respective to the vertical of the focal plane. This is defined as full FOV
             *  NOT the half angle measured from boresight. (degrees) */
            SIGNAL(fov_vertical,            double,                 0.0)
            /** The vehicle frame relative to which the sensor is mounted and aligned. This is most
             *  typically the body frame of a spacecraft or other vehicle. mount_position__mf and mount_alignment_mf
             *  are described relative to this frame. */
            SIGNAL(mount_frame,             Frame*,                nullptr)
            /** The position of the sensor relative to the mount frame and resolved in the mount frame. (meters) */
            SIGNAL(mount_position__mf,      CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** The alignment of the sun sensor relative to the mount frame. Rotation from mount frame to sensor frame. */
            SIGNAL(mount_alignment_mf,      clockwerk::Quaternion, clockwerk::Quaternion({1.0, 0.0, 0.0, 0.0}))
            /** The rate at which the sensor generates an output, in hertz. This value must be some
             *  positive (non-zero) integer. (Hz) */
            SIGNAL(rate_hz,                 int,                    0)
            /** Value to seed the internal RNG for this model. */
            SIGNAL(seed_value,              int,                    0)
            /** The inertial frame of the sun. */
            SIGNAL(sun_inertial_frame,      Frame*,                 nullptr)
            /** The inertial frame of the spacecraft's primary orbiter (e.g. Earth). This is used for occultation. */
            SIGNAL(primary_inertial_frame,  Frame*,                 nullptr)
            /** Radius of the primary orbiter, occultation assumes circular cross-sections. Defaults to Earth. (m) */
            SIGNAL(primary_radius,          double,                 warpos::earth_wgs84.eq_radius)
            /** Latency of the sun sensor, millisecond value for the amount of delay in sim time for 
             *  the correct values to be reflected in the outputs. Must be set before executive startup. 
             *  Defaults to no delay. (milliseconds) */
            SIGNAL(latency,                 int,                    0)
            /** Power draw of the sun sensor. This value may or may not be the peak power draw provided by most
             *  data sheets. This value is the expected power draw of a sensor when operational. (Watts) */
            SIGNAL(operational_power_draw,  double,                 0.0)
            /** Mass of the sun sensor. (kg) */
            SIGNAL(mass,                    double,                 0.0)
        END_PARAMS

        // Model inputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_INPUTS
            /** The one-sigma Gaussian noise in sun sensor measurement output described as the error
             *  in angle between true sun-vector and expected sun-vector. This value is provided by
             *  most data sheets and is the same between fine and coarse sun sensors. (radians) */
            SIGNAL(gaussian_noise,          double,                 0.0)
        END_INPUTS

        // Model outputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_OUTPUTS
            /** Output time tied to measurements. Output time is exactly the navigation time
             *  (see SimTimeManager for configuration), without latency (instantaneous) but
             *  but with a rate that mirrors output rate */
            SIGNAL(output_time,             clockwerk::Time,        clockwerk::Time(0, 0))
            /** The "noisy" unit vector representing the direction of the sun relative to the sun
             *  sensor frame in sun sensor frame coordinates. This value is subject to noise, bias, 
             *  dead-zoning, occultation, sensor rate, and latency. */
            SIGNAL(meas_sun_vector__ss,     CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** The "truth" unit vector representing the direction of the sun relative to the sun
             *  sensor frame in sun sensor frame coordinates. This value is NOT subject to noise, bias,
             *  dead-zoning, occultation, or latency; but is subject to sensor rate. */
            SIGNAL(truth_sun_vector__ss,    CartesianVector3,      CartesianVector3({0.0, 0.0, 0.0}))
            /** Boolean value to notify if the output measurement is valid (i.e. boolean for 
             *  blackout-zones). True = not in blackout-zone, False = in blackout-zone. This value is
             *  subject to latency and will line-up with a measurement value. */
            SIGNAL(is_valid,                bool,                   false)
            /** Power draw of the sensor. This value is populated when the model is active, and zero
             *  when the model is deactive. Allows the user to create duty cycles and power budgets. (Watts) */
            SIGNAL(current_power_draw,      double,                 0.0)
        END_OUTPUTS

        /// @brief Accessor for the sensor's frame
        clockwerk::DataIO<Frame*> sensor_frame = clockwerk::DataIO<Frame*>(this, "sensor_frame", &_sensor_frame);

        /// @brief Accessor for the internal bias and noise model
        /// @return Pointer to the bias noise model
        warptwin::BiasNoiseModel* biasNoiseModel() {return &_sensor_noise_model;}

        /// @brief Accessor for the internal rate monitor model
        /// @return Pointer to the rate monitor model
        warptwin::RateMonitor* rateMonitor() {return &_rate_monitor;}

        /// @brief Accessor for the internal occultation model
        /// @return Pointer to the occultation model
        warptwin::OccultationModel* occultationModel() {return &_occult;}

        int16 activate() override;
        int16 deactivate() override;

    protected:
        int16 start() override;
        int16 execute() override;

        /// @brief Function to configure sensor -- runs in all constructors
        void _configureInternal();

        /// @brief The sensor frame in which all measurements will be taken
        Frame _sensor_frame;

        /// @brief The bias and noise model for sensor output.
        BiasNoiseModel _sensor_noise_model;

        /// @brief Rate monitor to control the rate at which the sensor runs
        RateMonitor _rate_monitor;

        /// @brief Occultation model
        OccultationModel _occult;

        /// @brief Model to compute the position of the sun relative to the sun sensor frame
        FrameStateSensorModel _sun_relative_state;

        /// @brief Model to compute the position of the primary orbiter relative to the sun sensor frame
        FrameStateSensorModel _primary_orbiter_relative_state;

        /// @brief Interal model for generating a uniform random number
        UniformRandom<double>* _uniform_random_model = nullptr;

        /// @brief Internal latency model, templated to the sensor output struct
        LatencyUtil<_sunsensor_output_struct> _latency_model;

        /// @brief Temporary variable for the latest recorded output added to latency model and dummy output for stepping though latency
        _sunsensor_output_struct _last_output, _latency_return;

        /// @brief Internal variable for the position of the sun sensor with respect to the sun sensor represented in sun sensor frame coordinates. Zero vector always
        CartesianVector3 _pos_ss_ss__ss = CartesianVector3({0.0, 0.0, 0.0});
        /// @brief Internal variable for the position of the primary orbiter with respect to the sun sensor represented in sun sensor frame coordinates
        CartesianVector3 _pos_PCI_ss__ss;
        /// @brief Internal variable for the position of the Sun with respect to the sun sensor represented in sun sensor frame coordinates
        CartesianVector3 _pos_SCI_ss__ss, _pos_SCI_ss__ss_unit;

        /// @brief Temporary vector used for random rotations
        CartesianVector3 _w;
        /// @brief Temporary angle used for random rotations
        double _theta;
        /// @brief Temporary quaternion used for random rotations
        clockwerk::Quaternion _q;
    };

}

#endif