diff --git a/src/algorithms/PVT/libs/rinex_printer.cc b/src/algorithms/PVT/libs/rinex_printer.cc index 9d88845dd..35047ec37 100644 --- a/src/algorithms/PVT/libs/rinex_printer.cc +++ b/src/algorithms/PVT/libs/rinex_printer.cc @@ -2861,7 +2861,9 @@ void Rinex_Printer::log_rinex_nav_glo_gnav(const std::map(((static_cast(eph.d_B_n) & 4) == 0) ? 0 : 1); + out << get_nav_broadcast_orbit(&eph.d_Xn, &eph.d_VXn, &eph.d_AXn, &health_d, d_version) << '\n'; // -------- BROADCAST ORBIT - 2 const auto freq_channel_d = static_cast(eph.i_satellite_freq_channel); diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.cc index 5ffc15bc8..7109e1003 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.cc @@ -55,7 +55,6 @@ glonass_l1_ca_telemetry_decoder_gs::glonass_l1_ca_telemetry_decoder_gs(const Tlm gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))), d_dump_filename(conf.dump_filename), - d_preamble_time_samples(0), d_TOW_at_current_symbol(0), d_sample_counter(0ULL), d_preamble_index(0ULL), @@ -73,8 +72,6 @@ glonass_l1_ca_telemetry_decoder_gs::glonass_l1_ca_telemetry_decoder_gs(const Tlm { configure_basic_outputs(); - this->message_port_register_out(pmt::mp("preamble_timestamp_samples")); - if (d_enable_navdata_monitor) { // register nav message monitor out @@ -223,6 +220,28 @@ void glonass_l1_ca_telemetry_decoder_gs::set_channel(int32_t channel) } +void glonass_l1_ca_telemetry_decoder_gs::reset() +{ + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_symbol_history.clear(); + d_stat = 0; + d_CRC_error_counter = 0; + d_flag_frame_sync = false; + d_flag_preamble = false; + // Invalidate the propagated TOW until a new string 5 is decoded; otherwise + // Flag_valid_word would remain true with a TOW offset by the outage duration + d_nav.set_flag_TOW_set(false); + d_nav.set_flag_TOW_new(false); + // Drop partially decoded ephemeris strings so that strings received before + // the outage cannot be combined with strings of a different frame + d_nav.set_flag_ephemeris_str_1(false); + d_nav.set_flag_ephemeris_str_2(false); + d_nav.set_flag_ephemeris_str_3(false); + d_nav.set_flag_ephemeris_str_4(false); + DLOG(INFO) << "Telemetry decoder reset for satellite " << d_satellite; +} + + int glonass_l1_ca_telemetry_decoder_gs::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { @@ -269,8 +288,6 @@ int glonass_l1_ca_telemetry_decoder_gs::general_work(int noutput_items __attribu LOG(INFO) << "Preamble detection for GLONASS L1 C/A SAT " << this->d_satellite; // Enter into frame pre-detection status d_stat = 1; - d_preamble_time_samples = d_symbol_history[0].Tracking_sample_counter; // record the preamble sample stamp - // std::cout<< "Preamble detection for GLONASS L1 C/A SAT " << this->d_satellite; } } else if (d_stat == 1) // possible preamble lock @@ -279,14 +296,11 @@ int glonass_l1_ca_telemetry_decoder_gs::general_work(int noutput_items __attribu { // check preamble separation preamble_diff = static_cast(d_sample_counter - d_preamble_index); - // Record the PRN start sample index associated to the preamble - d_preamble_time_samples = static_cast(d_symbol_history[0].Tracking_sample_counter); if (abs(preamble_diff - GLONASS_GNAV_PREAMBLE_PERIOD_BITS) == 0) { // try to decode frame LOG(INFO) << "Starting string decoder for GLONASS L1 C/A SAT " << this->d_satellite; d_preamble_index = d_sample_counter; // record the preamble sample stamp - this->message_port_pub(pmt::mp("preamble_timestamp_samples"), pmt::mp(d_preamble_time_samples)); d_stat = 2; } else diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.h index 91bb10154..3151431ae 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_gs.h @@ -50,7 +50,7 @@ public: ~glonass_l1_ca_telemetry_decoder_gs() override; //!< Class destructor void set_satellite(const Gnss_Satellite &satellite) override; //!< Set satellite PRN void set_channel(int32_t channel) override; //!< Set receiver's channel - inline void reset() override {}; + void reset() override; //!< Clear synchronization state on channel re-acquisition /*! * \brief This is where all signal processing takes place @@ -81,7 +81,6 @@ private: std::string d_dump_filename; std::ofstream d_dump_file; - double d_preamble_time_samples; double d_TOW_at_current_symbol; // Variables for internal functionality diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.cc index 517888f3d..520e29e9e 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.cc @@ -55,7 +55,6 @@ glonass_l2_ca_telemetry_decoder_gs::glonass_l2_ca_telemetry_decoder_gs(const Tlm gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))), d_dump_filename(conf.dump_filename), - d_preamble_time_samples(0), d_TOW_at_current_symbol(0), d_sample_counter(0ULL), d_preamble_index(0ULL), @@ -73,8 +72,6 @@ glonass_l2_ca_telemetry_decoder_gs::glonass_l2_ca_telemetry_decoder_gs(const Tlm { configure_basic_outputs(); - this->message_port_register_out(pmt::mp("preamble_timestamp_samples")); - if (d_enable_navdata_monitor) { // register nav message monitor out @@ -224,6 +221,28 @@ void glonass_l2_ca_telemetry_decoder_gs::set_channel(int32_t channel) } +void glonass_l2_ca_telemetry_decoder_gs::reset() +{ + gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler + d_symbol_history.clear(); + d_stat = 0; + d_CRC_error_counter = 0; + d_flag_frame_sync = false; + d_flag_preamble = false; + // Invalidate the propagated TOW until a new string 5 is decoded; otherwise + // Flag_valid_word would remain true with a TOW offset by the outage duration + d_nav.set_flag_TOW_set(false); + d_nav.set_flag_TOW_new(false); + // Drop partially decoded ephemeris strings so that strings received before + // the outage cannot be combined with strings of a different frame + d_nav.set_flag_ephemeris_str_1(false); + d_nav.set_flag_ephemeris_str_2(false); + d_nav.set_flag_ephemeris_str_3(false); + d_nav.set_flag_ephemeris_str_4(false); + DLOG(INFO) << "Telemetry decoder reset for satellite " << d_satellite; +} + + int glonass_l2_ca_telemetry_decoder_gs::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { @@ -269,7 +288,6 @@ int glonass_l2_ca_telemetry_decoder_gs::general_work(int noutput_items __attribu LOG(INFO) << "Preamble detection for GLONASS L2 C/A SAT " << this->d_satellite; // Enter into frame pre-detection status d_stat = 1; - d_preamble_time_samples = d_symbol_history[0].Tracking_sample_counter; // record the preamble sample stamp } } else if (d_stat == 1) // possible preamble lock @@ -278,14 +296,11 @@ int glonass_l2_ca_telemetry_decoder_gs::general_work(int noutput_items __attribu { // check preamble separation preamble_diff = static_cast(d_sample_counter - d_preamble_index); - // Record the PRN start sample index associated to the preamble - d_preamble_time_samples = static_cast(d_symbol_history[0].Tracking_sample_counter); if (abs(preamble_diff - GLONASS_GNAV_PREAMBLE_PERIOD_BITS) == 0) { // try to decode frame LOG(INFO) << "Starting string decoder for GLONASS L2 C/A SAT " << this->d_satellite; d_preamble_index = d_sample_counter; // record the preamble sample stamp - this->message_port_pub(pmt::mp("preamble_timestamp_samples"), pmt::mp(d_preamble_time_samples)); d_stat = 2; } else diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.h index 2a256de2a..6856e9096 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l2_ca_telemetry_decoder_gs.h @@ -49,7 +49,7 @@ public: ~glonass_l2_ca_telemetry_decoder_gs() override; //!< Class destructor void set_satellite(const Gnss_Satellite &satellite) override; //!< Set satellite PRN void set_channel(int32_t channel) override; //!< Set receiver's channel - inline void reset() override {}; + void reset() override; //!< Clear synchronization state on channel re-acquisition /*! * \brief This is where all signal processing takes place @@ -78,7 +78,6 @@ private: std::string d_dump_filename; std::ofstream d_dump_file; - double d_preamble_time_samples; double d_TOW_at_current_symbol; uint64_t d_sample_counter; // Sample counter as an index (1,2,3,..etc) indicating number of samples processed diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.cc b/src/core/system_parameters/glonass_gnav_ephemeris.cc index 92afcb701..795196568 100644 --- a/src/core/system_parameters/glonass_gnav_ephemeris.cc +++ b/src/core/system_parameters/glonass_gnav_ephemeris.cc @@ -119,8 +119,7 @@ void Glonass_Gnav_Ephemeris::glot_to_gpst(double tod_offset, double glot2utc_cor const boost::gregorian::date d1(d_yr - J + 1.0, 1, 1); const boost::gregorian::days d2(d_N_T - 1); const boost::posix_time::ptime utc_time(d1 + d2, t); - const boost::gregorian::date utc_date = utc_time.date(); - boost::posix_time::ptime gps_time; + boost::posix_time::ptime gps_time = utc_time; // Adjust for leap second correction for (i = 0; GLONASS_LEAP_SECONDS[i][0] > 0; i++) @@ -136,10 +135,9 @@ void Glonass_Gnav_Ephemeris::glot_to_gpst(double tod_offset, double glot2utc_cor } } - // Total number of days - days = static_cast((utc_date - gps_epoch).days()); - - // Total number of seconds + // Days and seconds of day must be taken from the same (GPS) timestamp, + // since the leap second adjustment may roll gps_time over a day boundary + days = static_cast((gps_time.date() - gps_epoch).days()); sec_of_day = static_cast((gps_time.time_of_day()).total_seconds()); total_sec = days * 86400 + sec_of_day; diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.cc b/src/core/system_parameters/glonass_gnav_navigation_message.cc index 95aef4f0e..c0a88f148 100644 --- a/src/core/system_parameters/glonass_gnav_navigation_message.cc +++ b/src/core/system_parameters/glonass_gnav_navigation_message.cc @@ -560,8 +560,9 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame // parameters instead of almanac data if (d_frame_ID == 5) { - gnav_utc_model.d_B1 = static_cast(read_navigation_unsigned(string_bits, B1)); - gnav_utc_model.d_B2 = static_cast(read_navigation_unsigned(string_bits, B2)); + // B1 and B2 are sign-magnitude values (GLONASS ICD Table 4.9) + gnav_utc_model.d_B1 = static_cast(read_navigation_signed(string_bits, B1)) * TWO_N10; + gnav_utc_model.d_B2 = static_cast(read_navigation_signed(string_bits, B2)) * TWO_N16; } else if (d_frame_ID != 0) { diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.h b/src/core/system_parameters/glonass_gnav_navigation_message.h index eb6e5d129..5663659a6 100644 --- a/src/core/system_parameters/glonass_gnav_navigation_message.h +++ b/src/core/system_parameters/glonass_gnav_navigation_message.h @@ -148,6 +148,11 @@ public: return flag_TOW_set; } + inline void set_flag_TOW_set(bool tow_set) + { + flag_TOW_set = tow_set; + } + inline void set_flag_ephemeris_str_1(bool ephemeris_str_1) { flag_ephemeris_str_1 = ephemeris_str_1; diff --git a/src/core/system_parameters/glonass_gnav_utc_model.cc b/src/core/system_parameters/glonass_gnav_utc_model.cc index c402af550..53c9c6768 100644 --- a/src/core/system_parameters/glonass_gnav_utc_model.cc +++ b/src/core/system_parameters/glonass_gnav_utc_model.cc @@ -20,8 +20,10 @@ double Glonass_Gnav_Utc_Model::utc_time(double glonass_time_corrected) const { - // GLONASS Time is relative to UTC Moscow, so we simply add its time difference - double t_utc = glonass_time_corrected + 3.0 * 3600.0 + d_tau_c; + // GLONASS Time runs 3 hours ahead of UTC(SU): tUTC + 3h = tGLO + tau_c + // (GLONASS ICD Edition 5.1, Section 4.5). The result may be negative, + // meaning the UTC epoch falls in the previous day + double t_utc = glonass_time_corrected - 3.0 * 3600.0 + d_tau_c; return t_utc; } diff --git a/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc b/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc index 1ce515690..328d2b791 100644 --- a/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc +++ b/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc @@ -19,6 +19,7 @@ #include "GLONASS_L1_L2_CA.h" #include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_utc_model.h" #include "gnss_satellite.h" #include "gnss_signal_replica.h" @@ -243,3 +244,40 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT5) ASSERT_TRUE(week - true_week < FLT_EPSILON); ASSERT_TRUE(tow - true_tow < FLT_EPSILON); } + + +/*! + * \brief Testing conversion from GLONASST to GPST across the UTC day boundary + * \test The GLONASS time of day falls less than one leap-second interval + * before 03:00:00, so the UTC epoch lies just before midnight and the leap + * second correction rolls the GPS time into the next day + */ +TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT6) +{ + Glonass_Gnav_Ephemeris gnav_eph; + gnav_eph.d_yr = 2019; + gnav_eph.d_N_T = 1366; // 2019-09-27 in the GLONASS day scale + + int week = 0; + double tow = 0.0; + + // GLONASS tod 02:59:50 -> UTC 2019-09-26 23:59:50 -> GPST 2019-09-27 00:00:08 + gnav_eph.glot_to_gpst(10790, 0.0, 0.0, &week, &tow); + + EXPECT_EQ(week, 2072); + EXPECT_DOUBLE_EQ(tow, 432008.0); +} + + +/*! + * \brief Testing the GLONASST to UTC(SU) conversion of the UTC model: + * tUTC = tGLO + tau_c - 3 hrs (GLONASS ICD Edition 5.1, Section 4.5) + */ +TEST(GlonassGnavEphemerisTest, UtcModelUtcTime) +{ + Glonass_Gnav_Utc_Model gnav_utc_model; + gnav_utc_model.d_tau_c = -1.0 / 1024.0; + + // GLONASS tod 12:00:00 -> UTC 09:00:00 (minus tau_c correction) + EXPECT_DOUBLE_EQ(gnav_utc_model.utc_time(43200.0), 32400.0 - 1.0 / 1024.0); +}