From bc8d0bbe64ac87759212beba5aa36ed11fa1fc11 Mon Sep 17 00:00:00 2001 From: Damian Miralles Date: Sun, 13 Aug 2017 20:42:24 -0700 Subject: [PATCH] Adds unit test for RINEX and RTCM messages printer Adds set of unit test to check functionality of GLONASS processing for RINEX and RTCM messages. It also fixes a couple of bug fixes with formatting in existing code. --- .../glonass_gnav_ephemeris.h | 4 +- src/core/system_parameters/rtcm.cc | 50 ++++ .../pvt/rinex_printer_test.cc | 249 ++++++++++++++++++ .../signal-processing-blocks/pvt/rtcm_test.cc | 57 +++- 4 files changed, 350 insertions(+), 10 deletions(-) diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.h b/src/core/system_parameters/glonass_gnav_ephemeris.h index 153f5b5b1..3f8fa699c 100644 --- a/src/core/system_parameters/glonass_gnav_ephemeris.h +++ b/src/core/system_parameters/glonass_gnav_ephemeris.h @@ -95,8 +95,8 @@ public: double d_P_2; //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] double d_P_3; //!< Flag indicating a number of satellites for which almanac is transmitted within given frame: "1" corresponds to 5 satellites and "0" corresponds to 4 satellites [dimensionless] double d_P_4; //!< Flag to show that ephemeris parameters are present. "1" indicates that updated ephemeris or frequency/time parameters have been uploaded by the control segment [dimensionless] - double d_l3rd_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] - double d_l5th_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + double d_l3rd_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + double d_l5th_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] // Inmediate deliverables of ephemeris information //TODO check how freq channel is managed in gnav message. I think it is a number greater thn 0 diff --git a/src/core/system_parameters/rtcm.cc b/src/core/system_parameters/rtcm.cc index 7e11062a8..3a82d5647 100644 --- a/src/core/system_parameters/rtcm.cc +++ b/src/core/system_parameters/rtcm.cc @@ -3310,6 +3310,13 @@ boost::posix_time::ptime Rtcm::compute_Galileo_time(const Galileo_Ephemeris & ep } +boost::posix_time::ptime Rtcm::compute_GLONASS_time(const Glonass_Gnav_Ephemeris & eph, double obs_time) const +{ + boost::posix_time::ptime p_time = eph.compute_GLONASS_time(obs_time); + return p_time; +} + + unsigned int Rtcm::lock_time(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) { unsigned int lock_time_in_seconds; @@ -3385,6 +3392,49 @@ unsigned int Rtcm::lock_time(const Galileo_Ephemeris & eph, double obs_time, con } +unsigned int Rtcm::lock_time(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + unsigned int lock_time_in_seconds; + boost::posix_time::ptime current_time = Rtcm::compute_GLONASS_time(eph, obs_time); + + boost::posix_time::ptime last_lock_time; + std::string sig_(gnss_synchro.Signal); + if(sig_.compare("1C") == 0) + { + last_lock_time = Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN]; + } + if(sig_.compare("2C") == 0) + { + last_lock_time = Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN]; + } + + if(last_lock_time.is_not_a_date_time() )// || CHECK LLI!!......) + { + if(sig_.compare("1C") == 0) + { + Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN] = current_time; + } + if(sig_.compare("2C") == 0) + { + Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN] = current_time; + } + } + + boost::posix_time::time_duration lock_duration = current_time - current_time; + if(sig_.compare("1C") == 0) + { + lock_duration = current_time - Rtcm::glo_L1_last_lock_time[65 - gnss_synchro.PRN]; + } + if(sig_.compare("2C") == 0) + { + lock_duration = current_time - Rtcm::glo_L2_last_lock_time[65 - gnss_synchro.PRN]; + } + + lock_time_in_seconds = static_cast(lock_duration.total_seconds()); + return lock_time_in_seconds; +} + + unsigned int Rtcm::lock_time_indicator(unsigned int lock_time_period_s) { // Table 3.4-2 diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc index fdf1d7d2c..33ed3965c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc @@ -87,6 +87,35 @@ TEST(RinexPrinterTest, GalileoObsHeader) } +TEST(RinexPrinterTest, GlonassObsHeader) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph = Glonass_Gnav_Ephemeris(); + + std::shared_ptr rp1; + rp1 = std::make_shared(); + rp1->rinex_obs_header(rp1->obsFile, eph, 0.0); + rp1->obsFile.seekp(0); + + while(!rp1->obsFile.eof()) + { + std::getline(rp1->obsFile, line_str); + if(!no_more_finds) + { + if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + std::string expected_str("R 4 C1C L1C D1C S1C SYS / # / OBS TYPES "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + if(remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + line_aux.clear(); +} TEST(RinexPrinterTest, MixedObsHeader) @@ -133,6 +162,50 @@ TEST(RinexPrinterTest, MixedObsHeader) } +TEST(RinexPrinterTest, MixedObsHeaderGpsGlo) +{ + std::string line_aux; + std::string line_aux2; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph_glo = Glonass_Gnav_Ephemeris(); + const Gps_Ephemeris eph_gps = Gps_Ephemeris(); + + std::shared_ptr rp1; + rp1 = std::make_shared(); + rp1->rinex_obs_header(rp1->obsFile, eph_gps, eph_glo, 0.0, "1C"); + rp1->obsFile.seekp(0); + int systems_found = 0; + + while(!rp1->obsFile.eof()) + { + std::getline(rp1->obsFile, line_str); + if(!no_more_finds) + { + if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos) + { + systems_found++; + if(systems_found == 1) + { + line_aux = std::string(line_str); + } + if(systems_found == 2) + { + line_aux2 = std::string(line_str); + no_more_finds = true; + } + } + } + } + + std::string expected_str("G 4 C1C L1C D1C S1C SYS / # / OBS TYPES "); + std::string expected_str2("R 8 C1C L1C D1C S1C SYS / # / OBS TYPES "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + EXPECT_EQ(0, expected_str2.compare(line_aux2)); + if(remove(rp1->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} + + TEST(RinexPrinterTest, GalileoObsLog) { std::string line_aux; @@ -201,6 +274,74 @@ TEST(RinexPrinterTest, GalileoObsLog) } +TEST(RinexPrinterTest, GlonassObsLog) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph = Glonass_Gnav_Ephemeris(); + + std::shared_ptr rp; + rp = std::make_shared(); + rp->rinex_obs_header(rp->obsFile, eph, 0.0); + + std::map gnss_pseudoranges_map; + + Gnss_Synchro gs1 = Gnss_Synchro(); + Gnss_Synchro gs2 = Gnss_Synchro(); + Gnss_Synchro gs3 = Gnss_Synchro(); + Gnss_Synchro gs4 = Gnss_Synchro(); + + std::string sys = "R"; + gs1.System = *sys.c_str(); + gs2.System = *sys.c_str(); + gs3.System = *sys.c_str(); + gs4.System = *sys.c_str(); + + std::string sig = "1C"; + std::memcpy((void*)gs1.Signal, sig.c_str(), 3); + std::memcpy((void*)gs2.Signal, sig.c_str(), 3); + std::memcpy((void*)gs3.Signal, sig.c_str(), 3); + std::memcpy((void*)gs4.Signal, sig.c_str(), 3); + + gs1.PRN = 3; + gs2.PRN = 8; + gs3.PRN = 10; + gs4.PRN = 22; + + gs4.Pseudorange_m = 22000000; + gs4.Carrier_phase_rads = 23.4; + gs4.Carrier_Doppler_hz = 1534; + gs4.CN0_dB_hz = 42; + + gnss_pseudoranges_map.insert( std::pair(1,gs1) ); + gnss_pseudoranges_map.insert( std::pair(2,gs2) ); + gnss_pseudoranges_map.insert( std::pair(3,gs3) ); + gnss_pseudoranges_map.insert( std::pair(4,gs4) ); + + rp->log_rinex_obs(rp->obsFile, eph, 0.0, gnss_pseudoranges_map); + rp->obsFile.seekp(0); + + while(!rp->obsFile.eof()) + { + std::getline(rp->obsFile, line_str); + if(!no_more_finds) + { + if (line_str.find("R22", 0) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + + std::string expected_str("R22 22000000.000 7 3.724 7 1534.000 7 42.000 "); + EXPECT_EQ(0, expected_str.compare(line_aux)); + + if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} + + TEST(RinexPrinterTest, GpsObsLogDualBand) { std::string line_aux; @@ -473,3 +614,111 @@ TEST(RinexPrinterTest, MixedObsLog) if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } + + +TEST(RinexPrinterTest, MixedObsLogGpsGlo) +{ + std::string line_aux; + std::string line_str; + bool no_more_finds = false; + const Glonass_Gnav_Ephemeris eph_glo = Glonass_Gnav_Ephemeris(); + const Gps_Ephemeris eph_gps = Gps_Ephemeris(); + + std::shared_ptr rp; + rp = std::make_shared(); + rp->rinex_obs_header(rp->obsFile, eph_gps, eph_glo, 0.0, "1C"); + + std::map gnss_pseudoranges_map; + + Gnss_Synchro gs1 = Gnss_Synchro(); + Gnss_Synchro gs2 = Gnss_Synchro(); + Gnss_Synchro gs3 = Gnss_Synchro(); + Gnss_Synchro gs4 = Gnss_Synchro(); + Gnss_Synchro gs5 = Gnss_Synchro(); + Gnss_Synchro gs6 = Gnss_Synchro(); + Gnss_Synchro gs7 = Gnss_Synchro(); + Gnss_Synchro gs8 = Gnss_Synchro(); + + std::string sys = "G"; + gs1.System = *sys.c_str(); + gs2.System = *sys.c_str(); + gs3.System = *sys.c_str(); + gs4.System = *sys.c_str(); + + sys = "R"; + gs5.System = *sys.c_str(); + gs6.System = *sys.c_str(); + gs7.System = *sys.c_str(); + gs8.System = *sys.c_str(); + + std::string sig = "1C"; + std::memcpy((void*)gs1.Signal, sig.c_str(), 3); + std::memcpy((void*)gs2.Signal, sig.c_str(), 3); + std::memcpy((void*)gs3.Signal, sig.c_str(), 3); + std::memcpy((void*)gs4.Signal, sig.c_str(), 3); + + sig = "1C"; + std::memcpy((void*)gs5.Signal, sig.c_str(), 3); + std::memcpy((void*)gs6.Signal, sig.c_str(), 3); + std::memcpy((void*)gs7.Signal, sig.c_str(), 3); + std::memcpy((void*)gs8.Signal, sig.c_str(), 3); + + gs1.PRN = 3; + gs2.PRN = 8; + gs3.PRN = 14; + gs4.PRN = 16; + gs5.PRN = 3; + gs6.PRN = 16; + gs7.PRN = 14; + gs8.PRN = 16; + + gs2.Pseudorange_m = 22000002.1; + gs2.Carrier_phase_rads = 45.4; + gs2.Carrier_Doppler_hz = 321; + gs2.CN0_dB_hz = 39; + + gs4.Pseudorange_m = 22000000; + gs4.Carrier_phase_rads = 23.4; + gs4.Carrier_Doppler_hz = -1534; + gs4.CN0_dB_hz = 40; + + gs6.Pseudorange_m = 22000000; + gs6.Carrier_phase_rads = 52.1; + gs6.Carrier_Doppler_hz = 1534; + gs6.CN0_dB_hz = 41; + + gs8.Pseudorange_m = 22000000; + gs8.Carrier_phase_rads = 0.8; + gs8.Carrier_Doppler_hz = -20; + gs8.CN0_dB_hz = 42; + + gnss_pseudoranges_map.insert( std::pair(1,gs1) ); + gnss_pseudoranges_map.insert( std::pair(2,gs2) ); + gnss_pseudoranges_map.insert( std::pair(3,gs3) ); + gnss_pseudoranges_map.insert( std::pair(4,gs4) ); + gnss_pseudoranges_map.insert( std::pair(5,gs5) ); + gnss_pseudoranges_map.insert( std::pair(6,gs6) ); + gnss_pseudoranges_map.insert( std::pair(7,gs7) ); + gnss_pseudoranges_map.insert( std::pair(8,gs8) ); + + rp->log_rinex_obs(rp->obsFile, eph_gps, eph_glo, 0.0, gnss_pseudoranges_map); + + rp->obsFile.seekp(0); + + while(!rp->obsFile.eof()) + { + std::getline(rp->obsFile, line_str); + if(!no_more_finds) + { + if (line_str.find("R16", 0) != std::string::npos) + { + no_more_finds = true; + line_aux = std::string(line_str); + } + } + } + std::string expected_str("R16 22000000.000 7 0.127 7 -20.000 7 42.000 22000000.000 6 8.292 6 1534.000 6 41.000"); + EXPECT_EQ(0, expected_str.compare(line_aux)); + + if(remove(rp->obsfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc index 11bd5d7cc..2f8307ee4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/rtcm_test.cc @@ -276,6 +276,33 @@ TEST(RtcmTest, MT1019) } +TEST(RtcmTest, MT1020) +{ + auto rtcm = std::make_shared(); + bool expected_true = true; + + Glonass_Gnav_Ephemeris glonass_gnav_eph = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model glonass_gnav_utc_model = Glonass_Gnav_Utc_Model(); + Glonass_Gnav_Ephemeris glonass_gnav_eph_read = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model glonass_gnav_utc_model_read = Glonass_Gnav_Utc_Model(); + + glonass_gnav_eph.i_satellite_PRN = 3; + glonass_gnav_eph.d_t_b = 4; + glonass_gnav_eph.d_E_n = 2.0 * E_LSB; + glonass_gnav_eph.d_l3rd_n = true; + glonass_gnav_utc_model.d_tau_gps = 5; + std::string tx_msg = rtcm->print_MT1020(glonass_gnav_eph, glonass_gnav_utc_model); + + EXPECT_EQ(0, rtcm->read_MT1020(tx_msg, glonass_gnav_eph_read, glonass_gnav_utc_model_read)); + EXPECT_EQ(3, glonass_gnav_eph_read.i_satellite_PRN); + EXPECT_DOUBLE_EQ(4, glonass_gnav_eph_read.d_t_b); + EXPECT_DOUBLE_EQ( 2.0 * E_LSB, glonass_gnav_eph_read.d_E_n); + EXPECT_DOUBLE_EQ( 5, glonass_gnav_utc_model_read.d_tau_gps); + EXPECT_EQ(expected_true, glonass_gnav_eph_read.d_l3rd_n); + EXPECT_EQ(1, rtcm->read_MT1020(rtcm->bin_to_binary_data(rtcm->hex_to_bin("FFFFFFFFFFF")), glonass_gnav_eph_read, glonass_gnav_utc_model_read)); +} + + TEST(RtcmTest, MT1029) { auto rtcm = std::make_shared(); @@ -321,6 +348,7 @@ TEST(RtcmTest, MSMCell) auto rtcm = std::make_shared(); Gps_Ephemeris gps_eph = Gps_Ephemeris(); Galileo_Ephemeris gal_eph = Galileo_Ephemeris(); + Glonass_Gnav_Ephemeris glo_gnav_eph = Glonass_Gnav_Ephemeris(); std::map pseudoranges; Gnss_Synchro gnss_synchro; @@ -328,15 +356,18 @@ TEST(RtcmTest, MSMCell) Gnss_Synchro gnss_synchro3; Gnss_Synchro gnss_synchro4; Gnss_Synchro gnss_synchro5; + Gnss_Synchro gnss_synchro6; gnss_synchro.PRN = 4; gnss_synchro2.PRN = 8; gnss_synchro3.PRN = 32; gnss_synchro4.PRN = 10; gnss_synchro5.PRN = 10; + gnss_synchro6.PRN = 10; std::string gps = "G"; std::string gal = "E"; + std::string glo = "R"; std::string c1 = "1C"; std::string s2 = "2S"; @@ -347,24 +378,28 @@ TEST(RtcmTest, MSMCell) gnss_synchro3.System = *gps.c_str(); gnss_synchro4.System = *gal.c_str(); gnss_synchro5.System = *gps.c_str(); + gnss_synchro6.System = *glo.c_str(); std::memcpy(static_cast(gnss_synchro.Signal), x5.c_str(), 3); std::memcpy(static_cast(gnss_synchro2.Signal), s2.c_str(), 3); std::memcpy(static_cast(gnss_synchro3.Signal), c1.c_str(), 3); std::memcpy(static_cast(gnss_synchro4.Signal), x5.c_str(), 3); std::memcpy(static_cast(gnss_synchro5.Signal), c1.c_str(), 3); + std::memcpy(static_cast(gnss_synchro6.Signal), c1.c_str(), 3); gnss_synchro.Pseudorange_m = 20000000.0; gnss_synchro2.Pseudorange_m = 20001010.0; gnss_synchro3.Pseudorange_m = 24002020.0; gnss_synchro4.Pseudorange_m = 20003010.1; gnss_synchro5.Pseudorange_m = 22003010.1; + gnss_synchro6.Pseudorange_m = 22003010.1; pseudoranges.insert(std::pair(1, gnss_synchro)); pseudoranges.insert(std::pair(2, gnss_synchro2)); pseudoranges.insert(std::pair(3, gnss_synchro3)); pseudoranges.insert(std::pair(4, gnss_synchro4)); pseudoranges.insert(std::pair(5, gnss_synchro5)); + pseudoranges.insert(std::pair(6, gnss_synchro5)); unsigned int ref_id = 1234; unsigned int clock_steering_indicator = 0; @@ -376,10 +411,12 @@ TEST(RtcmTest, MSMCell) gps_eph.i_satellite_PRN = gnss_synchro2.PRN; gal_eph.i_satellite_PRN = gnss_synchro.PRN; + glo_gnav_eph.i_satellite_PRN = gnss_synchro.PRN; std::string MSM1 = rtcm->print_MSM_1(gps_eph, {}, gal_eph, + glo_gnav_eph, obs_time, pseudoranges, ref_id, @@ -397,14 +434,17 @@ TEST(RtcmTest, MSMCell) EXPECT_EQ(0, MSM1_bin.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010101100")); // check cell mask std::map pseudoranges2; + pseudoranges2.insert(std::pair(1, gnss_synchro6)); pseudoranges2.insert(std::pair(1, gnss_synchro5)); pseudoranges2.insert(std::pair(2, gnss_synchro4)); pseudoranges2.insert(std::pair(3, gnss_synchro3)); pseudoranges2.insert(std::pair(4, gnss_synchro2)); pseudoranges2.insert(std::pair(5, gnss_synchro)); + pseudoranges2.insert(std::pair(6, gnss_synchro)); std::string MSM1_2 = rtcm->print_MSM_1(gps_eph, {}, gal_eph, + glo_gnav_eph, obs_time, pseudoranges2, ref_id, @@ -416,22 +456,23 @@ TEST(RtcmTest, MSMCell) std::string MSM1_bin_2 = rtcm->binary_data_to_bin(MSM1_2); EXPECT_EQ(0, MSM1_bin_2.substr(size_header + size_msg_length + 169, Nsat * Nsig).compare("001010101100")); // check cell mask - Gnss_Synchro gnss_synchro6; - gnss_synchro6.PRN = 10; - gnss_synchro6.System = *gps.c_str(); - std::memcpy(static_cast(gnss_synchro6.Signal), s2.c_str(), 3); - gnss_synchro6.Pseudorange_m = 24000000.0; + Gnss_Synchro gnss_synchro7; + gnss_synchro7.PRN = 10; + gnss_synchro7.System = *gps.c_str(); + std::memcpy(static_cast(gnss_synchro7.Signal), s2.c_str(), 3); + gnss_synchro7.Pseudorange_m = 24000000.0; std::map pseudoranges3; pseudoranges3.insert(std::pair(1, gnss_synchro)); pseudoranges3.insert(std::pair(2, gnss_synchro2)); - pseudoranges3.insert(std::pair(3, gnss_synchro6)); + pseudoranges3.insert(std::pair(3, gnss_synchro7)); pseudoranges3.insert(std::pair(4, gnss_synchro4)); pseudoranges3.insert(std::pair(5, gnss_synchro5)); std::string MSM1_3 = rtcm->print_MSM_1(gps_eph, {}, gal_eph, + {}, obs_time, pseudoranges3, ref_id, @@ -498,7 +539,7 @@ TEST(RtcmTest, MSM1) gps_eph.i_satellite_PRN = gnss_synchro.PRN; std::string MSM1 = rtcm->print_MSM_1(gps_eph, - {}, {}, + {}, {}, {}, obs_time, pseudoranges, ref_id, @@ -545,7 +586,7 @@ TEST(RtcmTest, MSM1) pseudoranges2.insert(std::pair(3, gnss_synchro2)); pseudoranges2.insert(std::pair(4, gnss_synchro)); std::string MSM1_2 = rtcm->print_MSM_1(gps_eph, - {}, {}, + {}, {}, {}, obs_time, pseudoranges2, ref_id,