diff --git a/docs/protobuf/monitor_pvt.proto b/docs/protobuf/monitor_pvt.proto index 2875b38db..b55b13c4f 100644 --- a/docs/protobuf/monitor_pvt.proto +++ b/docs/protobuf/monitor_pvt.proto @@ -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 diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 2a6c15022..62a2f8684 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -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"; } diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index bbc6ce5ce..d02a39a14 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -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); diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h index 68d6f801c..a3f6b21cc 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.h +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -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