Merge branch 'joebre-fix-gps-l2c-l5-health-exclusion' into next

This commit is contained in:
Carles Fernandez
2026-10-03 08:18:28 +02:00
4 changed files with 25 additions and 16 deletions
+4 -1
View File
@@ -61,7 +61,10 @@ message MonitorPvt {
// azimuth_deg/elevation_deg populated with used = false when it was
// tracked and had az/el computed but excluded from the fix itself (e.g.
// below PVT.elevation_mask, or by RAIM FDE). The healthy flag carries the
// broadcast health of the signal, independently of used.
// broadcast health of the signal, independently of used. Exception: GPS L5
// carries the LNAV SV health of the same satellite (as GPS L1 C/A does),
// because its CNAV L5 health bit is broadcast as unhealthy while the signal
// is pre-operational.
message TrackedSatellite {
uint32 prn = 1;
string system = 2; // "G" GPS, "E" Galileo, "R" GLONASS, "C" BeiDou, "S" SBAS, "J" QZSS
@@ -1652,19 +1652,17 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg)
{
d_user_pvt_solver->gps_cnav_ephemeris_map[gps_cnav_ephemeris->PRN] = *gps_cnav_ephemeris;
}
// The CNAV L1/L2/L5 health bits are not used to exclude observables
// from the PVT solution (pre-operational GPS L5 is broadcast as
// unhealthy), so they are only logged here. See
// Rtklib_Solver::get_broadcast_signal_health() for how they are reported.
if (gps_cnav_ephemeris->signal_health != 0)
{
const std::string sat_sys = (MINPRNQZS <= gps_cnav_ephemeris->PRN && gps_cnav_ephemeris->PRN <= MAXPRNQZS) ? "QZSS" : "GPS";
std::cout << "Satellite " << Gnss_Satellite(sat_sys, gps_cnav_ephemeris->PRN)
<< " reports an unhealthy status in the CNAV message,";
if (d_use_unhealthy_sats)
{
std::cout << " use PVT solutions at your own risk.\n";
}
else
{
std::cout << " not used for navigation.\n";
}
LOG(INFO) << "CNAV signal health of " << Gnss_Satellite(sat_sys, gps_cnav_ephemeris->PRN)
<< ": L1 " << ((gps_cnav_ephemeris->signal_health & 0x4) ? "bad" : "OK")
<< ", L2 " << ((gps_cnav_ephemeris->signal_health & 0x2) ? "bad" : "OK")
<< ", L5 " << ((gps_cnav_ephemeris->signal_health & 0x1) ? "bad" : "OK");
}
DLOG(INFO) << "New GPS CNAV ephemeris record has arrived";
}
+9 -3
View File
@@ -1430,8 +1430,14 @@ bool Rtklib_Solver::get_broadcast_signal_health(char system, uint32_t prn, const
{
// L2C and L5 health comes from the CNAV message that carries them:
// bits 52-54 of message type 10 are the L1, L2 and L5 signal health
// (0 = OK, IS-GPS-200 30.3.3.1.1.2).
if (signal == "2S" || signal == "L5" || signal == "J5")
// (0 = OK, IS-GPS-200N 30.3.3.1.1.2).
// Exception: GPS L5 is still pre-operational (IS-GPS-200N 6.3.7), and
// its CNAV L5 health bit is broadcast as "unhealthy" on every SV
// regardless of the actual signal status. Reporting that bit would
// flag every GPS L5 signal as unhealthy, so GPS L5 reports the LNAV
// SV health of the same satellite (as L1 C/A does) instead. QZSS L5
// keeps the CNAV bit.
if (signal == "2S" || signal == "J5")
{
const auto cnav_it = gps_cnav_ephemeris_map.find(prn_key);
if (cnav_it != gps_cnav_ephemeris_map.cend())
@@ -1441,7 +1447,7 @@ bool Rtklib_Solver::get_broadcast_signal_health(char system, uint32_t prn, const
return true;
}
}
// L1 C/A: per-satellite SV health from LNAV subframe 1, falling back
// L1 C/A and GPS L5: per-satellite SV health from LNAV subframe 1, falling back
// to the almanac (broadcast by every satellite) when no ephemeris has
// been decoded for this satellite yet.
const auto eph_it = gps_ephemeris_map.find(prn_key);
+4 -2
View File
@@ -175,8 +175,10 @@ public:
/*!
* \brief Broadcast health of one tracked signal, as reported by the navigation
* message that carries it: GPS/QZSS L1 C/A from the LNAV SV health (almanac
* when no ephemeris has been decoded yet), GPS/QZSS L2C and L5 from the CNAV
* per-signal health bits, Galileo per signal (see get_galileo_signal_health(),
* when no ephemeris has been decoded yet), GPS L2C and QZSS L5 from the CNAV
* per-signal health bits, GPS L5 from the LNAV SV health of the same satellite
* (the CNAV L5 bit is broadcast as unhealthy while GPS L5 is pre-operational),
* Galileo per signal (see get_galileo_signal_health(),
* the almanac health status of the same signal when no ephemeris is available),
* GLONASS from the GNAV ln/Bn
* flags, BeiDou B1I/B3I from the DNAV SV health and B1C/B2a from the