Glonass improvements: define resets in telemetry decoders, remove unused async port, fix decoding of some parameters

This commit is contained in:
Carles Fernandez committed 2026-06-11 15:22:25 +02:00
1 parent 925e2e56c2
commit b6fe42e19c
10 files changed
+103 -30

No files matched your search

+3 -1
View File
@@ -2861,7 +2861,9 @@ void Rinex_Printer::log_rinex_nav_glo_gnav(const std::map<int32_t, Glonass_Gnav_
line.clear();
// -------- BROADCAST ORBIT - 1
out << get_nav_broadcast_orbit(&eph.d_Xn, &eph.d_VXn, &eph.d_AXn, &eph.d_B_n, d_version) << '\n';
// RINEX expects the health flag in the MSB of the 3-bit Bn word (0 = OK)
const auto health_d = static_cast<double>(((static_cast<int32_t>(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<double>(eph.i_satellite_freq_channel);
@@ -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<int32_t>(d_sample_counter - d_preamble_index);
// Record the PRN start sample index associated to the preamble
d_preamble_time_samples = static_cast<double>(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
@@ -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
@@ -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<int32_t>(d_sample_counter - d_preamble_index);
// Record the PRN start sample index associated to the preamble
d_preamble_time_samples = static_cast<double>(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
@@ -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
@@ -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<double>((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<double>((gps_time.date() - gps_epoch).days());
sec_of_day = static_cast<double>((gps_time.time_of_day()).total_seconds());
total_sec = days * 86400 + sec_of_day;
@@ -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<double>(read_navigation_unsigned(string_bits, B1));
gnav_utc_model.d_B2 = static_cast<double>(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<double>(read_navigation_signed(string_bits, B1)) * TWO_N10;
gnav_utc_model.d_B2 = static_cast<double>(read_navigation_signed(string_bits, B2)) * TWO_N16;
}
else if (d_frame_ID != 0)
{
@@ -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;
@@ -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;
}
@@ -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);
}