mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-08-09 19:58:53 +00:00
Implement QZSS LNAV almanac/auxiliary pages decoding, add unit tests
This commit is contained in:
@@ -781,7 +781,9 @@ alm_t alm_to_rtklib(const Gps_Almanac& gps_alm)
|
||||
|
||||
rtklib_alm = {0, 0, 0, 0, {0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
rtklib_alm.sat = gps_alm.PRN;
|
||||
const int gps_sys = (MINPRNQZS <= gps_alm.PRN && gps_alm.PRN <= MAXPRNQZS) ? SYS_QZS : SYS_GPS;
|
||||
|
||||
rtklib_alm.sat = satno(gps_sys, gps_alm.PRN);
|
||||
rtklib_alm.svh = gps_alm.SV_health;
|
||||
rtklib_alm.svconf = gps_alm.AS_status;
|
||||
rtklib_alm.week = gps_alm.WNa;
|
||||
@@ -791,7 +793,7 @@ alm_t alm_to_rtklib(const Gps_Almanac& gps_alm)
|
||||
rtklib_alm.toa = toa;
|
||||
rtklib_alm.A = gps_alm.sqrtA * gps_alm.sqrtA;
|
||||
rtklib_alm.e = gps_alm.ecc;
|
||||
rtklib_alm.i0 = (gps_alm.delta_i + 0.3) * GNSS_PI;
|
||||
rtklib_alm.i0 = ((gps_alm.get_system() == 'J') ? gps_alm.delta_i : (gps_alm.delta_i + 0.3)) * GNSS_PI;
|
||||
rtklib_alm.OMG0 = gps_alm.OMEGA_0 * GNSS_PI;
|
||||
rtklib_alm.OMGd = gps_alm.OMEGAdot * GNSS_PI;
|
||||
rtklib_alm.omg = gps_alm.omega * GNSS_PI;
|
||||
|
||||
@@ -387,6 +387,16 @@ bool gps_l1_ca_telemetry_decoder_gs::decode_subframe(double cn0, bool flag_inver
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (d_nav->get_flag_iono_valid() == true)
|
||||
{
|
||||
const std::shared_ptr<Gps_Iono> tmp_obj = std::make_shared<Gps_Iono>(d_nav->get_iono());
|
||||
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
|
||||
}
|
||||
if (d_nav->get_flag_utc_model_valid() == true)
|
||||
{
|
||||
const std::shared_ptr<Gps_Utc_Model> tmp_obj = std::make_shared<Gps_Utc_Model>(d_nav->get_utc_model());
|
||||
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
|
||||
}
|
||||
if (d_nav->almanac_validation() == true)
|
||||
{
|
||||
const std::shared_ptr<Gps_Almanac> tmp_obj = std::make_shared<Gps_Almanac>(d_nav->get_almanac());
|
||||
|
||||
@@ -111,7 +111,7 @@ double Gnss_Almanac::predicted_doppler(double rx_time_s,
|
||||
predicted_doppler = 0.0;
|
||||
}
|
||||
}
|
||||
else if (this->System == 'G') // GPS
|
||||
else if (this->System == 'G' || this->System == 'J') // GPS/QZSS
|
||||
{
|
||||
if (band == 1)
|
||||
{
|
||||
@@ -233,7 +233,7 @@ void Gnss_Almanac::satellitePosVelComputation(double transmitTime, std::array<do
|
||||
}
|
||||
else
|
||||
{
|
||||
i = (0.3 + this->delta_i) * GNSS_PI;
|
||||
i = ((this->System == 'J') ? this->delta_i : (0.3 + this->delta_i)) * GNSS_PI;
|
||||
}
|
||||
|
||||
const double sik = sin(i);
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
double af1{}; //!< Coefficient 1 of code phase offset model [s/s]
|
||||
|
||||
protected:
|
||||
char System{}; //!< Character ID of the GNSS system. 'G': GPS. 'E': Galileo. 'C': BeiDou
|
||||
char System{}; //!< Character ID of the GNSS system. 'G': GPS. 'E': Galileo. 'C': BeiDou. 'J': QZSS
|
||||
private:
|
||||
double check_t(double time) const;
|
||||
};
|
||||
|
||||
@@ -43,6 +43,16 @@ public:
|
||||
this->System = 'G';
|
||||
};
|
||||
|
||||
void set_system(char system)
|
||||
{
|
||||
this->System = system;
|
||||
}
|
||||
|
||||
char get_system() const
|
||||
{
|
||||
return this->System;
|
||||
}
|
||||
|
||||
int32_t SV_health{}; //!< SV Health
|
||||
int32_t AS_status{}; //!< Anti-Spoofing Flags and SV Configuration
|
||||
|
||||
|
||||
@@ -19,11 +19,14 @@
|
||||
|
||||
#include "gps_navigation_message.h"
|
||||
#include "gnss_satellite.h"
|
||||
#include <array>
|
||||
#include <cmath> // for fmod, abs, floor
|
||||
#include <cstring> // for memcpy
|
||||
#include <iostream> // for operator<<, cout
|
||||
#include <limits> // for std::numeric_limits
|
||||
|
||||
using LnavParameter = std::vector<std::pair<int32_t, int32_t>>;
|
||||
|
||||
|
||||
Gps_Navigation_Message::Gps_Navigation_Message(LnavSystem system)
|
||||
: d_system(system)
|
||||
@@ -49,6 +52,173 @@ void Gps_Navigation_Message::print_gps_word_bytes(uint32_t GPS_word) const
|
||||
}
|
||||
|
||||
|
||||
static uint32_t qzss_prn_from_lnav_sv_id(int32_t sv_id)
|
||||
{
|
||||
if (sv_id < 1 || sv_id > 10)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(sv_id) + QZSS_PRN_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
static bool qzss_is_qzo(uint32_t prn)
|
||||
{
|
||||
return prn >= 194U && prn <= 197U;
|
||||
}
|
||||
|
||||
|
||||
static double qzss_almanac_eccentricity_ref(uint32_t prn)
|
||||
{
|
||||
return qzss_is_qzo(prn) ? QZSS_QZO_ECCENTRICITY_REF : 0.0;
|
||||
}
|
||||
|
||||
|
||||
static double qzss_almanac_inclination_ref(uint32_t prn)
|
||||
{
|
||||
return qzss_is_qzo(prn) ? QZSS_QZO_INCLINATION_REF : 0.0;
|
||||
}
|
||||
|
||||
|
||||
static const std::array<const LnavParameter*, 24>& gps_sf5_health_fields()
|
||||
{
|
||||
static const std::array<const LnavParameter*, 24> fields = {
|
||||
&HEALTH_SV1,
|
||||
&HEALTH_SV2,
|
||||
&HEALTH_SV3,
|
||||
&HEALTH_SV4,
|
||||
&HEALTH_SV5,
|
||||
&HEALTH_SV6,
|
||||
&HEALTH_SV7,
|
||||
&HEALTH_SV8,
|
||||
&HEALTH_SV9,
|
||||
&HEALTH_SV10,
|
||||
&HEALTH_SV11,
|
||||
&HEALTH_SV12,
|
||||
&HEALTH_SV13,
|
||||
&HEALTH_SV14,
|
||||
&HEALTH_SV15,
|
||||
&HEALTH_SV16,
|
||||
&HEALTH_SV17,
|
||||
&HEALTH_SV18,
|
||||
&HEALTH_SV19,
|
||||
&HEALTH_SV20,
|
||||
&HEALTH_SV21,
|
||||
&HEALTH_SV22,
|
||||
&HEALTH_SV23,
|
||||
&HEALTH_SV24};
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
void Gps_Navigation_Message::decode_lnav_almanac(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits, uint32_t prn, double eccentricity_ref, double inclination_ref)
|
||||
{
|
||||
a_M_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_MZERO));
|
||||
a_M_0 = a_M_0 * ALM_MZERO_LSB;
|
||||
a_ecc = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_ECC));
|
||||
a_ecc = a_ecc * ALM_ECC_LSB + eccentricity_ref;
|
||||
a_sqrtA = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_SQUAREA));
|
||||
a_sqrtA = a_sqrtA * ALM_SQUAREA_LSB;
|
||||
a_OMEGA_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGAZERO));
|
||||
a_OMEGA_0 = a_OMEGA_0 * ALM_OMEGAZERO_LSB;
|
||||
a_omega = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGA));
|
||||
a_omega = a_omega * ALM_OMEGA_LSB;
|
||||
a_OMEGAdot = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGADOT));
|
||||
a_OMEGAdot = a_OMEGAdot * ALM_OMEGADOT_LSB;
|
||||
a_delta_i = static_cast<double>(read_navigation_signed(subframe_bits, ALM_DELTAI));
|
||||
a_delta_i = a_delta_i * ALM_DELTAI_LSB + inclination_ref;
|
||||
a_af0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF0));
|
||||
a_af0 = a_af0 * ALM_AF0_LSB;
|
||||
a_af1 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF1));
|
||||
a_af1 = a_af1 * ALM_AF1_LSB;
|
||||
a_PRN = prn;
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, ALM_TOA));
|
||||
i_Toa = i_Toa * ALM_TOA_LSB;
|
||||
SV_Health = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, ALM_SVHEALTH));
|
||||
|
||||
flag_almanac_valid = true;
|
||||
}
|
||||
|
||||
|
||||
void Gps_Navigation_Message::decode_lnav_iono_utc(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits)
|
||||
{
|
||||
d_alpha0 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_0));
|
||||
d_alpha0 = d_alpha0 * ALPHA_0_LSB;
|
||||
d_alpha1 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_1));
|
||||
d_alpha1 = d_alpha1 * ALPHA_1_LSB;
|
||||
d_alpha2 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_2));
|
||||
d_alpha2 = d_alpha2 * ALPHA_2_LSB;
|
||||
d_alpha3 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_3));
|
||||
d_alpha3 = d_alpha3 * ALPHA_3_LSB;
|
||||
d_beta0 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_0));
|
||||
d_beta0 = d_beta0 * BETA_0_LSB;
|
||||
d_beta1 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_1));
|
||||
d_beta1 = d_beta1 * BETA_1_LSB;
|
||||
d_beta2 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_2));
|
||||
d_beta2 = d_beta2 * BETA_2_LSB;
|
||||
d_beta3 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_3));
|
||||
d_beta3 = d_beta3 * BETA_3_LSB;
|
||||
d_A1 = static_cast<double>(read_navigation_signed(subframe_bits, A_1));
|
||||
d_A1 = d_A1 * A_1_LSB;
|
||||
d_A0 = static_cast<double>(read_navigation_signed(subframe_bits, A_0));
|
||||
d_A0 = d_A0 * A_0_LSB;
|
||||
d_t_OT = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, T_OT));
|
||||
d_t_OT = d_t_OT * T_OT_LSB;
|
||||
i_WN_T = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_T));
|
||||
d_DeltaT_LS = static_cast<int32_t>(read_navigation_signed(subframe_bits, DELTAT_LS));
|
||||
i_WN_LSF = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_LSF));
|
||||
i_DN = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, DN));
|
||||
d_DeltaT_LSF = static_cast<int32_t>(read_navigation_signed(subframe_bits, DELTAT_LSF));
|
||||
flag_iono_valid = true;
|
||||
flag_utc_model_valid = true;
|
||||
}
|
||||
|
||||
|
||||
void Gps_Navigation_Message::decode_gps_almanac_health_sf4(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits)
|
||||
{
|
||||
almanacHealth[25] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV25));
|
||||
almanacHealth[26] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV26));
|
||||
almanacHealth[27] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV27));
|
||||
almanacHealth[28] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV28));
|
||||
almanacHealth[29] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV29));
|
||||
almanacHealth[30] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV30));
|
||||
almanacHealth[31] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV31));
|
||||
almanacHealth[32] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV32));
|
||||
}
|
||||
|
||||
|
||||
void Gps_Navigation_Message::decode_gps_almanac_health_sf5(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits)
|
||||
{
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, T_OA));
|
||||
i_Toa = i_Toa * T_OA_LSB;
|
||||
i_WN_A = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_A));
|
||||
flag_almanac_week_valid = true;
|
||||
|
||||
const auto& health_fields = gps_sf5_health_fields();
|
||||
for (uint32_t prn = 1; prn <= health_fields.size(); ++prn)
|
||||
{
|
||||
almanacHealth[prn] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, *health_fields[prn - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Gps_Navigation_Message::decode_qzss_almanac_epoch_health(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits)
|
||||
{
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, T_OA));
|
||||
i_Toa = i_Toa * T_OA_LSB;
|
||||
i_WN_A = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_A));
|
||||
flag_almanac_week_valid = true;
|
||||
|
||||
const auto& health_fields = gps_sf5_health_fields();
|
||||
for (int32_t sv_id = 1; sv_id <= 10; ++sv_id)
|
||||
{
|
||||
almanacHealth[qzss_prn_from_lnav_sv_id(sv_id)] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, *health_fields[sv_id - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Gps_Navigation_Message::read_navigation_bool(const std::bitset<GPS_SUBFRAME_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const
|
||||
{
|
||||
bool value = bits[GPS_SUBFRAME_BITS - parameter[0].first];
|
||||
@@ -212,91 +382,55 @@ int32_t Gps_Navigation_Message::subframe_decoder(const char* subframe)
|
||||
b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG);
|
||||
SV_data_ID = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, SV_DATA_ID));
|
||||
SV_page = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, SV_PAGE));
|
||||
if (SV_page > 24 && SV_page < 33) // Page 4 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
if (d_system == LnavSystem::QZSS)
|
||||
{
|
||||
if (SV_data_ID != 0)
|
||||
if (SV_data_ID == QZSS_LNAV_DATA_ID)
|
||||
{
|
||||
a_M_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_MZERO));
|
||||
a_M_0 = a_M_0 * ALM_MZERO_LSB;
|
||||
a_ecc = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_ECC));
|
||||
a_ecc = a_ecc * ALM_ECC_LSB;
|
||||
a_sqrtA = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_SQUAREA));
|
||||
a_sqrtA = a_sqrtA * ALM_SQUAREA_LSB;
|
||||
a_OMEGA_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGAZERO));
|
||||
a_OMEGA_0 = a_OMEGA_0 * ALM_OMEGAZERO_LSB;
|
||||
a_omega = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGA));
|
||||
a_omega = a_omega * ALM_OMEGA_LSB;
|
||||
a_OMEGAdot = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGADOT));
|
||||
a_OMEGAdot = a_OMEGAdot * ALM_OMEGADOT_LSB;
|
||||
a_delta_i = static_cast<double>(read_navigation_signed(subframe_bits, ALM_DELTAI));
|
||||
a_delta_i = a_delta_i * ALM_DELTAI_LSB;
|
||||
a_af0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF0));
|
||||
a_af0 = a_af0 * ALM_AF0_LSB;
|
||||
a_af1 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF1));
|
||||
a_af1 = a_af1 * ALM_AF1_LSB;
|
||||
a_PRN = SV_page;
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, ALM_TOA));
|
||||
i_Toa = i_Toa * ALM_TOA_LSB;
|
||||
|
||||
flag_almanac_valid = true;
|
||||
const uint32_t qzss_prn = qzss_prn_from_lnav_sv_id(SV_page);
|
||||
if (qzss_prn != 0U)
|
||||
{
|
||||
decode_lnav_almanac(subframe_bits, qzss_prn, qzss_almanac_eccentricity_ref(qzss_prn), qzss_almanac_inclination_ref(qzss_prn));
|
||||
}
|
||||
else if (SV_page == QZSS_ALMANAC_EPOCH_HEALTH_SV_ID)
|
||||
{
|
||||
decode_qzss_almanac_epoch_health(subframe_bits);
|
||||
}
|
||||
else if (SV_page == QZSS_IONO_UTC_WIDE_AREA_SV_ID || SV_page == QZSS_IONO_UTC_JAPAN_AREA_SV_ID)
|
||||
{
|
||||
decode_lnav_iono_utc(subframe_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SV_page > 24 && SV_page < 33) // Page 4 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
if (SV_data_ID != 0)
|
||||
{
|
||||
decode_lnav_almanac(subframe_bits, static_cast<uint32_t>(SV_page), 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (SV_page == 52) // Page 13 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
//! \TODO read Estimated Range Deviation (ERD) values
|
||||
}
|
||||
if (SV_page == 52) // Page 13 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
//! \TODO read Estimated Range Deviation (ERD) values
|
||||
}
|
||||
|
||||
if (SV_page == 56) // Page 18 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
// Page 18 - Ionospheric and UTC data
|
||||
d_alpha0 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_0));
|
||||
d_alpha0 = d_alpha0 * ALPHA_0_LSB;
|
||||
d_alpha1 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_1));
|
||||
d_alpha1 = d_alpha1 * ALPHA_1_LSB;
|
||||
d_alpha2 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_2));
|
||||
d_alpha2 = d_alpha2 * ALPHA_2_LSB;
|
||||
d_alpha3 = static_cast<double>(read_navigation_signed(subframe_bits, ALPHA_3));
|
||||
d_alpha3 = d_alpha3 * ALPHA_3_LSB;
|
||||
d_beta0 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_0));
|
||||
d_beta0 = d_beta0 * BETA_0_LSB;
|
||||
d_beta1 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_1));
|
||||
d_beta1 = d_beta1 * BETA_1_LSB;
|
||||
d_beta2 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_2));
|
||||
d_beta2 = d_beta2 * BETA_2_LSB;
|
||||
d_beta3 = static_cast<double>(read_navigation_signed(subframe_bits, BETA_3));
|
||||
d_beta3 = d_beta3 * BETA_3_LSB;
|
||||
d_A1 = static_cast<double>(read_navigation_signed(subframe_bits, A_1));
|
||||
d_A1 = d_A1 * A_1_LSB;
|
||||
d_A0 = static_cast<double>(read_navigation_signed(subframe_bits, A_0));
|
||||
d_A0 = d_A0 * A_0_LSB;
|
||||
d_t_OT = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, T_OT));
|
||||
d_t_OT = d_t_OT * T_OT_LSB;
|
||||
i_WN_T = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_T));
|
||||
d_DeltaT_LS = static_cast<int32_t>(read_navigation_signed(subframe_bits, DELTAT_LS));
|
||||
i_WN_LSF = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_LSF));
|
||||
i_DN = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, DN)); // Right-justified ?
|
||||
d_DeltaT_LSF = static_cast<int32_t>(read_navigation_signed(subframe_bits, DELTAT_LSF));
|
||||
flag_iono_valid = true;
|
||||
flag_utc_model_valid = true;
|
||||
}
|
||||
if (SV_page == 57)
|
||||
{
|
||||
// Reserved
|
||||
}
|
||||
if (SV_page == 56) // Page 18 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
decode_lnav_iono_utc(subframe_bits);
|
||||
}
|
||||
if (SV_page == 57)
|
||||
{
|
||||
// Reserved
|
||||
}
|
||||
|
||||
if (SV_page == 63) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
// Page 25 Anti-Spoofing, SV config and almanac health (PRN: 25-32)
|
||||
//! \TODO Read Anti-Spoofing, SV config
|
||||
almanacHealth[25] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV25));
|
||||
almanacHealth[26] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV26));
|
||||
almanacHealth[27] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV27));
|
||||
almanacHealth[28] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV28));
|
||||
almanacHealth[29] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV29));
|
||||
almanacHealth[30] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV30));
|
||||
almanacHealth[31] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV31));
|
||||
almanacHealth[32] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV32));
|
||||
if (SV_page == 63) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
// Page 25 Anti-Spoofing, SV config and almanac health (PRN: 25-32)
|
||||
//! \TODO Read Anti-Spoofing, SV config
|
||||
decode_gps_almanac_health_sf4(subframe_bits);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -311,65 +445,38 @@ int32_t Gps_Navigation_Message::subframe_decoder(const char* subframe)
|
||||
b_antispoofing_flag = read_navigation_bool(subframe_bits, ANTI_SPOOFING_FLAG);
|
||||
SV_data_ID_5 = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, SV_DATA_ID));
|
||||
SV_page_5 = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, SV_PAGE));
|
||||
if ((SV_page_5 > 0) && (SV_page_5 < 25))
|
||||
if (d_system == LnavSystem::QZSS)
|
||||
{
|
||||
if (SV_data_ID_5 != 0)
|
||||
if (SV_data_ID_5 == QZSS_LNAV_DATA_ID)
|
||||
{
|
||||
a_M_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_MZERO));
|
||||
a_M_0 = a_M_0 * ALM_MZERO_LSB;
|
||||
a_ecc = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_ECC));
|
||||
a_ecc = a_ecc * ALM_ECC_LSB;
|
||||
a_sqrtA = static_cast<double>(read_navigation_unsigned(subframe_bits, ALM_SQUAREA));
|
||||
a_sqrtA = a_sqrtA * ALM_SQUAREA_LSB;
|
||||
a_OMEGA_0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGAZERO));
|
||||
a_OMEGA_0 = a_OMEGA_0 * ALM_OMEGAZERO_LSB;
|
||||
a_omega = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGA));
|
||||
a_omega = a_omega * ALM_OMEGA_LSB;
|
||||
a_OMEGAdot = static_cast<double>(read_navigation_signed(subframe_bits, ALM_OMEGADOT));
|
||||
a_OMEGAdot = a_OMEGAdot * ALM_OMEGADOT_LSB;
|
||||
a_delta_i = static_cast<double>(read_navigation_signed(subframe_bits, ALM_DELTAI));
|
||||
a_delta_i = a_delta_i * ALM_DELTAI_LSB;
|
||||
a_af0 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF0));
|
||||
a_af0 = a_af0 * ALM_AF0_LSB;
|
||||
a_af1 = static_cast<double>(read_navigation_signed(subframe_bits, ALM_AF1));
|
||||
a_af1 = a_af1 * ALM_AF1_LSB;
|
||||
a_PRN = SV_page_5;
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, ALM_TOA));
|
||||
i_Toa = i_Toa * ALM_TOA_LSB;
|
||||
SV_Health = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, ALM_SVHEALTH));
|
||||
flag_almanac_valid = true;
|
||||
const uint32_t qzss_prn = qzss_prn_from_lnav_sv_id(SV_page_5);
|
||||
if (qzss_prn != 0U)
|
||||
{
|
||||
decode_lnav_almanac(subframe_bits, qzss_prn, qzss_almanac_eccentricity_ref(qzss_prn), qzss_almanac_inclination_ref(qzss_prn));
|
||||
}
|
||||
else if (SV_page_5 == QZSS_ALMANAC_EPOCH_HEALTH_SV_ID)
|
||||
{
|
||||
decode_qzss_almanac_epoch_health(subframe_bits);
|
||||
}
|
||||
else if (SV_page_5 == QZSS_IONO_UTC_WIDE_AREA_SV_ID || SV_page_5 == QZSS_IONO_UTC_JAPAN_AREA_SV_ID)
|
||||
{
|
||||
decode_lnav_iono_utc(subframe_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SV_page_5 == 51) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
else
|
||||
{
|
||||
i_Toa = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, T_OA));
|
||||
i_Toa = i_Toa * T_OA_LSB;
|
||||
i_WN_A = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, WN_A));
|
||||
flag_almanac_week_valid = true;
|
||||
almanacHealth[1] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV1));
|
||||
almanacHealth[2] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV2));
|
||||
almanacHealth[3] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV3));
|
||||
almanacHealth[4] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV4));
|
||||
almanacHealth[5] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV5));
|
||||
almanacHealth[6] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV6));
|
||||
almanacHealth[7] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV7));
|
||||
almanacHealth[8] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV8));
|
||||
almanacHealth[9] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV9));
|
||||
almanacHealth[10] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV10));
|
||||
almanacHealth[11] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV11));
|
||||
almanacHealth[12] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV12));
|
||||
almanacHealth[13] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV13));
|
||||
almanacHealth[14] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV14));
|
||||
almanacHealth[15] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV15));
|
||||
almanacHealth[16] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV16));
|
||||
almanacHealth[17] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV17));
|
||||
almanacHealth[18] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV18));
|
||||
almanacHealth[19] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV19));
|
||||
almanacHealth[20] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV20));
|
||||
almanacHealth[21] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV21));
|
||||
almanacHealth[22] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV22));
|
||||
almanacHealth[23] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV23));
|
||||
almanacHealth[24] = static_cast<int32_t>(read_navigation_unsigned(subframe_bits, HEALTH_SV24));
|
||||
if ((SV_page_5 > 0) && (SV_page_5 < 25))
|
||||
{
|
||||
if (SV_data_ID_5 != 0)
|
||||
{
|
||||
decode_lnav_almanac(subframe_bits, static_cast<uint32_t>(SV_page_5), 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
if (SV_page_5 == 51) // Page 25 (from Table 20-V. Data IDs and SV IDs in Subframes 4 and 5, IS-GPS-200M)
|
||||
{
|
||||
decode_gps_almanac_health_sf5(subframe_bits);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -503,6 +610,10 @@ Gps_Ephemeris Gps_Navigation_Message::get_ephemeris() const
|
||||
Gps_Almanac Gps_Navigation_Message::get_almanac()
|
||||
{
|
||||
Gps_Almanac almanac;
|
||||
if (d_system == LnavSystem::QZSS)
|
||||
{
|
||||
almanac.set_system('J');
|
||||
}
|
||||
almanac.SV_health = SV_Health;
|
||||
almanac.PRN = a_PRN;
|
||||
almanac.delta_i = a_delta_i;
|
||||
@@ -558,6 +669,17 @@ Gps_Utc_Model Gps_Navigation_Message::get_utc_model()
|
||||
}
|
||||
|
||||
|
||||
int32_t Gps_Navigation_Message::get_almanac_health(uint32_t prn) const
|
||||
{
|
||||
const auto almanac_health = almanacHealth.find(prn);
|
||||
if (almanac_health == almanacHealth.cend())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return almanac_health->second;
|
||||
}
|
||||
|
||||
|
||||
bool Gps_Navigation_Message::satellite_validation()
|
||||
{
|
||||
bool flag_data_valid = false;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "gps_ephemeris.h"
|
||||
#include "gps_iono.h"
|
||||
#include "gps_utc_model.h"
|
||||
#include "qzss.h"
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
@@ -143,6 +144,11 @@ public:
|
||||
return flag_utc_model_valid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the almanac health field for a satellite PRN
|
||||
*/
|
||||
int32_t get_almanac_health(uint32_t prn) const;
|
||||
|
||||
bool satellite_validation();
|
||||
bool almanac_validation() const;
|
||||
|
||||
@@ -151,6 +157,11 @@ private:
|
||||
int64_t read_navigation_signed(const std::bitset<GPS_SUBFRAME_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const;
|
||||
bool read_navigation_bool(const std::bitset<GPS_SUBFRAME_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const;
|
||||
void print_gps_word_bytes(uint32_t GPS_word) const;
|
||||
void decode_lnav_almanac(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits, uint32_t prn, double eccentricity_ref, double inclination_ref);
|
||||
void decode_lnav_iono_utc(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits);
|
||||
void decode_gps_almanac_health_sf4(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits);
|
||||
void decode_gps_almanac_health_sf5(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits);
|
||||
void decode_qzss_almanac_epoch_health(const std::bitset<GPS_SUBFRAME_BITS>& subframe_bits);
|
||||
|
||||
std::map<int32_t, int32_t> almanacHealth; //!< Map that stores the health information stored in the almanac
|
||||
|
||||
|
||||
@@ -52,6 +52,14 @@ constexpr const char QZSS_CA_PREAMBLE_SYMBOLS_STR[161] = "1111111111111111111100
|
||||
constexpr const char QZSS_L5Q_NH_CODE_STR[21] = "00000100110101001110";
|
||||
constexpr const char QZSS_L5I_NH_CODE_STR[11] = "0000110101";
|
||||
|
||||
static constexpr int32_t QZSS_LNAV_DATA_ID = 3;
|
||||
static constexpr int32_t QZSS_ALMANAC_EPOCH_HEALTH_SV_ID = 51;
|
||||
static constexpr int32_t QZSS_IONO_UTC_WIDE_AREA_SV_ID = 56;
|
||||
static constexpr int32_t QZSS_IONO_UTC_JAPAN_AREA_SV_ID = 61;
|
||||
static constexpr uint32_t QZSS_PRN_OFFSET = 192U;
|
||||
static constexpr double QZSS_QZO_ECCENTRICITY_REF = 0.06;
|
||||
static constexpr double QZSS_QZO_INCLINATION_REF = 0.25;
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
|
||||
|
||||
@@ -189,6 +189,7 @@ private:
|
||||
#include "unit-tests/system-parameters/gps_cnav_navigation_message_test.cc"
|
||||
#include "unit-tests/system-parameters/has_decoding_test.cc"
|
||||
#include "unit-tests/system-parameters/qzss_code_generation_test.cc"
|
||||
#include "unit-tests/system-parameters/qzss_lnav_navigation_message_test.cc"
|
||||
|
||||
#ifndef EXCLUDE_TESTS_REQUIRING_BINARIES
|
||||
#include "unit-tests/control-plane/control_thread_test.cc"
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*!
|
||||
* \file qzss_lnav_navigation_message_test.cc
|
||||
* \brief Tests for QZSS LNAV navigation message decoding
|
||||
* \author Carles Fernandez-Prades, 2026. cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "GPS_L1_CA.h"
|
||||
#include "gps_navigation_message.h"
|
||||
#include "rtklib_conversions.h"
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
int32_t qzss_lnav_field_width(const std::vector<std::pair<int32_t, int32_t>>& parameter)
|
||||
{
|
||||
int32_t width = 0;
|
||||
for (const auto& p : parameter)
|
||||
{
|
||||
width += p.second;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
void set_qzss_lnav_unsigned_field(std::bitset<GPS_SUBFRAME_BITS>& bits,
|
||||
const std::vector<std::pair<int32_t, int32_t>>& parameter,
|
||||
uint64_t value)
|
||||
{
|
||||
int32_t pending_bits = qzss_lnav_field_width(parameter);
|
||||
|
||||
for (const auto& p : parameter)
|
||||
{
|
||||
for (int32_t j = 0; j < p.second; ++j)
|
||||
{
|
||||
--pending_bits;
|
||||
bits[GPS_SUBFRAME_BITS - p.first - j] = ((value >> pending_bits) & 1ULL) != 0ULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_qzss_lnav_signed_field(std::bitset<GPS_SUBFRAME_BITS>& bits,
|
||||
const std::vector<std::pair<int32_t, int32_t>>& parameter,
|
||||
int64_t value)
|
||||
{
|
||||
const int32_t width = qzss_lnav_field_width(parameter);
|
||||
const uint64_t mask = (width == 64) ? std::numeric_limits<uint64_t>::max() : ((1ULL << width) - 1ULL);
|
||||
set_qzss_lnav_unsigned_field(bits, parameter, static_cast<uint64_t>(value) & mask);
|
||||
}
|
||||
|
||||
|
||||
std::array<char, GPS_SUBFRAME_LENGTH> qzss_lnav_subframe_bytes(const std::bitset<GPS_SUBFRAME_BITS>& bits)
|
||||
{
|
||||
std::array<char, GPS_SUBFRAME_LENGTH> subframe{};
|
||||
|
||||
for (int32_t i = 0; i < 10; ++i)
|
||||
{
|
||||
uint32_t word = 0;
|
||||
for (int32_t j = 0; j < GPS_WORD_BITS; ++j)
|
||||
{
|
||||
if (bits[GPS_WORD_BITS * (9 - i) + j])
|
||||
{
|
||||
word |= (1U << j);
|
||||
}
|
||||
}
|
||||
std::memcpy(&subframe[i * GPS_WORD_LENGTH], &word, sizeof(word));
|
||||
}
|
||||
|
||||
return subframe;
|
||||
}
|
||||
|
||||
|
||||
std::bitset<GPS_SUBFRAME_BITS> qzss_lnav_page(int32_t subframe_id, int32_t sv_id)
|
||||
{
|
||||
std::bitset<GPS_SUBFRAME_BITS> bits;
|
||||
|
||||
set_qzss_lnav_unsigned_field(bits, TOW, 1);
|
||||
set_qzss_lnav_unsigned_field(bits, SUBFRAME_ID, static_cast<uint64_t>(subframe_id));
|
||||
set_qzss_lnav_unsigned_field(bits, SV_DATA_ID, 3);
|
||||
set_qzss_lnav_unsigned_field(bits, SV_PAGE, static_cast<uint64_t>(sv_id));
|
||||
|
||||
return bits;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
TEST(QzssLnavNavigationMessageTest, DecodesQzoAlmanacFromSubframe4)
|
||||
{
|
||||
Gps_Navigation_Message nav_message(LnavSystem::QZSS);
|
||||
|
||||
auto bits = qzss_lnav_page(4, 2);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_ECC, 100);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_TOA, 7);
|
||||
set_qzss_lnav_signed_field(bits, ALM_DELTAI, -25);
|
||||
set_qzss_lnav_signed_field(bits, ALM_OMEGADOT, -30);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_SVHEALTH, 0xAD);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_SQUAREA, 5440000);
|
||||
set_qzss_lnav_signed_field(bits, ALM_OMEGAZERO, -3000);
|
||||
set_qzss_lnav_signed_field(bits, ALM_OMEGA, 2000);
|
||||
set_qzss_lnav_signed_field(bits, ALM_MZERO, -1000);
|
||||
set_qzss_lnav_signed_field(bits, ALM_AF0, -12);
|
||||
set_qzss_lnav_signed_field(bits, ALM_AF1, 13);
|
||||
|
||||
const auto subframe = qzss_lnav_subframe_bytes(bits);
|
||||
EXPECT_EQ(4, nav_message.subframe_decoder(subframe.data()));
|
||||
|
||||
ASSERT_FALSE(nav_message.almanac_validation());
|
||||
const auto almanac = nav_message.get_almanac();
|
||||
|
||||
EXPECT_EQ('J', almanac.get_system());
|
||||
EXPECT_EQ(194U, almanac.PRN);
|
||||
EXPECT_EQ(7 * ALM_TOA_LSB, almanac.toa);
|
||||
EXPECT_EQ(0xAD, almanac.SV_health);
|
||||
EXPECT_NEAR(0.06 + 100.0 * ALM_ECC_LSB, almanac.ecc, 1e-14);
|
||||
EXPECT_NEAR(0.25 - 25.0 * ALM_DELTAI_LSB, almanac.delta_i, 1e-14);
|
||||
EXPECT_NEAR(-30.0 * ALM_OMEGADOT_LSB, almanac.OMEGAdot, 1e-18);
|
||||
|
||||
const auto rtklib_almanac = alm_to_rtklib(almanac);
|
||||
EXPECT_EQ(satno(SYS_QZS, 194), rtklib_almanac.sat);
|
||||
EXPECT_NEAR(almanac.delta_i * GNSS_PI, rtklib_almanac.i0, 1e-12);
|
||||
}
|
||||
|
||||
|
||||
TEST(GpsLnavNavigationMessageTest, KeepsGpsAlmanacReferenceConvention)
|
||||
{
|
||||
Gps_Navigation_Message nav_message;
|
||||
|
||||
auto bits = qzss_lnav_page(5, 2);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_ECC, 100);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_TOA, 7);
|
||||
set_qzss_lnav_signed_field(bits, ALM_DELTAI, -25);
|
||||
set_qzss_lnav_unsigned_field(bits, ALM_SVHEALTH, 0x12);
|
||||
|
||||
const auto subframe = qzss_lnav_subframe_bytes(bits);
|
||||
EXPECT_EQ(5, nav_message.subframe_decoder(subframe.data()));
|
||||
|
||||
const auto almanac = nav_message.get_almanac();
|
||||
EXPECT_EQ('G', almanac.get_system());
|
||||
EXPECT_EQ(2U, almanac.PRN);
|
||||
EXPECT_EQ(7 * ALM_TOA_LSB, almanac.toa);
|
||||
EXPECT_EQ(0x12, almanac.SV_health);
|
||||
EXPECT_NEAR(100.0 * ALM_ECC_LSB, almanac.ecc, 1e-14);
|
||||
EXPECT_NEAR(-25.0 * ALM_DELTAI_LSB, almanac.delta_i, 1e-14);
|
||||
|
||||
const auto rtklib_almanac = alm_to_rtklib(almanac);
|
||||
EXPECT_EQ(satno(SYS_GPS, 2), rtklib_almanac.sat);
|
||||
EXPECT_NEAR((0.3 + almanac.delta_i) * GNSS_PI, rtklib_almanac.i0, 1e-12);
|
||||
}
|
||||
|
||||
|
||||
TEST(QzssLnavNavigationMessageTest, DecodesQzssAlmanacEpochAndHealthFromSubframe4)
|
||||
{
|
||||
Gps_Navigation_Message nav_message(LnavSystem::QZSS);
|
||||
|
||||
auto bits = qzss_lnav_page(4, 51);
|
||||
set_qzss_lnav_unsigned_field(bits, T_OA, 9);
|
||||
set_qzss_lnav_unsigned_field(bits, WN_A, 77);
|
||||
set_qzss_lnav_unsigned_field(bits, HEALTH_SV1, 1);
|
||||
set_qzss_lnav_unsigned_field(bits, HEALTH_SV4, 4);
|
||||
set_qzss_lnav_unsigned_field(bits, HEALTH_SV8, 8);
|
||||
set_qzss_lnav_unsigned_field(bits, HEALTH_SV10, 10);
|
||||
|
||||
const auto subframe = qzss_lnav_subframe_bytes(bits);
|
||||
EXPECT_EQ(4, nav_message.subframe_decoder(subframe.data()));
|
||||
|
||||
EXPECT_EQ(1, nav_message.get_almanac_health(193));
|
||||
EXPECT_EQ(4, nav_message.get_almanac_health(196));
|
||||
EXPECT_EQ(8, nav_message.get_almanac_health(200));
|
||||
EXPECT_EQ(10, nav_message.get_almanac_health(202));
|
||||
}
|
||||
|
||||
|
||||
TEST(QzssLnavNavigationMessageTest, DecodesJapanAreaIonoUtcFromSubframe5)
|
||||
{
|
||||
Gps_Navigation_Message nav_message(LnavSystem::QZSS);
|
||||
|
||||
auto bits = qzss_lnav_page(5, 61);
|
||||
set_qzss_lnav_signed_field(bits, ALPHA_0, -1);
|
||||
set_qzss_lnav_signed_field(bits, ALPHA_1, 2);
|
||||
set_qzss_lnav_signed_field(bits, ALPHA_2, -3);
|
||||
set_qzss_lnav_signed_field(bits, ALPHA_3, 4);
|
||||
set_qzss_lnav_signed_field(bits, BETA_0, -5);
|
||||
set_qzss_lnav_signed_field(bits, BETA_1, 6);
|
||||
set_qzss_lnav_signed_field(bits, BETA_2, -7);
|
||||
set_qzss_lnav_signed_field(bits, BETA_3, 8);
|
||||
set_qzss_lnav_signed_field(bits, A_1, -9);
|
||||
set_qzss_lnav_signed_field(bits, A_0, 10);
|
||||
set_qzss_lnav_unsigned_field(bits, T_OT, 11);
|
||||
set_qzss_lnav_unsigned_field(bits, WN_T, 12);
|
||||
set_qzss_lnav_signed_field(bits, DELTAT_LS, -18);
|
||||
set_qzss_lnav_unsigned_field(bits, WN_LSF, 13);
|
||||
set_qzss_lnav_unsigned_field(bits, DN, 4);
|
||||
set_qzss_lnav_signed_field(bits, DELTAT_LSF, -17);
|
||||
|
||||
const auto subframe = qzss_lnav_subframe_bytes(bits);
|
||||
EXPECT_EQ(5, nav_message.subframe_decoder(subframe.data()));
|
||||
|
||||
ASSERT_TRUE(nav_message.get_flag_iono_valid());
|
||||
ASSERT_TRUE(nav_message.get_flag_utc_model_valid());
|
||||
|
||||
const auto iono = nav_message.get_iono();
|
||||
EXPECT_TRUE(iono.valid);
|
||||
EXPECT_NEAR(-1.0 * ALPHA_0_LSB, iono.alpha0, 1e-18);
|
||||
EXPECT_NEAR(2.0 * ALPHA_1_LSB, iono.alpha1, 1e-18);
|
||||
EXPECT_NEAR(-3.0 * ALPHA_2_LSB, iono.alpha2, 1e-18);
|
||||
EXPECT_NEAR(4.0 * ALPHA_3_LSB, iono.alpha3, 1e-18);
|
||||
EXPECT_NEAR(-5.0 * BETA_0_LSB, iono.beta0, 1e-12);
|
||||
EXPECT_NEAR(6.0 * BETA_1_LSB, iono.beta1, 1e-12);
|
||||
|
||||
const auto utc = nav_message.get_utc_model();
|
||||
EXPECT_TRUE(utc.valid);
|
||||
EXPECT_NEAR(-9.0 * A_1_LSB, utc.A1, 1e-18);
|
||||
EXPECT_NEAR(10.0 * A_0_LSB, utc.A0, 1e-18);
|
||||
EXPECT_EQ(11 * T_OT_LSB, utc.tot);
|
||||
EXPECT_EQ(12, utc.WN_T);
|
||||
EXPECT_EQ(-18, utc.DeltaT_LS);
|
||||
EXPECT_EQ(13, utc.WN_LSF);
|
||||
EXPECT_EQ(4, utc.DN);
|
||||
EXPECT_EQ(-17, utc.DeltaT_LSF);
|
||||
}
|
||||
Reference in New Issue
Block a user