Program Listing for File gnss_constellation.h

Return to documentation for file (agents/gnss_constellation.h)

#pragma once

#include <filesystem>
#include <map>
#include <vector>

#include "lupnt/agents/constellation.h"
#include "lupnt/agents/gnss_attitude.h"
#include "lupnt/devices/space_comms.h"
#include "lupnt/measurements/antenna.h"
#include "lupnt/numerics/cheby_fit.h"

namespace lupnt {

  struct GnssReceiverParams {
    Real Bp = 1.0;   // [Hz] Carrier loop noise bandwidth
    Real T = 20e-3;  // [s] Tracking loop integration time
    Real b = 2.0;    // [-] Front-end bandwidth factor (B_fe = b * R_c)
    Real Bn = 0.7;   // [Hz] Code loop noise bandwidth
    Real Bf = 0.2;   // [Hz] Frequency loop noise bandwidth
    Real D = 0.1;    // [chip] Early-to-late correlator spacing
  };

  struct GnssOccludingBody {
    Real radius_m = 0.0;             // [m] Body radius
    Vec3 position_m = Vec3::Zero();  // [m] Body center, in the same frame as the
                                     //     satellite/receiver states (e.g. ECI)
  };

  class GnssConstellation : public Constellation {
  public:
    GnssConstellation() = default;

    explicit GnssConstellation(GnssConst gnss_const);

    GnssConstellation(Config& config);

    // ---- Setup --------------------------------------------------------------

    void SetSatelliteStates(const std::vector<int>& prns, const VecXd& t_tai,
                            const std::vector<MatXd>& rv_eci);

    void LoadEphemeris(const std::filesystem::path& filepath);

    void SaveEphemeris(const std::filesystem::path& filepath) const;

    void SetupSatelliteStatesFromFiles(const std::vector<std::filesystem::path>& sp3_filepaths,
                                       const std::filesystem::path& antex_filepath,
                                       const VecXd& t_tai, GnssFreq freq,
                                       const std::vector<int>& prns = {});

    void SetupTransmitters();

    void SetFaultPrns(const std::vector<int>& prns) { fault_prns_ = prns; }
    // ---- Queries --------------------------------------------------------------

    int GetNumSatellites() const { return static_cast<int>(prns_.size()); }
    const std::vector<int>& GetPrns() const { return prns_; }
    GnssConst GetGnssConst() const { return gnss_const_; }
    const std::vector<GnssFreq>& GetFreqList() const { return freq_list_; }

    bool IsFaultPrn(int prn) const;

    Vec6 GetSatelliteStateEci(int prn, Real t_tai) const;

    Real ComputeRange(int prn, const Vec3& r_rx_eci, Real t_tai) const;

    Real ComputeRangeRate(int prn, const Vec6& rv_rx_eci, Real t_tai) const;

    const VecXd& GetEphemerisTimesTai() const { return t_tai_; }

    const MatXd& GetSatelliteStateHistoryEci(int prn) const;

    const ChebyshevFitModel& GetSatelliteStateChebyshevEci(int prn) const;

    bool HasTransmitterInfo(int prn, GnssFreq freq) const;

    const Antenna& GetTransmitterAntenna(int prn, GnssFreq freq) const;

    Real GetTransmitPowerDbw(int prn, GnssFreq freq) const;

    static void ComputeAttitude(const Vec3& r_sat_eci, const Vec3& r_sun_eci, Vec3& ex, Vec3& ey,
                                Vec3& ez) {
      GnssAttitude::Compute(r_sat_eci, r_sun_eci, ex, ey, ez);
    }

    static void ComputeAttitude(const Vec3& r_sat_eci, const Vec3& v_sat_eci, const Vec3& r_sun_eci,
                                Vec3& ex, Vec3& ey, Vec3& ez) {
      GnssAttitude::Compute(r_sat_eci, v_sat_eci, r_sun_eci, ex, ey, ez);
    }

    Real ComputeSigmaRange(Real cn0_dbhz, GnssFreq freq) const;

    Real ComputeSigmaRangeRate(Real cn0_dbhz, GnssFreq freq) const;

    Real ComputeSigmaCarrierPhase(Real cn0_dbhz, GnssFreq freq) const;

    // ---- Constellation interface ------------------------------------------
    // Note: `Constellation::Setup`/`Step` are not virtual; `GnssConstellation`
    // does not populate the base `satellites_` container (its GNSS satellites
    // are represented by precomputed ephemerides + lightweight `GnssTransmitter`
    // metadata rather than full dynamically-propagated `Agent`s), so these
    // hide (rather than override) the base no-op implementations.
    void Setup();
    void Step(Real t);

  private:
    GnssConst gnss_const_ = GnssConst::GPS;
    std::vector<int> prns_;
    std::vector<int> fault_prns_;

    VecXd t_tai_;                                    // [M] ephemeris epochs (TAI seconds)
    std::map<int, MatXd> rv_eci_;                    // PRN -> [M x 6] ECI state history
    std::map<int, ChebyshevFitModel> rv_eci_cheby_;  // PRN -> fitted ECI state model

    std::map<int, std::map<GnssFreq, Antenna>> antennas_;  // PRN -> freq -> antenna pattern
    std::map<int, std::map<GnssFreq, Real>> P_tx_;         // PRN -> freq -> transmit power [dB-W]
    std::vector<GnssFreq> freq_list_;                      // Frequencies available (from PRN 0)

    GnssReceiverParams rx_params_;
  };

}  // namespace lupnt