mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-10-04 23:01:50 +00:00
Implement Glonass handling of new leap second (KP word)
This commit is contained in:
@@ -47,26 +47,19 @@ TEST(GlonassGnavEphemerisTest, ComputeGlonassTime)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2016;
|
||||
gnav_eph.d_N_T = 367;
|
||||
boost::posix_time::time_duration t(0, 0, 7560);
|
||||
boost::gregorian::date d(gnav_eph.d_yr, 1, 1);
|
||||
boost::gregorian::days d2(gnav_eph.d_N_T);
|
||||
d = d + d2;
|
||||
gnav_eph.d_N_T = 367; // 2016-01-02 in the GLONASS day scale
|
||||
|
||||
boost::gregorian::date expected_gdate;
|
||||
boost::posix_time::time_duration expected_gtime;
|
||||
|
||||
boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
expected_gdate = gtime.date();
|
||||
expected_gtime = gtime.time_of_day();
|
||||
const boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
const boost::gregorian::date gdate = gtime.date();
|
||||
const boost::posix_time::time_duration gtod = gtime.time_of_day();
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(expected_gdate.year() - d.year() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.month() - d.month() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.day() - d.day() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.hours() - t.hours() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.minutes() - t.minutes() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.seconds() - t.seconds() < FLT_EPSILON);
|
||||
EXPECT_EQ(gdate.year(), 2016);
|
||||
EXPECT_EQ(gdate.month(), 1);
|
||||
EXPECT_EQ(gdate.day(), 2);
|
||||
EXPECT_EQ(gtod.hours(), 2);
|
||||
EXPECT_EQ(gtod.minutes(), 6);
|
||||
EXPECT_EQ(gtod.seconds(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,26 +67,19 @@ TEST(GlonassGnavEphemerisTest, ComputeGlonassTime2019)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2019;
|
||||
gnav_eph.d_N_T = 1366;
|
||||
boost::posix_time::time_duration t(0, 0, 7560);
|
||||
boost::gregorian::date d(gnav_eph.d_yr, 1, 1);
|
||||
boost::gregorian::days d2(gnav_eph.d_N_T);
|
||||
d = d + d2;
|
||||
gnav_eph.d_N_T = 1366; // 2019-09-27 in the GLONASS day scale
|
||||
|
||||
boost::gregorian::date expected_gdate;
|
||||
boost::posix_time::time_duration expected_gtime;
|
||||
|
||||
boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
expected_gdate = gtime.date();
|
||||
expected_gtime = gtime.time_of_day();
|
||||
const boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
const boost::gregorian::date gdate = gtime.date();
|
||||
const boost::posix_time::time_duration gtod = gtime.time_of_day();
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(expected_gdate.year() - d.year() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.month() - d.month() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.day() - d.day() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.hours() - t.hours() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.minutes() - t.minutes() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.seconds() - t.seconds() < FLT_EPSILON);
|
||||
EXPECT_EQ(gdate.year(), 2019);
|
||||
EXPECT_EQ(gdate.month(), 9);
|
||||
EXPECT_EQ(gdate.day(), 27);
|
||||
EXPECT_EQ(gtod.hours(), 2);
|
||||
EXPECT_EQ(gtod.minutes(), 6);
|
||||
EXPECT_EQ(gtod.seconds(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,26 +87,19 @@ TEST(GlonassGnavEphemerisTest, ComputeGlonassTime2020)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2020;
|
||||
gnav_eph.d_N_T = 62;
|
||||
boost::posix_time::time_duration t(0, 0, 7560);
|
||||
boost::gregorian::date d(gnav_eph.d_yr, 1, 1);
|
||||
boost::gregorian::days d2(gnav_eph.d_N_T);
|
||||
d = d + d2;
|
||||
gnav_eph.d_N_T = 62; // 2020-03-02, a Monday
|
||||
|
||||
boost::gregorian::date expected_gdate;
|
||||
boost::posix_time::time_duration expected_gtime;
|
||||
|
||||
boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
expected_gdate = gtime.date();
|
||||
expected_gtime = gtime.time_of_day();
|
||||
const boost::posix_time::ptime gtime = gnav_eph.compute_GLONASS_time(7560);
|
||||
const boost::gregorian::date gdate = gtime.date();
|
||||
const boost::posix_time::time_duration gtod = gtime.time_of_day();
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(expected_gdate.year() - d.year() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.month() - d.month() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gdate.day() - d.day() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.hours() - t.hours() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.minutes() - t.minutes() < FLT_EPSILON);
|
||||
ASSERT_TRUE(expected_gtime.seconds() - t.seconds() < FLT_EPSILON);
|
||||
EXPECT_EQ(gdate.year(), 2020);
|
||||
EXPECT_EQ(gdate.month(), 3);
|
||||
EXPECT_EQ(gdate.day(), 2);
|
||||
EXPECT_EQ(gtod.hours(), 2);
|
||||
EXPECT_EQ(gtod.minutes(), 6);
|
||||
EXPECT_EQ(gtod.seconds(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,21 +111,21 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT1)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2004;
|
||||
gnav_eph.d_N_T = 366 + 28;
|
||||
gnav_eph.d_N_T = 366 + 28; // 2004-01-29 in the GLONASS day scale, a Thursday
|
||||
|
||||
double glo2utc = 3600 * 3;
|
||||
double tod = 48600;
|
||||
int week = 0.0;
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
double true_leap_sec = 13;
|
||||
double true_week = 1307;
|
||||
double true_tow = 480600 + true_leap_sec;
|
||||
int true_week = 1255;
|
||||
double true_tow = 345600 + true_leap_sec + tod;
|
||||
|
||||
gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow);
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(week - true_week < FLT_EPSILON);
|
||||
ASSERT_TRUE(tow - true_tow < FLT_EPSILON);
|
||||
EXPECT_EQ(week, true_week);
|
||||
EXPECT_DOUBLE_EQ(tow, true_tow);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,21 +137,21 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT2)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2016;
|
||||
gnav_eph.d_N_T = 268;
|
||||
gnav_eph.d_N_T = 268; // 2016-09-24, a Saturday
|
||||
|
||||
double glo2utc = 3600 * 3;
|
||||
double tod = 7560;
|
||||
int week = 0.0;
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
double true_leap_sec = 17;
|
||||
double true_week = 1915;
|
||||
int true_week = 1915;
|
||||
double true_tow = 518400 + true_leap_sec + tod;
|
||||
|
||||
gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow);
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(week - true_week < FLT_EPSILON);
|
||||
ASSERT_TRUE(tow - true_tow < FLT_EPSILON);
|
||||
EXPECT_EQ(week, true_week);
|
||||
EXPECT_DOUBLE_EQ(tow, true_tow);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,21 +163,21 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT3)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2016;
|
||||
gnav_eph.d_N_T = 62;
|
||||
gnav_eph.d_N_T = 62; // 2016-03-02, a Wednesday
|
||||
|
||||
double glo2utc = 3600 * 3;
|
||||
double tod = 7560;
|
||||
int week = 0.0;
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
double true_leap_sec = 17;
|
||||
double true_week = 1886;
|
||||
int true_week = 1886;
|
||||
double true_tow = 259200 + true_leap_sec + tod;
|
||||
|
||||
gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow);
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(week - true_week < FLT_EPSILON);
|
||||
ASSERT_TRUE(tow - true_tow < FLT_EPSILON);
|
||||
EXPECT_EQ(week, true_week);
|
||||
EXPECT_DOUBLE_EQ(tow, true_tow);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,21 +185,21 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT4)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2019;
|
||||
gnav_eph.d_N_T = 1366;
|
||||
gnav_eph.d_N_T = 1366; // 2019-09-27 in the GLONASS day scale, a Friday
|
||||
|
||||
double glo2utc = 3600 * 3;
|
||||
double tod = 7560;
|
||||
int week = 0.0;
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
double true_leap_sec = 18;
|
||||
double true_week = 2072;
|
||||
double true_tow = 447120 + true_leap_sec + tod;
|
||||
int true_week = 2072;
|
||||
double true_tow = 432000 + true_leap_sec + tod;
|
||||
|
||||
gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow);
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(week - true_week < FLT_EPSILON);
|
||||
ASSERT_TRUE(tow - true_tow < FLT_EPSILON);
|
||||
EXPECT_EQ(week, true_week);
|
||||
EXPECT_DOUBLE_EQ(tow, true_tow);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,21 +207,21 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT5)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2020;
|
||||
gnav_eph.d_N_T = 62;
|
||||
gnav_eph.d_N_T = 62; // 2020-03-02, a Monday
|
||||
|
||||
double glo2utc = 3600 * 3;
|
||||
double tod = 7560;
|
||||
int week = 0.0;
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
double true_leap_sec = 18;
|
||||
double true_week = 2095;
|
||||
double true_tow = 259200 + true_leap_sec + tod;
|
||||
int true_week = 2095;
|
||||
double true_tow = 86400 + true_leap_sec + tod;
|
||||
|
||||
gnav_eph.glot_to_gpst(tod + glo2utc, 0.0, 0.0, &week, &tow);
|
||||
|
||||
// Perform assertions of decoded fields
|
||||
ASSERT_TRUE(week - true_week < FLT_EPSILON);
|
||||
ASSERT_TRUE(tow - true_tow < FLT_EPSILON);
|
||||
EXPECT_EQ(week, true_week);
|
||||
EXPECT_DOUBLE_EQ(tow, true_tow);
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +248,28 @@ TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsT6)
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Testing conversion from GLONASST to GPST when a leap second announced
|
||||
* by the KP word is in effect but not yet in the receiver's leap second table
|
||||
*/
|
||||
TEST(GlonassGnavEphemerisTest, ConvertGlonassT2GpsTKpLeapSecond)
|
||||
{
|
||||
Glonass_Gnav_Ephemeris gnav_eph;
|
||||
gnav_eph.d_yr = 2019;
|
||||
gnav_eph.d_N_T = 1366; // 2019-09-27, a Friday
|
||||
gnav_eph.d_kp_leap_correction_s = 1.0;
|
||||
|
||||
int week = 0;
|
||||
double tow = 0.0;
|
||||
|
||||
// UTC tod 02:06:00 -> GPST tow = 5 days + 7560 s + 18 s + 1 s announced leap
|
||||
gnav_eph.glot_to_gpst(7560 + 10800, 0.0, 0.0, &week, &tow);
|
||||
|
||||
EXPECT_EQ(week, 2072);
|
||||
EXPECT_DOUBLE_EQ(tow, 432000.0 + 7560.0 + 18.0 + 1.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)
|
||||
|
||||
@@ -299,3 +299,88 @@ TEST(GlonassGnavNavigationMessageTest, String14RequiresKnownFrame)
|
||||
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_almanac(10).d_n_A, 0.0);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief KP announces a UTC leap second correction at the end of the current
|
||||
* quarter: 01 = +1 s, 11 = -1 s (GLONASS ICD Edition 5.1, Table 4.12)
|
||||
*/
|
||||
TEST(GlonassGnavNavigationMessageTest, KpAnnouncedLeapSecondMapping)
|
||||
{
|
||||
Glonass_Gnav_Utc_Model gnav_utc_model;
|
||||
|
||||
gnav_utc_model.d_KP = 0.0;
|
||||
EXPECT_EQ(gnav_utc_model.announced_leap_second(), 0);
|
||||
gnav_utc_model.d_KP = 1.0;
|
||||
EXPECT_EQ(gnav_utc_model.announced_leap_second(), 1);
|
||||
gnav_utc_model.d_KP = 2.0;
|
||||
EXPECT_EQ(gnav_utc_model.announced_leap_second(), 0);
|
||||
gnav_utc_model.d_KP = 3.0;
|
||||
EXPECT_EQ(gnav_utc_model.announced_leap_second(), -1);
|
||||
}
|
||||
|
||||
|
||||
// Synthetic strings (with valid Hamming code bits) for a scenario where KP
|
||||
// announces a +1 s UTC leap second at the end of a quarter. GLONASS day 913
|
||||
// of four-year interval 8 is 2026-07-01, which starts at 2026-06-30 21:00
|
||||
// UTC; the announced leap second event is at 2026-07-01 00:00:00 UTC
|
||||
std::string str1_kp_a("0000100000001001111000000000000000000000000000000000000000000000000000000000000011000"); // tk = 02:30:00 (UTC 2026-06-30 23:30)
|
||||
std::string str1_kp_b("0000100000001100101100000000000000000000000000000000000000000000000000000000000011000"); // tk = 03:11:00 (UTC 2026-07-01 00:11)
|
||||
std::string str1_kp_c("0000100000001101111000000000000000000000000000000000000000000000000000000000011011111"); // tk = 03:30:00 (UTC 2026-07-01 00:30)
|
||||
std::string str4_kp("0010000000000000000000000000000000000000000000000000000000001110010001101100001011101"); // N_T = 913, n = 22
|
||||
std::string str5_kp("0010101110010001000000000000000000000000000000000010000000000000000000000000001100000"); // N_A = 913, N_4 = 8 -> year 2026
|
||||
std::string str6_kp_f5("0011000010110000000000000000000000000000000000000000000000000000000000000000001001100"); // almanac slot 22 identifies frame 5
|
||||
std::string str14_kp1("0111000000000000000000000001000000000000000000000000000000000000000000000000011101000"); // KP = 01 (+1 s)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief A leap second announced by KP before the end of the quarter is
|
||||
* applied to the GLONASS to GPS time conversion once the event epoch is
|
||||
* reached, so the TOW remains correct even if the event is not yet in the
|
||||
* receiver's leap second table
|
||||
*/
|
||||
TEST(GlonassGnavNavigationMessageTest, KpLeapSecondAppliedAfterQuarterEnd)
|
||||
{
|
||||
Glonass_Gnav_Navigation_Message gnav_nav_message;
|
||||
|
||||
gnav_nav_message.string_decoder(str1_kp_a); // tk = 02:30:00 GLONASS
|
||||
gnav_nav_message.set_flag_ephemeris_str_2(true);
|
||||
gnav_nav_message.set_flag_ephemeris_str_3(true);
|
||||
gnav_nav_message.string_decoder(str4_kp);
|
||||
gnav_nav_message.string_decoder(str5_kp); // computes the TOW
|
||||
const double tow_before = gnav_nav_message.get_ephemeris().d_TOW;
|
||||
gnav_nav_message.string_decoder(str6_kp_f5);
|
||||
gnav_nav_message.string_decoder(str14_kp1);
|
||||
|
||||
// The correction is announced but the event has not occurred yet
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_utc_model().d_KP, 1.0);
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_ephemeris().d_kp_leap_correction_s, 0.0);
|
||||
|
||||
gnav_nav_message.string_decoder(str1_kp_b); // tk = 03:11:00, past the event
|
||||
gnav_nav_message.string_decoder(str5_kp); // recomputes the TOW
|
||||
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_ephemeris().d_kp_leap_correction_s, 1.0);
|
||||
// 2460 s elapsed between the two TOW computations, plus the leap second
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_ephemeris().d_TOW - tow_before, 2461.0);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief If KP still announces a correction right after a quarter boundary
|
||||
* (broadcast not updated yet), the leap second has just been applied to UTC,
|
||||
* and the receiver must account for it immediately
|
||||
*/
|
||||
TEST(GlonassGnavNavigationMessageTest, KpLeapSecondAppliedRightAfterBoundary)
|
||||
{
|
||||
Glonass_Gnav_Navigation_Message gnav_nav_message;
|
||||
|
||||
gnav_nav_message.string_decoder(str1_kp_c); // tk = 03:30:00 (UTC 00:30, 30 min after the boundary)
|
||||
gnav_nav_message.set_flag_ephemeris_str_2(true);
|
||||
gnav_nav_message.set_flag_ephemeris_str_3(true);
|
||||
gnav_nav_message.string_decoder(str4_kp);
|
||||
gnav_nav_message.string_decoder(str5_kp);
|
||||
gnav_nav_message.string_decoder(str6_kp_f5);
|
||||
gnav_nav_message.string_decoder(str14_kp1);
|
||||
|
||||
EXPECT_DOUBLE_EQ(gnav_nav_message.get_ephemeris().d_kp_leap_correction_s, 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user