ModelSpace
Documentation for ModelSpace models and classes.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
/******************************************************************************
* 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.
******************************************************************************/
/*
Pressure Sensor model header file

Author: James Tabony
*/
/*
Metadata for MS GUI:
imdata = {"exclude" : True}
*/

#ifndef MODELS_SENSORS_PRESSURE_SENSOR_H
#define MODELS_SENSORS_PRESSURE_SENSOR_H

#include "simulation/Model.h"
#include "models/support/MarkovUncertaintyModel.h"
#include "monitors/RateMonitor.h"
#include "utils/LatencyUtil.hpp"

namespace modelspace {

    /**
     * @brief   Pressure Sensor Model
     * 
     * This model simulates a simple pressure sensor, gathering data from the MSIS
     * atmospheric model or some other external atmosphere model at a specified rate.
     * 
     * HOW DOES THIS MODEL HANDLE NOISE:
     * The typical barometric pressure sensor has some amount of additive noise in the
     * pressure measurement that can be modeled as Gaussian white noise with a standard
     * deviation that is dependent on the oversample ratio (OSR) of the sensors Analog
     * to Digital Converter (ADC). This quantity is often labled as resolution in a data
     * sheet and should not get confused with measurement resolution which is defined as
     * measurement range / bits per measurement.
     * 
     * The typical pressure sensor also has some bias even after factory calibration. This
     * bias is very stable (~mbar/year) so the bias random walk doesn't need to be modeled
     * for the majority of missions that would use a pressure sensor. The bias is constant
     * as a function of time, however it is not constant as a function of temperature. Most
     * pressure sensor data sheets will have different temperature bands where the bias
     * will change.
     * 
     * The majority of pressure sensors operate through an ADC which requires some internal
     * factory calibrated polynomial function to convert the voltage source into a pressure
     * reading. The internal polynomial are subject to manufacturing tolerances. To account
     * for the error in this voltage to pressure conversion, multiplicative error can be used.
     * The percent error should be very small (~0.1%) becuase the additive error is still
     * accounted for.
     * 
     * Typically the noise profile (additive, multiplicative, and biasing) are all dependent
     * on temperature. Because of this, the model has the values as inputs. The user has the
     * choice to repeatedly input new noise characteristics based on an external model, or input
     * them once and it be held constant.
     * 
     * Author: James Tabony <james.tabony@attx.tech>
     * 
     * TODO: Set up sat select
     * TODO: Make model work in GUI
    */

    /// @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 _pressure_output_struct {
        double meas_pressure;
        bool is_valid;
        // Default constuctor (should populate with model defualt outputs)
        _pressure_output_struct()
            : meas_pressure(0.0), is_valid(false) {}
        // Custom constructor
        _pressure_output_struct(double meas_pressure, bool is_valid)
            : meas_pressure(meas_pressure), is_valid(is_valid) {}
    };

    MODEL(PressureSensor)
    public:
        // Model params
        //         NAME                     TYPE                    DEFAULT VALUE
        START_PARAMS
            /** The minimum pressure that the sensor can record. (Pascals) */
            SIGNAL(min_pressure,            double,                 0.0)
            /** The maximum pressure that the sensor can record. (Pascals) */
            SIGNAL(max_pressure,            double,                 0.0)
            /** The measurement resolution. The output value will be some multiple of this value. If the 
             *  value is left at zero, an infinite resolution will be assumed, i.e. no data loss/quantinization. 
             *  From a data sheet, this value can be computed as (measurement range) / 2^(bits per measurement) . (Pascals)  */
            SIGNAL(resolution,              double,                 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)
            /** Latency of the pressure 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 pressure 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 pressure sensor. (kg) */
            SIGNAL(mass,                    double,                 0.0)
        END_PARAMS

        // Model inputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_INPUTS
            /** Local pressure from a atmosphere model, no incorporated noise. (Pascals) */
            SIGNAL(perfect_pressure,        double,                 0.0)
            /** The bias in measurement output described as a double. Default is no bias. 
             *  This value can change with an external model, i.e. temperature effects. (Pascals) */
            SIGNAL(bias,                    double,                 0.0)
            /** The one-sigma gaussian noise in measurement output described as a double. 
             *  Default is no noise. This value can change with en external model, i.e. modeling
             *  temperature effects. (Pascals) */
            SIGNAL(gaussian_noise_std,      double,                 0.0)
            /** The one-sigma scale percent increase/decrease of the measurement. Default is no scaling. */
            SIGNAL(scale_factor_std,        double,                 0.0)
        END_INPUTS 

        // Model outputs
        //         NAME                     TYPE                    DEFAULT VALUE
        START_OUTPUTS
            /** The measured output pressure produced by the pressure sensor describing the 
             *  local pressure of the sensor frame through the configured atmospheric model.
             *  Appropiate bias, noise, scaling, rate limiting, deadzoning, and resolution
             *  applied. The model outputs zero when in the blackout zone. (Pascals) */
            SIGNAL(meas_pressure,           double,                 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. */
            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 internal noise model
        /// @return Pointer to the internal noise model
        modelspace::MarkovUncertaintyModel* getNoiseModel() {return &_sensor_noise_model;}

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

        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 bias and noise model for sensor output.
        MarkovUncertaintyModel _sensor_noise_model;

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

        /// @brief Temporary variable to hold the measured pressure before bound
        /// checks and reolution quantinization
        double _meas_pres;

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

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

    };

}

#endif