Skip to content

Type System

Astrea's type system provides dimensional safety for astrodynamics calculations through compile-time unit checking using the mp-units library. The system ensures unit consistency while maintaining zero runtime overhead.

Design Philosophy

1. Unit Safety

  • Dimensional Analysis: Prevent unit mismatch errors at compile-time
  • Natural Expressions: Code reads like mathematical equations
  • Zero Cost: No runtime performance penalty for type safety
  • Clear Errors: Helpful compiler messages for unit mismatches

2. Practical Design

  • Standard Units: Built on SI base units with aerospace-specific extensions
  • Simple API: Straightforward type definitions for common quantities
  • Extensible: Easy to add new quantity types as needed

Core Type Definitions

Physical Quantities

Astrea defines aerospace-specific quantities as type aliases over mp-units:

namespace astrea {
    // Basic quantities
    using Distance = mp_units::quantity<detail::distance_unit>;        // kilometers
    using Length = mp_units::quantity<detail::minor_distance_unit>;    // meters
    using Time = mp_units::quantity<detail::time_unit>;               // seconds
    using Angle = mp_units::quantity<detail::angle_unit>;             // radians
    using Velocity = mp_units::quantity<detail::distance_unit / detail::time_unit>;
    using Mass = mp_units::quantity<detail::mass_unit>;               // kilograms
    using Unitless = mp_units::quantity<detail::unitless>;            // dimensionless

    // Derived astrodynamics quantities
    using GravParam = mp_units::quantity<mp_units::pow<3>(detail::distance_unit) / 
                                        mp_units::pow<2>(detail::time_unit)>;
    using Acceleration = mp_units::quantity<detail::distance_unit / 
                                           mp_units::pow<2>(detail::time_unit)>;
    using AngularRate = mp_units::quantity<detail::angle_unit / detail::time_unit>;

    // Specialized quantities
    using Thrust = mp_units::quantity<detail::mass_unit * detail::distance_unit / 
                                     mp_units::pow<2>(detail::time_unit)>;
    using SpecificAngularMomentum = mp_units::quantity<detail::distance_unit * 
                                                      detail::distance_unit / detail::time_unit>;
}

Unit System Details

The underlying unit definitions use mp-units with SI base units optimized for astrodynamics:

namespace astrea::detail {
    // Base units optimized for aerospace calculations
    inline constexpr auto time_unit           = mp_units::si::unit_symbols::s;     // seconds
    inline constexpr auto distance_unit       = mp_units::si::unit_symbols::km;    // kilometers  
    inline constexpr auto minor_distance_unit = mp_units::si::unit_symbols::m;     // meters
    inline constexpr auto angle_unit          = mp_units::angular::unit_symbols::rad; // radians
    inline constexpr auto mass_unit           = mp_units::si::unit_symbols::kg;    // kilograms
    inline constexpr auto unitless            = mp_units::one;                     // dimensionless
}

Type-Safe Calculations

The unit system prevents common astrodynamics errors:

// This compiles and produces correct results
auto orbital_velocity(Distance radius, GravParam mu) {
    return sqrt(mu / radius);  // Returns Velocity quantity automatically
}

// This fails to compile - unit mismatch detected
auto invalid_calculation(Distance radius, Time time) {
    return radius + time;  // ERROR: Cannot add distance and time
}

// Automatic unit conversions where appropriate
Distance altitude = 400.0 * astrea::detail::distance_unit;  // 400 km
Length precise_alt = altitude;  // Automatic conversion to meters: 400,000 m

State Representation

Orbital Elements

Astrea provides multiple orbital element representations through a unified interface:

namespace astrea::astro {
    // Base orbital elements interface
    class OrbitalElements {
        // Virtual interface for different element types
    };

    // Concrete implementations
    class Keplerian {
        Distance _semimajor;      // Semi-major axis
        Unitless _eccentricity;   // Eccentricity
        Angle _inclination;       // Inclination
        Angle _rightAscension;    // RAAN
        Angle _argPerigee;        // Argument of perigee
        Angle _trueAnomaly;       // True anomaly

    public:
        Keplerian(const Distance& a, const Unitless& e, const Angle& i,
                 const Angle& raan, const Angle& argp, const Angle& nu);

        // Conversion from other element types
        Keplerian(const OrbitalElements& elements, const GravParam& mu);
    };

    class Cartesian {
        // Position and velocity vectors
    };

    class Equinoctial {
        // Modified equinoctial elements for near-circular orbits
    };
}
### State Management

The `State` class combines orbital elements with epoch and system information:

```cpp
namespace astrea::astro {
    class State {
        OrbitalElements _elements;
        Date _epoch;
        const AstrodynamicsSystem* _system;

    public:
        State(const OrbitalElements& elements, const Date& epoch, 
              const AstrodynamicsSystem& sys);

        const OrbitalElements& get_elements() const { return _elements; }
        const Date& get_epoch() const { return _epoch; }
        const AstrodynamicsSystem& get_system() const { return *_system; }

        // Element conversion while preserving epoch and system
        template<typename ElementType>
        State convert_to() const;
    };
}

    template<typename Frame = frames::ICRF, typename TimeScale = TT>
    using KeplerianState = State<Keplerian, Frame, TimeScale>;
}

Time Handling

Date Class

Astrea uses a simplified Date class for time management:

namespace astrea::astro {
    class Date {
        JulianDate julian_date_;

    public:
        Date();  // Defaults to J2000.0 epoch
        explicit Date(const JulianDate& jd);

        // Time arithmetic
        Date operator+(const Time& duration) const;
        Date operator-(const Time& duration) const;
        Time operator-(const Date& other) const;

        // Conversions
        JulianDate get_julian_date() const { return julian_date_; }
        std::string to_string(const std::string& format = "%Y-%m-%d %H:%M:%S") const;
    };

    // Utility functions
    JulianDate epoch_to_julian_date(const std::string& epoch, 
                                   const std::string format = "%Y-%m-%d %H:%M:%S");
}

Coordinate Vectors

Typed Vector System

Astrea provides type-safe vector representations:

namespace astrea::astro {
    // Template for typed vectors in specific frames
    template<typename Quantity, typename Frame>
    class CartesianVector {
        std::array<Quantity, 3> components_;

    public:
        // Component access
        Quantity x() const { return components_[0]; }
        Quantity y() const { return components_[1]; }  
        Quantity z() const { return components_[2]; }

        // Vector operations
        auto magnitude() const -> Quantity;
        auto normalize() const -> CartesianVector<Unitless, Frame>;
    };

    // Common vector type aliases
    template<typename Frame>
    using RadiusVector = CartesianVector<Distance, Frame>;

    template<typename Frame>
    using VelocityVector = CartesianVector<Velocity, Frame>;

    template<typename Frame>
    using AccelerationVector = CartesianVector<Acceleration, Frame>;

    template<typename Frame>
    using UnitVector = CartesianVector<Unitless, Frame>;
}

Frame Instances

The actual frame types implemented in Astrea:

namespace astrea::astro::frames {
    // Local coordinate frames
    struct EastNorthUp {};        // East-North-Up topocentric frame
    struct LocalHorizontal {};    // Local horizontal frame
    struct RadialInTrackCrossTrack {};  // RIC frame for relative motion
    struct VelocityNormalBinormal {};   // VNB orbital frame

    // Inertial frames (body-centered)
    struct EarthCenteredInertial {};    // ECI frame
    struct MoonCenteredInertial {};     // Selenocentric inertial

    // Body-fixed frames
    struct EarthFixed {};               // ECEF-type frame
}

Example Usage

Complete Orbit Definition

// Create orbital state with type safety
Distance sma = 7000.0 * astrea::detail::distance_unit;     // 7000 km
Unitless ecc = 0.1 * astrea::detail::unitless;             // 0.1 eccentricity  
Angle inc = 45.0 * astrea::detail::angle_unit;             // 45 degrees

auto elements = astrea::astro::Keplerian(
    sma, ecc, inc, 
    0.0 * astrea::detail::angle_unit,  // RAAN
    0.0 * astrea::detail::angle_unit,  // Argument of perigee
    0.0 * astrea::detail::angle_unit   // True anomaly
);

auto epoch = astrea::astro::Date();  // J2000.0
auto system = astrea::astro::AstrodynamicsSystem();  // Earth-Moon system
auto state = astrea::astro::State(elements, epoch, system);

// Type-safe element conversions
auto cartesian_elements = astrea::astro::Cartesian(elements, system.get_mu());

Gravitational Parameter Calculations

// Type-safe orbital mechanics calculations
auto calculate_orbital_period(Distance semi_major_axis, GravParam mu) -> Time {
    // Kepler's third law calculation with automatic unit checking
    auto period_squared = 4.0 * M_PI * M_PI * mp_units::pow<3>(semi_major_axis) / mu;
    return sqrt(period_squared);
}

// Usage example
auto earth_mu = 398600.4418 * mp_units::pow<3>(astrea::detail::distance_unit) / 
                             mp_units::pow<2>(astrea::detail::time_unit);
auto period = calculate_orbital_period(sma, earth_mu);  // Returns Time quantity

Performance Characteristics

Zero Runtime Overhead

The type system adds no runtime cost:

// Type information is compile-time only
static_assert(sizeof(Distance) == sizeof(double));
static_assert(sizeof(astrea::astro::Keplerian) == 6 * sizeof(mp_units::quantity<double>));

// No virtual function overhead in quantity types
static_assert(std::is_trivially_copyable_v<Distance>);
static_assert(std::is_trivially_copyable_v<Velocity>);

Compile-Time Benefits

  • Error Prevention: Unit mismatches caught at compile-time
  • Optimization: Compilers can optimize knowing exact types
  • Documentation: Types serve as self-documenting code
  • Refactoring Safety: Type checking prevents breaking changes

Integration with mp-units

Astrea leverages the mp-units library for its foundation:

  • Standards Compliance: Based on SI units and ISO standards
  • Performance: Zero-runtime-cost with compile-time checking
  • Extensibility: Easy to add domain-specific quantities
  • Interoperability: Compatible with standard mathematical operations

Astrea's type system provides practical dimensional safety for astrodynamics while maintaining the performance characteristics required for mission-critical applications.