diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8f2e21881..2d7d32dc1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -109,6 +109,13 @@ All notable changes to GNSS-SDR will be documented in this file. Their generation can be disabled by setting `Observables.enable_E6=false`. This setting is now independent of `PVT.use_e6_for_pvt`, which keeps controlling whether E6 observables are used in the PVT solution. +- The Monitor (`Monitor.enable_monitor=true`) now also reports channels that are + tracking a signal but do not have a valid time reference yet, filling their + entries with the latest raw tracking data (C/N0, Doppler, carrier phase) while + keeping their observable validity flags unset. This makes the Monitor usable + in Galileo E6-only configurations, where the time of week cannot be obtained + from HAS pages, as well as during the initial seconds of operation, before the + telemetry decoders attain synchronization. - Reworked the Python plotting utilities under `utils/python` (acquisition, tracking, telemetry, observables, and PVT diagnostics). Each script now exposes a command-line interface (run with `--help`) and can be executed from diff --git a/src/algorithms/observables/adapters/hybrid_observables.cc b/src/algorithms/observables/adapters/hybrid_observables.cc index 9b72f478e..a08ecaea1 100644 --- a/src/algorithms/observables/adapters/hybrid_observables.cc +++ b/src/algorithms/observables/adapters/hybrid_observables.cc @@ -50,6 +50,7 @@ HybridObservables::HybridObservables(const ConfigurationInterface* configuration conf.enable_carrier_smoothing = configuration->property(role + ".enable_carrier_smoothing", conf.enable_carrier_smoothing); conf.always_output_gs = configuration->property("PVT.an_output_enabled", conf.always_output_gs) || configuration->property(role + ".always_output_gs", conf.always_output_gs); conf.enable_E6 = configuration->property(role + ".enable_E6", conf.enable_E6); + conf.enable_monitor = configuration->property("Monitor.enable_monitor", conf.enable_monitor); #if USE_GLOG_AND_GFLAGS if (FLAGS_carrier_smoothing_factor == DEFAULT_CARRIER_SMOOTHING_FACTOR) diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc index 8af593030..84dbf31fc 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc @@ -106,6 +106,7 @@ hybrid_observables_gs::hybrid_observables_gs(const Obs_Conf &conf_) d_channel_last_pseudorange_smooth = std::vector(d_nchannels_out, 0.0); d_channel_last_carrier_phase_rads = std::vector(d_nchannels_out, 0.0); d_channel_last_rx_time_valid = std::vector(d_nchannels_out, false); + d_last_trk_data = std::vector(d_nchannels_out); d_SourceTagTimestamps = std::vector>(d_nchannels_out); @@ -512,6 +513,19 @@ void hybrid_observables_gs::forecast(int noutput_items __attribute__((unused)), } +bool hybrid_observables_gs::has_fresh_trk_data(uint32_t ch, uint64_t rx_clock) const +{ + const Gnss_Synchro &trk = d_last_trk_data[ch]; + if (trk.fs <= 0) + { + return false; + } + // the interpolation epoch lags the latest tracking data, so a negative age is expected + const auto age_samples = static_cast(rx_clock) - static_cast(trk.Tracking_sample_counter); + return age_samples < trk.fs; // tracking data not older than one second +} + + void hybrid_observables_gs::update_TOW(const std::vector &data) { // 1. Set the TOW using the latest TOW in the observables. @@ -888,6 +902,12 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused) // ************ end time tags ************** for (int32_t m = 0; m < ninput_items[n]; m++) { + if (d_conf.enable_monitor) + { + // Keep the latest tracking data so that channels without a + // valid time reference can be reported through the Monitor + d_last_trk_data[n] = in[n][m]; + } // Push the valid tracking Gnss_Synchros to their corresponding deque if (in[n][m].Flag_valid_word) { @@ -919,6 +939,7 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused) { std::vector epoch_data(d_nchannels_out); int32_t n_valid = 0; + int32_t n_trk_only = 0; for (uint32_t n = 0; n < d_nchannels_out; n++) { Gnss_Synchro interpolated_gnss_synchro{}; @@ -926,6 +947,14 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused) { // Produce an empty observation interpolated_gnss_synchro = Gnss_Synchro(); + if (d_conf.enable_monitor && has_fresh_trk_data(n, d_Rx_clock_buffer.front())) + { + // Report the latest tracking data (e.g., C/N0, Doppler) for + // channels lacking a valid time reference, such as Galileo E6 + // when no I/NAV or F/NAV channel provides the time of week + interpolated_gnss_synchro = d_last_trk_data[n]; + n_trk_only++; + } interpolated_gnss_synchro.Flag_valid_pseudorange = false; interpolated_gnss_synchro.Flag_valid_word = false; interpolated_gnss_synchro.Flag_valid_acquisition = false; @@ -1017,7 +1046,7 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused) } } - if (n_valid > 0) + if (n_valid > 0 || n_trk_only > 0) { // LOG(INFO) << "OBS: diff time: " << out[0][0].RX_time * 1000.0 - old_time_debug; // old_time_debug = out[0][0].RX_time * 1000.0; diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h index 9f256294d..65d38b6df 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h @@ -74,6 +74,7 @@ private: void msg_handler_pvt_to_observables(const pmt::pmt_t& msg); double compute_T_rx_s(const Gnss_Synchro& a) const; bool interp_trk_obs(Gnss_Synchro& interpolated_obs, uint32_t ch, uint64_t rx_clock) const; + bool has_fresh_trk_data(uint32_t ch, uint64_t rx_clock) const; void update_TOW(const std::vector& data); void compute_pranges(std::vector& data) const; void smooth_pseudoranges(std::vector& data); @@ -101,6 +102,7 @@ private: std::vector d_channel_last_pseudorange_smooth; std::vector d_channel_last_carrier_phase_rads; std::vector d_channel_last_rx_time_valid; + std::vector d_last_trk_data; // latest tracking data per channel, for the Monitor std::string d_dump_filename; diff --git a/src/algorithms/observables/libs/obs_conf.h b/src/algorithms/observables/libs/obs_conf.h index f66bf6afa..f177da077 100644 --- a/src/algorithms/observables/libs/obs_conf.h +++ b/src/algorithms/observables/libs/obs_conf.h @@ -42,6 +42,7 @@ public: bool dump{false}; bool dump_mat{false}; bool enable_E6{true}; + bool enable_monitor{false}; }; /** \} */