diff --git a/.gitignore b/.gitignore index 2d1eebded..a128f1558 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ docs/latex docs/GNSS-SDR_manual.pdf src/tests/data/output.dat thirdparty/ +.settings .project .cproject +.idea +cmake-build-debug/ /install .DS_Store diff --git a/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf b/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf new file mode 100644 index 000000000..4f3d513dc --- /dev/null +++ b/conf/gnss-sdr_GLONASS_L1_CA_ibyte.conf @@ -0,0 +1,76 @@ +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +GNSS-SDR.internal_fs_hz=6625000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=File_Signal_Source +SignalSource.filename=/archive/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_schar_1m.bin +SignalSource.item_type=ibyte +SignalSource.sampling_frequency=6625000 +;SignalSource.freq=0 +;SignalSource.samples=66250000 +SignalSource.samples=0 +SignalSource.dump=false; +SignalSource.dump_filename=/archive/signal_glonass.bin + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner.implementation=Signal_Conditioner +DataTypeAdapter.implementation=Ibyte_To_Complex +InputFilter.implementation=Pass_Through +InputFilter.item_type=gr_complex +Resampler.implementation=Direct_Resampler +Resampler.sample_freq_in=6625000 +Resampler.sample_freq_out=6625000 +Resampler.item_type=gr_complex + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1G.count=5 +Channels.in_acquisition=5 +Channel0.signal=1G +Channel1.signal=1G +Channel2.signal=1G +Channel3.signal=1G +Channel4.signal=1G + +Channel0.satellite=11 +Channel1.satellite=2 +Channel2.satellite=18 +Channel3.satellite=12 +Channel4.satellite=21 +; Possible list includes 2, 12, 21, 22 + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition +Acquisition_1G.item_type=gr_complex +Acquisition_1G.threshold=0.0 +Acquisition_1G.pfa=0.0001 +Acquisition_1G.if=0 +Acquisition_1G.doppler_max=10000 +Acquisition_1G.doppler_step=250 +Acquisition_1G.dump=false; +Acquisition_1G.dump_filename=/archive/glo_acquisition.dat +;Acquisition_1G.coherent_integration_time_ms=10 + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking +Tracking_1G.item_type=gr_complex +Tracking_1G.if=1 +Tracking_1G.early_late_space_chips=0.5 +Tracking_1G.pll_bw_hz=25.0; +Tracking_1G.dll_bw_hz=3.0; +Tracking_1G.dump=true; +Tracking_1G.dump_filename=/archive/glo_tracking_ch_ + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1G.implementation=GPS_L1_CA_Telemetry_Decoder + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.averaging_depth=100 +PVT.flag_averaging=true +PVT.output_rate_ms=10 +PVT.display_rate_ms=500 diff --git a/conf/gnss-sdr_GPS_L1_gr_complex.conf b/conf/gnss-sdr_GPS_L1_gr_complex.conf index 662d42b12..3cf123514 100644 --- a/conf/gnss-sdr_GPS_L1_gr_complex.conf +++ b/conf/gnss-sdr_GPS_L1_gr_complex.conf @@ -34,7 +34,7 @@ DataTypeAdapter.dump=false DataTypeAdapter.dump_filename=../data/DataTypeAdapter.dat ;######### CHANNELS GLOBAL CONFIG ############ -Channels_1C.count=8 +Channels_1C.count=5 Channels.in_acquisition=1 Channel.signal=1C @@ -51,6 +51,7 @@ Acquisition_1C.threshold=0.05 Acquisition_1C.doppler_max=10000 Acquisition_1C.doppler_step=250 + ;######### TRACKING GLOBAL CONFIG ############ Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_C_Aid_Tracking Tracking_1C.item_type=gr_complex diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index 8e1e9fbe0..2dbd59145 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -84,17 +84,24 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, unsigned short rtcm_station_id = configuration->property(role + ".rtcm_station_id", 1234); // RTCM message rates: least common multiple with output_rate_ms int rtcm_MT1019_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1019_rate_ms", 5000), output_rate_ms); + int rtcm_MT1020_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1020_rate_ms", 5000), output_rate_ms); int rtcm_MT1045_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1045_rate_ms", 5000), output_rate_ms); int rtcm_MSM_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MSM_rate_ms", 1000), output_rate_ms); int rtcm_MT1077_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1077_rate_ms", rtcm_MSM_rate_ms), output_rate_ms); + int rtcm_MT1087_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1087_rate_ms", rtcm_MSM_rate_ms), output_rate_ms); int rtcm_MT1097_rate_ms = boost::math::lcm(configuration->property(role + ".rtcm_MT1097_rate_ms", rtcm_MSM_rate_ms), output_rate_ms); std::map rtcm_msg_rate_ms; rtcm_msg_rate_ms[1019] = rtcm_MT1019_rate_ms; + rtcm_msg_rate_ms[1020] = rtcm_MT1020_rate_ms; rtcm_msg_rate_ms[1045] = rtcm_MT1045_rate_ms; for (int k = 1071; k < 1078; k++) // All GPS MSM { rtcm_msg_rate_ms[k] = rtcm_MT1077_rate_ms; } + for (int k = 1081; k < 1088; k++) // All GLONASS MSM + { + rtcm_msg_rate_ms[k] = rtcm_MT1087_rate_ms; + } for (int k = 1091; k < 1098; k++) // All Galileo MSM { rtcm_msg_rate_ms[k] = rtcm_MT1097_rate_ms; @@ -138,38 +145,48 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, * 20 | GPS L5 + Galileo E5b * 21 | GPS L1 C/A + Galileo E1B + GPS L2C * 22 | GPS L1 C/A + Galileo E1B + GPS L5 + * 23 | GLONASS L1 C/A + * 24 | GLONASS L2 C/A + * 25 | GLONASS L1 C/A + GLONASS L2 C/A + * 26 | GPS L1 C/A + GLONASS L1 C/A + * 27 | Galileo E1B + GLONASS L1 C/A */ int gps_1C_count = configuration->property("Channels_1C.count", 0); int gps_2S_count = configuration->property("Channels_2S.count", 0); int gal_1B_count = configuration->property("Channels_1B.count", 0); int gal_E5a_count = configuration->property("Channels_5X.count", 0); // GPS L5 or Galileo E5a ? int gal_E5b_count = configuration->property("Channels_7X.count", 0); + int glo_1G_count = configuration->property("Channels_1G.count", 0); unsigned int type_of_receiver = 0; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 1; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 2; + if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 1; + if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 2; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 4; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 5; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 6; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 4; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 5; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0)) type_of_receiver = 6; - if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 7; + if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 7; //if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 8; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 9; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 10; - if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 11; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 12; + if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 9; + if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 10; + if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0)) type_of_receiver = 11; + if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 12; //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 13; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 14; - if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 15; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 14; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0)) type_of_receiver = 15; //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 16; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0)) type_of_receiver = 17; - if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0)) type_of_receiver = 18; + if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count != 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 17; + if( (gps_1C_count == 0) && (gps_2S_count != 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count != 0) && (glo_1G_count == 0)) type_of_receiver = 18; //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 19; //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 20; - if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0)) type_of_receiver = 21; + if( (gps_1C_count != 0) && (gps_2S_count != 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0)) type_of_receiver = 21; //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count = 0)) type_of_receiver = 22; - + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0)) type_of_receiver = 23; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count == 0) && (glo_2R_count != 0)) type_of_receiver = 24; + //if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0) && (glo_1G_count != 0)) type_of_receiver = 25; + if( (gps_1C_count != 0) && (gps_2S_count == 0) && (gal_1B_count == 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0)) type_of_receiver = 26; + if( (gps_1C_count == 0) && (gps_2S_count == 0) && (gal_1B_count != 0) && (gal_E5a_count == 0) && (gal_E5b_count == 0) && (glo_1G_count != 0)) type_of_receiver = 27; //RTKLIB PVT solver options // Settings 1 int positioning_mode = -1; @@ -192,10 +209,10 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, } int num_bands = 0; - if ((gps_1C_count > 0) || (gal_1B_count > 0)) num_bands = 1; - if (((gps_1C_count > 0) || (gal_1B_count > 0)) && (gps_2S_count > 0) ) num_bands = 2; - if (((gps_1C_count > 0) || (gal_1B_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0)) ) num_bands = 2; - if (((gps_1C_count > 0) || (gal_1B_count > 0)) && (gps_2S_count > 0) && ((gal_E5a_count > 0) || (gal_E5b_count > 0))) num_bands = 3; + if ((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) num_bands = 1; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && (gps_2S_count > 0) ) num_bands = 2; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && ((gal_E5a_count > 0) || (gal_E5b_count > 0)) ) num_bands = 2; + if (((gps_1C_count > 0) || (gal_1B_count > 0) || (glo_1G_count > 0)) && (gps_2S_count > 0) && ((gal_E5a_count > 0) || (gal_E5b_count > 0))) num_bands = 3; int number_of_frequencies = configuration->property(role + ".num_bands", num_bands); /* (1:L1, 2:L1+L2, 3:L1+L2+L5) */ if( (number_of_frequencies < 1) || (number_of_frequencies > 3) ) { @@ -207,6 +224,7 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, if( (elevation_mask < 0.0) || (elevation_mask > 90.0) ) { //warn user and set the default + LOG(WARNING) << "Erroneous Elevation Mask. Setting to default value of 15.0 degrees"; elevation_mask = 15.0; } @@ -214,6 +232,7 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, if( (dynamics_model < 0) || (dynamics_model > 2) ) { //warn user and set the default + LOG(WARNING) << "Erroneous Dynamics Model configuration. Setting to default value of (0:none)"; dynamics_model = 0; } @@ -275,10 +294,12 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, int nsys = 0; if ((gps_1C_count > 0) || (gps_2S_count > 0)) nsys += SYS_GPS; if ((gal_1B_count > 0) || (gal_E5a_count > 0) || (gal_E5b_count > 0)) nsys += SYS_GAL; + if ((glo_1G_count > 0)) nsys += SYS_GLO; int navigation_system = configuration->property(role + ".navigation_system", nsys); /* (SYS_XXX) see src/algorithms/libs/rtklib/rtklib.h */ if( (navigation_system < 1) || (navigation_system > 255) ) /* GPS: 1 SBAS: 2 GPS+SBAS: 3 Galileo: 8 Galileo+GPS: 9 GPS+SBAS+Galileo: 11 All: 255 */ { //warn user and set the default + LOG(WARNING) << "Erroneous Navigation System. Setting to default value of (0:none)"; navigation_system = nsys; } @@ -305,6 +326,7 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, if( (integer_ambiguity_resolution_glo < 0) || (integer_ambiguity_resolution_glo > 3) ) { //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for GLONASS . Setting to default value of (1:on)"; integer_ambiguity_resolution_glo = 1; } @@ -312,6 +334,7 @@ RtklibPvt::RtklibPvt(ConfigurationInterface* configuration, if( (integer_ambiguity_resolution_bds < 0) || (integer_ambiguity_resolution_bds > 1) ) { //warn user and set the default + LOG(WARNING) << "Erroneous Integer Ambiguity Resolution for BEIDOU . Setting to default value of (1:on)"; integer_ambiguity_resolution_bds = 1; } diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc index 152fc6f1d..f5bf5e503 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.cc @@ -181,6 +181,36 @@ void rtklib_pvt_cc::msg_handler_telemetry(pmt::pmt_t msg) DLOG(INFO) << "New Galileo Almanac has arrived "; } + //**************** GLONASS GNAV Telemetry ************************** + else if(pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) + { + // ### GLONASS GNAV EPHEMERIS ### + std::shared_ptr glonass_gnav_eph; + glonass_gnav_eph = boost::any_cast>(pmt::any_ref(msg)); + // TODO Add GLONASS with gps week number and tow, + // insert new ephemeris record + DLOG(INFO) << "GLONASS GNAV New Ephemeris record inserted in global map with TOW =" << glonass_gnav_eph->d_TOW + << ", GLONASS GNAV Week Number =" << glonass_gnav_eph->d_WN + << " and Ephemeris IOD = " << glonass_gnav_eph->compute_GLONASS_time(glonass_gnav_eph->d_t_b); + // update/insert new ephemeris record to the global ephemeris map + d_ls_pvt->glonass_gnav_ephemeris_map[glonass_gnav_eph->i_satellite_PRN] = *glonass_gnav_eph; + } + else if(pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) + { + // ### GLONASS GNAV UTC MODEL ### + std::shared_ptr glonass_gnav_utc_model; + glonass_gnav_utc_model = boost::any_cast>(pmt::any_ref(msg)); + d_ls_pvt->glonass_gnav_utc_model = *glonass_gnav_utc_model; + DLOG(INFO) << "New GLONASS GNAV UTC record has arrived "; + } + else if(pmt::any_ref(msg).type() == typeid(std::shared_ptr) ) + { + // ### GLONASS GNAV Almanac ### + std::shared_ptr glonass_gnav_almanac; + glonass_gnav_almanac = boost::any_cast>(pmt::any_ref(msg)); + d_ls_pvt->glonass_gnav_almanac = *glonass_gnav_almanac; + DLOG(INFO) << "New GLONASS GNAV Almanac has arrived "; + } else { LOG(WARNING) << "msg_handler_telemetry unknown object type!"; @@ -249,6 +279,14 @@ rtklib_pvt_cc::rtklib_pvt_cc(unsigned int nchannels, bool dump, std::string dump { d_rtcm_MT1019_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set } + if(rtcm_msg_rate_ms.find(1020) != rtcm_msg_rate_ms.end()) + { + d_rtcm_MT1020_rate_ms = rtcm_msg_rate_ms[1020]; + } + else + { + d_rtcm_MT1020_rate_ms = boost::math::lcm(5000, d_output_rate_ms); // default value if not set + } if(rtcm_msg_rate_ms.find(1045) != rtcm_msg_rate_ms.end()) { d_rtcm_MT1045_rate_ms = rtcm_msg_rate_ms[1045]; @@ -265,6 +303,14 @@ rtklib_pvt_cc::rtklib_pvt_cc(unsigned int nchannels, bool dump, std::string dump { d_rtcm_MT1077_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set } + if(rtcm_msg_rate_ms.find(1087) != rtcm_msg_rate_ms.end()) // whatever between 1081 and 1087 + { + d_rtcm_MT1087_rate_ms = rtcm_msg_rate_ms[1087]; + } + else + { + d_rtcm_MT1087_rate_ms = boost::math::lcm(1000, d_output_rate_ms); // default value if not set + } if(rtcm_msg_rate_ms.find(1097) != rtcm_msg_rate_ms.end()) // whatever between 1091 and 1097 { d_rtcm_MT1097_rate_ms = rtcm_msg_rate_ms[1097]; @@ -286,8 +332,10 @@ rtklib_pvt_cc::rtklib_pvt_cc(unsigned int nchannels, bool dump, std::string dump d_rx_time = 0.0; last_pvt_display_T_rx_s = 0.0; last_RTCM_1019_output_time = 0.0; + last_RTCM_1020_output_time = 0.0; last_RTCM_1045_output_time = 0.0; last_RTCM_1077_output_time = 0.0; + last_RTCM_1087_output_time = 0.0; last_RTCM_1097_output_time = 0.0; last_RTCM_MSM_output_time = 0.0; last_RINEX_obs_output_time = 0.0; @@ -335,7 +383,7 @@ rtklib_pvt_cc::~rtklib_pvt_cc() msgctl(sysv_msqid, IPC_RMID, NULL); //save GPS L2CM ephemeris to XML file - std::string file_name = "eph_GPS_L2CM.xml"; + std::string file_name="eph_GPS_L2CM.xml"; if (d_ls_pvt->gps_cnav_ephemeris_map.size() > 0) { @@ -347,7 +395,7 @@ rtklib_pvt_cc::~rtklib_pvt_cc() ofs.close(); LOG(INFO) << "Saved GPS L2CM Ephemeris map data"; } - catch (const std::exception & e) + catch (std::exception& e) { LOG(WARNING) << e.what(); } @@ -403,6 +451,28 @@ rtklib_pvt_cc::~rtklib_pvt_cc() LOG(WARNING) << "Failed to save Galileo E1 Ephemeris, map is empty"; } + //save GLONASS GNAV ephemeris to XML file + file_name = "eph_GLONASS_GNAV.xml"; + + if (d_ls_pvt->glonass_gnav_ephemeris_map.size() > 0) + { + try + { + std::ofstream ofs(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); + boost::archive::xml_oarchive xml(ofs); + xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", d_ls_pvt->glonass_gnav_ephemeris_map); + ofs.close(); + LOG(INFO) << "Saved GLONASS GNAV Ephemeris map data"; + } + catch (std::exception& e) + { + LOG(WARNING) << e.what(); + } + } + else + { + LOG(WARNING) << "Failed to save GLONASS GNAV Ephemeris, map is empty"; + } if (d_dump_file.is_open() == true) { try @@ -447,14 +517,17 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite bool flag_display_pvt = false; bool flag_compute_pvt_output = false; bool flag_write_RTCM_1019_output = false; + bool flag_write_RTCM_1020_output = false; bool flag_write_RTCM_1045_output = false; bool flag_write_RTCM_1077_output = false; + bool flag_write_RTCM_1087_output = false; bool flag_write_RTCM_1097_output = false; bool flag_write_RTCM_MSM_output = false; bool flag_write_RINEX_obs_output = false; bool flag_write_RINEX_nav_output = false; unsigned int gps_channel = 0; unsigned int gal_channel = 0; + unsigned int glo_channel = 0; gnss_observables_map.clear(); const Gnss_Synchro **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer @@ -467,10 +540,13 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite std::map::const_iterator tmp_eph_iter_gps = d_ls_pvt->gps_ephemeris_map.find(in[i][epoch].PRN); std::map::const_iterator tmp_eph_iter_gal = d_ls_pvt->galileo_ephemeris_map.find(in[i][epoch].PRN); std::map::const_iterator tmp_eph_iter_cnav = d_ls_pvt->gps_cnav_ephemeris_map.find(in[i][epoch].PRN); + std::map::const_iterator tmp_eph_iter_glo_gnav = d_ls_pvt->glonass_gnav_ephemeris_map.find(in[i][epoch].PRN); if(((tmp_eph_iter_gps->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("1C") == 0)) || ((tmp_eph_iter_cnav->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("2S") == 0)) || ((tmp_eph_iter_gal->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("1B") == 0)) - || ((tmp_eph_iter_gal->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("5X") == 0))) + || ((tmp_eph_iter_gal->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("5X") == 0)) + || ((tmp_eph_iter_glo_gnav->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("1C") == 0)) + || ((tmp_eph_iter_glo_gnav->second.i_satellite_PRN == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal).compare("2C") == 0))) { // store valid observables in a map. gnss_observables_map.insert(std::pair(i, in[i][epoch])); @@ -497,6 +573,14 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite d_rtcm_printer->lock_time(d_ls_pvt->gps_cnav_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time } } + if(d_ls_pvt->glonass_gnav_ephemeris_map.size() > 0) + { + if(tmp_eph_iter_glo_gnav != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + //d_rtcm_printer->lock_time(d_ls_pvt->glonass_gnav_ephemeris_map.find(in[i][epoch].PRN)->second, in[i][epoch].RX_time, in[i][epoch]); // keep track of locking time + } + } + } } @@ -529,7 +613,11 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite flag_write_RTCM_1019_output = true; last_RTCM_1019_output_time = current_RX_time; } - + if ((std::fabs(current_RX_time - last_RTCM_1020_output_time) * 1000.0 >= static_cast(d_rtcm_MT1020_rate_ms)) && (d_rtcm_MT1020_rate_ms != 0) ) // allows deactivating messages by setting rate = 0 + { + flag_write_RTCM_1020_output = true; + last_RTCM_1020_output_time = current_RX_time; + } if ((std::fabs(current_RX_time - last_RTCM_1045_output_time) * 1000.0 >= static_cast(d_rtcm_MT1045_rate_ms)) && (d_rtcm_MT1045_rate_ms != 0) ) { flag_write_RTCM_1045_output = true; @@ -541,7 +629,11 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite flag_write_RTCM_1077_output = true; last_RTCM_1077_output_time = current_RX_time; } - + if ((std::fabs(current_RX_time - last_RTCM_1087_output_time) * 1000.0 >= static_cast(d_rtcm_MT1087_rate_ms)) && (d_rtcm_MT1087_rate_ms != 0) ) + { + flag_write_RTCM_1087_output = true; + last_RTCM_1087_output_time = current_RX_time; + } if ((std::fabs(current_RX_time - last_RTCM_1097_output_time) * 1000.0 >= static_cast(d_rtcm_MT1097_rate_ms)) && (d_rtcm_MT1097_rate_ms != 0) ) { flag_write_RTCM_1097_output = true; @@ -613,6 +705,11 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite * 20 | GPS L5 + Galileo E5b * 21 | GPS L1 C/A + Galileo E1B + GPS L2C * 22 | GPS L1 C/A + Galileo E1B + GPS L5 + * 23 | GLONASS L1 C/A + * 24 | GLONASS L2 C/A + * 25 | GLONASS L1 C/A + GLONASS L2 C/A + * 26 | GPS L1 C/A + GLONASS L1 C/A + * 27 | Galileo E1B + GLONASS L1 C/A */ // ####################### RINEX FILES ################# @@ -620,6 +717,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite std::map::const_iterator galileo_ephemeris_iter; std::map::const_iterator gps_ephemeris_iter; std::map::const_iterator gps_cnav_ephemeris_iter; + std::map::const_iterator glonass_gnav_ephemeris_iter; std::map::const_iterator gnss_observables_iter; if (!b_rinex_header_written) // & we have utc data in nav message! @@ -627,6 +725,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.cbegin(); gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.cbegin(); gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.cbegin(); + glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.cbegin(); if(type_of_rx == 1) // GPS L1 C/A only { @@ -736,6 +835,58 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite b_rinex_header_written = true; // do not write header anymore } } + if(type_of_rx == 23) // GLONASS L1 C/A only + { + std::string signal("1C"); + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.cend()) + { + rp->rinex_obs_header(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + } + if(type_of_rx == 24) // GLONASS L2 C/A only + { + std::string signal("2C"); + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.cend()) + { + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + } + if(type_of_rx == 25) // GLONASS L1 C/A + GLONASS L2 C/A + { + std::string signal("1C 2C"); + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.cend()) + { + rp->rinex_obs_header(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, signal); + rp->rinex_nav_header(rp->navGloFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + } + + if(type_of_rx == 26) // GPS L1 C/A + GLONASS L1 C/A + { + if ((glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.cend()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) ) + { + std::string glo_signal("1C"); + rp->rinex_obs_header(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal); + rp->rinex_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + } + if(type_of_rx == 27) // Galileo E1B + GLONASS L1 C/A + { + if ((glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.cend()) && (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.cend()) ) + { + std::string glo_signal("1C"); + std::string gal_signal("1B"); + rp->rinex_obs_header(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, glo_signal, gal_signal); + rp->rinex_nav_header(rp->navMixFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_written = true; // do not write header anymore + } + } } if(b_rinex_header_written) // The header is already written, we can now log the navigation message data { @@ -765,10 +916,23 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite { rp->log_rinex_nav(rp->navGalFile, d_ls_pvt->galileo_ephemeris_map); } + if((type_of_rx == 23) || (type_of_rx == 24) || (type_of_rx == 25)) // GLONASS L1 C/A, GLONASS L2 C/A + { + rp->log_rinex_nav(rp->navGloFile, d_ls_pvt->glonass_gnav_ephemeris_map); + } + if(type_of_rx == 26) // GPS L1 C/A + GLONASS L1 C/A + { + rp->log_rinex_nav(rp->navMixFile, d_ls_pvt->gps_ephemeris_map, d_ls_pvt->glonass_gnav_ephemeris_map); + } + if(type_of_rx == 27) // Galileo E1B + GLONASS L1 C/A + { + rp->log_rinex_nav(rp->navMixFile, d_ls_pvt->galileo_ephemeris_map, d_ls_pvt->glonass_gnav_ephemeris_map); + } } galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.cbegin(); gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.cbegin(); gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.cbegin(); + glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.cbegin(); // Log observables into the RINEX file if(flag_write_RINEX_obs_output) @@ -890,6 +1054,73 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite b_rinex_header_updated = true; } } + if(type_of_rx == 23) // GLONASS L1 C/A only + { + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1C"); + } + if (!b_rinex_header_updated && (d_ls_pvt->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navGloFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_ls_pvt->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + } + if(type_of_rx == 24) // GLONASS L2 C/A only + { + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "2C"); + } + if (!b_rinex_header_updated && (d_ls_pvt->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navGloFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_ls_pvt->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + } + if(type_of_rx == 25) // GLONASS L1 C/A + GLONASS L2 C/A + { + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + rp->log_rinex_obs(rp->obsFile, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, "1C 2C"); + } + if (!b_rinex_header_updated && (d_ls_pvt->glonass_gnav_utc_model.d_tau_c != 0)) + { + rp->update_nav_header(rp->navMixFile, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + rp->update_obs_header(rp->obsFile, d_ls_pvt->glonass_gnav_utc_model); + b_rinex_header_updated = true; + } + } + if(type_of_rx == 26) // GPS L1 C/A + GLONASS L1 C/A + { + if ((glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) && (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) ) + { + rp->log_rinex_obs(rp->obsFile, gps_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + } + if (!b_rinex_header_updated && (d_ls_pvt->gps_utc_model.d_A0 != 0)) + { + rp->update_obs_header(rp->obsFile, d_ls_pvt->gps_utc_model); + rp->update_nav_header(rp->navMixFile, d_ls_pvt->gps_iono, d_ls_pvt->gps_utc_model, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + } + if(type_of_rx == 27) // Galileo E1B + GLONASS L1 C/A + { + if ((glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) && (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) ) + { + std::string glo_signal("1C"); + rp->log_rinex_obs(rp->obsFile, galileo_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map); + + } + if (!b_rinex_header_updated && (d_ls_pvt->galileo_utc_model.A0_6 != 0)) + { + rp->update_obs_header(rp->obsFile, d_ls_pvt->galileo_utc_model); + rp->update_nav_header(rp->navMixFile, d_ls_pvt->galileo_iono, d_ls_pvt->galileo_utc_model, d_ls_pvt->galileo_almanac, d_ls_pvt->glonass_gnav_utc_model, d_ls_pvt->glonass_gnav_almanac); + b_rinex_header_updated = true; // do not write header anymore + } + } } } @@ -912,7 +1143,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } } } @@ -931,7 +1162,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite gal_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.cbegin(); if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } } } @@ -952,7 +1183,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite gps_cnav_ephemeris_iter = d_ls_pvt->gps_cnav_ephemeris_map.cbegin(); if ((gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.cend()) ) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } } } @@ -1010,14 +1241,165 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } } if(flag_write_RTCM_MSM_output == true) { if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + } + } + if((type_of_rx == 23) || (type_of_rx == 24) || (type_of_rx == 25)) // GLONASS + { + if(flag_write_RTCM_1020_output == true) + { + for(std::map::iterator glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.begin(); glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end(); glonass_gnav_ephemeris_iter++ ) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_ephemeris_iter->second, d_ls_pvt->glonass_gnav_utc_model); + } + } + + std::map::iterator glo_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.begin(); + + if (glo_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glo_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + b_rtcm_writing_started = true; + } + if(type_of_rx == 26) // GPS L1 C/A + GLONASS L1 C/A + { + if(flag_write_RTCM_1019_output == true) + { + for(gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.begin(); gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end(); gps_ephemeris_iter++ ) + { + d_rtcm_printer->Print_Rtcm_MT1019(gps_ephemeris_iter->second); + } + } + if(flag_write_RTCM_1020_output == true) + { + for(std::map::iterator glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.begin(); glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end(); glonass_gnav_ephemeris_iter++ ) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_ephemeris_iter->second, d_ls_pvt->glonass_gnav_utc_model); + } + } + if(flag_write_RTCM_MSM_output == true) + { + //gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.end(); + //galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.end(); + unsigned int i = 0; + for (gnss_observables_iter = gnss_observables_map.begin(); gnss_observables_iter != gnss_observables_map.end(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if(gps_channel == 0) + { + if(system.compare("G") == 0) + { + // This is a channel with valid GPS signal + gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) + { + gps_channel = i; + } + } + } + if(glo_channel == 0) + { + if(system.compare("R") == 0) + { + glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + glo_channel = i; + } + } + } + i++; + } + if(flag_write_RTCM_MSM_output == true) + { + + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + if(flag_write_RTCM_MSM_output == true) + { + if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + } + } + if(type_of_rx == 27) // GLONASS L1 C/A + Galileo E1B + { + if(flag_write_RTCM_1020_output == true) + { + for(std::map::iterator glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.begin(); glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end(); glonass_gnav_ephemeris_iter++ ) + { + d_rtcm_printer->Print_Rtcm_MT1020(glonass_gnav_ephemeris_iter->second, d_ls_pvt->glonass_gnav_utc_model); + } + } + if(flag_write_RTCM_1045_output == true) + { + for(galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.begin(); galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end(); galileo_ephemeris_iter++ ) + { + d_rtcm_printer->Print_Rtcm_MT1045(galileo_ephemeris_iter->second); + } + } + if(flag_write_RTCM_MSM_output == true) + { + //gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.end(); + //galileo_ephemeris_iter = d_ls_pvt->galileo_ephemeris_map.end(); + unsigned int i = 0; + for (gnss_observables_iter = gnss_observables_map.begin(); gnss_observables_iter != gnss_observables_map.end(); gnss_observables_iter++) + { + std::string system(&gnss_observables_iter->second.System, 1); + if(gps_channel == 0) + { + if(system.compare("G") == 0) + { + // This is a channel with valid GPS signal + gps_ephemeris_iter = d_ls_pvt->gps_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end()) + { + gps_channel = i; + } + } + } + if(glo_channel == 0) + { + if(system.compare("R") == 0) + { + glonass_gnav_ephemeris_iter = d_ls_pvt->glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + glo_channel = i; + } + } + } + i++; + } + if(flag_write_RTCM_MSM_output == true) + { + + if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + } + } + if(flag_write_RTCM_MSM_output == true) + { + + if (glonass_gnav_ephemeris_iter != d_ls_pvt->glonass_gnav_ephemeris_map.end()) + { + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, {}, glonass_gnav_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } } } @@ -1037,7 +1419,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } b_rtcm_writing_started = true; } @@ -1053,7 +1435,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if (gal_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.cend()) { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, gal_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } b_rtcm_writing_started = true; } @@ -1069,7 +1451,7 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if ((gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.cend()) && (gps_cnav_ephemeris_iter != d_ls_pvt->gps_cnav_ephemeris_map.cend())) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, gps_cnav_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } b_rtcm_writing_started = true; } @@ -1122,12 +1504,12 @@ int rtklib_pvt_cc::work (int noutput_items, gr_vector_const_void_star &input_ite if (gps_ephemeris_iter != d_ls_pvt->gps_ephemeris_map.end() && (d_rtcm_MT1077_rate_ms != 0)) { - d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, gps_ephemeris_iter->second, {}, {}, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } if (galileo_ephemeris_iter != d_ls_pvt->galileo_ephemeris_map.end() && (d_rtcm_MT1097_rate_ms != 0) ) { - d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); + d_rtcm_printer->Print_Rtcm_MSM(7, {}, {}, galileo_ephemeris_iter->second, {}, d_rx_time, gnss_observables_map, 0, 0, 0, 0, 0); } b_rtcm_writing_started = true; } diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h index a188c5809..a46d26180 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_cc.h @@ -99,10 +99,12 @@ private: bool b_rinex_header_written; bool b_rinex_header_updated; bool b_rtcm_writing_started; - int d_rtcm_MT1045_rate_ms; - int d_rtcm_MT1019_rate_ms; - int d_rtcm_MT1077_rate_ms; - int d_rtcm_MT1097_rate_ms; + int d_rtcm_MT1045_rate_ms; //!< Galileo Broadcast Ephemeris + int d_rtcm_MT1019_rate_ms; //!< GPS Broadcast Ephemeris (orbits) + int d_rtcm_MT1020_rate_ms; //!< GLONASS Broadcast Ephemeris (orbits) + int d_rtcm_MT1077_rate_ms; //!< The type 7 Multiple Signal Message format for the USA’s GPS system, popular + int d_rtcm_MT1087_rate_ms; //!< GLONASS MSM7. The type 7 Multiple Signal Message format for the Russian GLONASS system + int d_rtcm_MT1097_rate_ms; //!< Galileo MSM7. The type 7 Multiple Signal Message format for Europe’s Galileo system int d_rtcm_MSM_rate_ms; int d_last_status_print_seg; //for status printer @@ -122,8 +124,10 @@ private: double d_rx_time; double last_pvt_display_T_rx_s; double last_RTCM_1019_output_time; + double last_RTCM_1020_output_time; double last_RTCM_1045_output_time; double last_RTCM_1077_output_time; + double last_RTCM_1087_output_time; double last_RTCM_1097_output_time; double last_RTCM_MSM_output_time; double last_RINEX_obs_output_time; diff --git a/src/algorithms/PVT/libs/nmea_printer.cc b/src/algorithms/PVT/libs/nmea_printer.cc index 97ab793a7..b7d55d67f 100644 --- a/src/algorithms/PVT/libs/nmea_printer.cc +++ b/src/algorithms/PVT/libs/nmea_printer.cc @@ -727,6 +727,3 @@ std::string Nmea_Printer::get_GPGGA() return sentence_str.str(); //$GPGGA,104427.591,5920.7009,N,01803.2938,E,1,05,3.3,78.2,M,23.2,M,0.0,0000*4A } - - - diff --git a/src/algorithms/PVT/libs/rinex_printer.cc b/src/algorithms/PVT/libs/rinex_printer.cc index 4631270d2..06508ee75 100644 --- a/src/algorithms/PVT/libs/rinex_printer.cc +++ b/src/algorithms/PVT/libs/rinex_printer.cc @@ -58,12 +58,14 @@ Rinex_Printer::Rinex_Printer(int conf_version) sbsfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_SBAS"); navGalfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_GAL_NAV"); navMixfilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_MIXED_NAV"); + navGlofilename = Rinex_Printer::createFilename("RINEX_FILE_TYPE_GLO_NAV"); Rinex_Printer::navFile.open(navfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::obsFile.open(obsfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::sbsFile.open(sbsfilename, std::ios::out | std::ios::app); Rinex_Printer::navGalFile.open(navGalfilename, std::ios::out | std::ios::in | std::ios::app); Rinex_Printer::navMixFile.open(navMixfilename, std::ios::out | std::ios::in | std::ios::app); + Rinex_Printer::navGloFile.open(navGlofilename, std::ios::out | std::ios::in | std::ios::app); // RINEX v3.02 codes satelliteSystem["GPS"] = "G"; @@ -194,16 +196,19 @@ Rinex_Printer::Rinex_Printer(int conf_version) Rinex_Printer::~Rinex_Printer() { // close RINEX files - long posn, poso, poss, posng, posmn; + long posn, poso, poss, posng, posmn, posnr; posn = navFile.tellp(); poso = obsFile.tellp(); poss = sbsFile.tellp(); posng = navGalFile.tellp(); posmn = navMixFile.tellp(); + posnr = navGloFile.tellp(); + Rinex_Printer::navFile.close(); Rinex_Printer::obsFile.close(); Rinex_Printer::sbsFile.close(); Rinex_Printer::navGalFile.close(); + Rinex_Printer::navGloFile.close(); // If nothing written, erase the files. if (posn == 0) { @@ -225,6 +230,10 @@ Rinex_Printer::~Rinex_Printer() { if(remove(navMixfilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } + if (posnr == 0) + { + if(remove(navGlofilename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; + } } @@ -399,6 +408,341 @@ std::string Rinex_Printer::getLocalTime() } +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} + std::string line; + stringVersion = "3.02"; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("R: GLONASS"); + line += std::string(10, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GLONASS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GLGP"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + // TODO hOW TO MAKE THIS IN GLONASS, the leap second is internally given + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} //Avoid compiler warning + std::string line; + stringVersion = "3.02"; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GPSA"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 1 + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 2 + line.clear(); + line += std::string("GLGP"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 3 + line.clear(); + line += std::string("GPUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_t_OT), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LS), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LSF), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_LSF), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_DN), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Galileo_Almanac& galileo_almanac, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} //Avoid compiler warning + //Avoid compiler warning, there is not time system correction between Galileo and GLONASS + if(galileo_almanac.A_0G_10){} + std::string line; + stringVersion = "3.02"; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += std::string("N: GNSS NAV DATA"); + line += std::string(4, ' '); + line += std::string("M: MIXED"); + line += std::string(12, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GNSS NAVIGATION MESSAGE FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line ionospheric info 1 + line.clear(); + line += std::string("GAL "); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line += std::string(7, ' '); + line += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + // -------- Line system time correction + line.clear(); + line += std::string("GAUT"); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.t0t_6), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WNot_6), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line system time correction 1 + line.clear(); + line += std::string("GLUT"); + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 17); + line += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line += std::string(10, ' '); + line += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 6 leap seconds + // For leap second information, see http://www.endruntechnologies.com/leap.htm + line.clear(); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLS_6), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLSF_6), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WN_LSF_6), 6); + line += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.DN_6), 6); + line += std::string(36, ' '); + line += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- End of Header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + void Rinex_Printer::rinex_nav_header(std::fstream& out, const Galileo_Iono& iono, const Galileo_Utc_Model& utc_model, const Galileo_Almanac& galileo_almanac) { std::string line; @@ -1048,6 +1392,80 @@ void Rinex_Printer::rinex_sbs_header(std::fstream& out) } +void Rinex_Printer::update_nav_header(std::fstream& out, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} //Avoid compiler warning + std::vector data; + std::string line_aux; + + long pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while(!out.eof()) + { + std::getline(out, line_str); + + if(!no_more_finds) + { + line_aux.clear(); + + if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLGP", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLGP"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navGlofilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int i = 0; i < static_cast(data.size()) - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navGlofilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC info." << std::endl; +} + + void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& utc_model, const Galileo_Almanac& galileo_almanac) { std::vector data; @@ -1133,7 +1551,7 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& gal out.close(); out.open(navGalfilename, std::ios::out | std::ios::trunc); out.seekp(0); - for (int i = 0; i < static_cast(data.size()) - 1; i++) + for (int i = 0; i < (int) data.size() - 1; i++) { out << data[i] << std::endl; } @@ -1521,6 +1939,212 @@ void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_ion } +void Rinex_Printer::update_nav_header(std::fstream& out, const Gps_Iono& gps_iono, const Gps_Utc_Model& gps_utc_model, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} //Avoid compiler warning + std::vector data; + std::string line_aux; + + long pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while(!out.eof()) + { + std::getline(out, line_str); + + if(!no_more_finds) + { + line_aux.clear(); + + if (line_str.find("GPSA", 0) != std::string::npos) + { + line_aux += std::string("GPSA"); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha0, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha1, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha2, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_iono.d_alpha3, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GPUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GPUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A0, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(gps_utc_model.d_A1, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_t_OT), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_T + 1024), 5); // valid until 2019 + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLGP", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLGP"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_gps, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LS), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.d_DeltaT_LSF), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_WN_LSF), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(gps_utc_model.i_DN), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int i = 0; i < (int) data.size() - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + +void Rinex_Printer::update_nav_header(std::fstream& out, const Galileo_Iono& galileo_iono, const Galileo_Utc_Model& galileo_utc_model, const Galileo_Almanac& galileo_almanac, const Glonass_Gnav_Utc_Model& glonass_gnav_utc_model, const Glonass_Gnav_Almanac& glonass_gnav_almanac) +{ + if(glonass_gnav_almanac.i_satellite_freq_channel){} //Avoid compiler warning + //Avoid compiler warning, there is not time system correction between Galileo and GLONASS + if(galileo_almanac.A_0G_10){} + std::vector data; + std::string line_aux; + + long pos = out.tellp(); + out.seekp(0); + data.clear(); + + bool no_more_finds = false; + std::string line_str; + + while(!out.eof()) + { + std::getline(out, line_str); + + if(!no_more_finds) + { + line_aux.clear(); + + if ((line_str.find("GAL", 0) != std::string::npos) && (line_str.find("IONOSPHERIC CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAL "); + line_aux += std::string(1, ' '); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai0_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai1_5, 10, 2), 12); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_iono.ai2_5, 10, 2), 12); + double zero = 0.0; + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(zero, 10, 2), 12); + line_aux += std::string(7, ' '); + line_aux += Rinex_Printer::leftJustify("IONOSPHERIC CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GAUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GAUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A0_6, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(galileo_utc_model.A1_6, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.t0t_6), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WNot_6), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if ((line_str.find("GLUT", 0) != std::string::npos) && (line_str.find("TIME SYSTEM CORR", 59) != std::string::npos)) + { + line_aux += std::string("GLUT"); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(glonass_gnav_utc_model.d_tau_c, 16, 2), 18); + line_aux += Rinex_Printer::rightJustify(Rinex_Printer::doub2for(0.0, 15, 2), 16); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 7); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(0.0), 5); + line_aux += std::string(10, ' '); + line_aux += Rinex_Printer::leftJustify("TIME SYSTEM CORR", 20); + data.push_back(line_aux); + } + else if (line_str.find("LEAP SECONDS", 59) != std::string::npos) + { + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLS_6), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.Delta_tLSF_6), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.WN_LSF_6), 6); + line_aux += Rinex_Printer::rightJustify(boost::lexical_cast(galileo_utc_model.DN_6), 6); + line_aux += std::string(36, ' '); + line_aux += Rinex_Printer::leftJustify("LEAP SECONDS", 20); + data.push_back(line_aux); + } + else if (line_str.find("END OF HEADER", 59) != std::string::npos) + { + data.push_back(line_str); + no_more_finds = true; + } + else + { + data.push_back(line_str); + } + + } + else + { + data.push_back(line_str); + } + } + + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::trunc); + out.seekp(0); + for (int i = 0; i < (int) data.size() - 1; i++) + { + out << data[i] << std::endl; + } + out.close(); + out.open(navMixfilename, std::ios::out | std::ios::app); + out.seekp(pos); + std::cout << "The RINEX Navigation file header has been updated with UTC and IONO info." << std::endl; +} + + void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) { std::string line; @@ -2194,6 +2818,200 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& eph_map) +{ + std::string line; + std::map::const_iterator glonass_gnav_ephemeris_iter; + + for(glonass_gnav_ephemeris_iter = eph_map.begin(); + glonass_gnav_ephemeris_iter != eph_map.end(); + glonass_gnav_ephemeris_iter++) + { + // -------- SV / EPOCH / SV CLK + boost::posix_time::ptime p_utc_time = Rinex_Printer::compute_GLONASS_time(glonass_gnav_ephemeris_iter->second, glonass_gnav_ephemeris_iter->second.d_t_k); + std::string timestring = boost::posix_time::to_iso_string(p_utc_time); + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + std::string seconds (timestring, 13, 2); + if (version == 2) + { + line += Rinex_Printer::rightJustify(boost::lexical_cast(glonass_gnav_ephemeris_iter->second.i_satellite_PRN), 2); + line += std::string(1, ' '); + std::string year (timestring, 2, 2); + line += year; + line += std::string(1, ' '); + if(boost::lexical_cast(month) < 10) + { + line += std::string(1, ' '); + line += std::string(month, 1, 1); + } + else + { + line += month; + } + line += std::string(1, ' '); + if(boost::lexical_cast(day) < 10) + { + line += std::string(1, ' '); + line += std::string(day, 1, 1); + } + else + { + line += day; + } + line += std::string(1, ' '); + if(boost::lexical_cast(hour) < 10) + { + line += std::string(1, ' '); + line += std::string(hour, 1, 1); + } + else + { + line += hour; + } + line += std::string(1, ' '); + if(boost::lexical_cast(minutes) < 10) + { + line += std::string(1, ' '); + line += std::string(minutes, 1, 1); + } + else + { + line += minutes; + } + line += std::string(1, ' '); + if(boost::lexical_cast(seconds) < 10) + { + line += std::string(1, ' '); + line += std::string(seconds, 1, 1); + } + else + { + line += seconds; + } + + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(-glonass_gnav_ephemeris_iter->second.d_tau_c, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_gamma_n, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_t_k, 18, 2); + line += std::string(1, ' '); + } + if (version == 3) + { + line += satelliteSystem["GLONASS"]; + if (glonass_gnav_ephemeris_iter->second.i_satellite_PRN < 10) line += std::string("0"); + line += boost::lexical_cast(glonass_gnav_ephemeris_iter->second.i_satellite_PRN); + std::string year (timestring, 0, 4); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + line += std::string(1, ' '); + line += seconds; + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(-glonass_gnav_ephemeris_iter->second.d_tau_n, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(+glonass_gnav_ephemeris_iter->second.d_gamma_n, 18, 2); + line += std::string(1, ' '); + //TODO need to define this here. what is nd + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_t_k + p_utc_time.date().day()*86400, 18, 2); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + // -------- BROADCAST ORBIT - 1 + line.clear(); + // TODO Why is this happening here?. The extra space maybe is intended to help with readability + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Xn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VXn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AXn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_B_n, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + // -------- BROADCAST ORBIT - 2 + line.clear(); + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Yn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VYn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AYn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.i_satellite_freq_channel, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + + // -------- BROADCAST ORBIT - 3 + line.clear(); + if (version == 2) + { + line += std::string(3, ' '); + } + if (version == 3) + { + line += std::string(4, ' '); + } + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_Zn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_VZn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_AZn, 18, 2); + line += std::string(1, ' '); + line += Rinex_Printer::doub2for(glonass_gnav_ephemeris_iter->second.d_E_n, 18, 2); + if (version == 2) + { + line += std::string(1, ' '); + } + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } +} + + void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& galileo_eph_map) { version = 3; @@ -2203,6 +3021,930 @@ void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& gps_eph_map, const std::map& glonass_gnav_eph_map) +{ + version = 3; + stringVersion = "3.02"; + Rinex_Printer::log_rinex_nav(out, gps_eph_map); + Rinex_Printer::log_rinex_nav(out, glonass_gnav_eph_map); +} + + +void Rinex_Printer::log_rinex_nav(std::fstream& out, const std::map& galileo_eph_map, const std::map& glonass_gnav_eph_map) +{ + version = 3; + stringVersion = "3.02"; + Rinex_Printer::log_rinex_nav(out, galileo_eph_map); + Rinex_Printer::log_rinex_nav(out, glonass_gnav_eph_map); +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Glonass_Gnav_Ephemeris& eph, const double d_TOW_first_observation, const std::string glonass_bands) +{ + if(eph.d_m){} //Avoid compiler warning + std::string line; + std::map::const_iterator glonass_gnav_ephemeris_iter; + + // -------- Line 1 + line = std::string(5, ' '); + line += stringVersion; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["GLONASS"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + if (version == 2) + { + line += Rinex_Printer::leftJustify("BLANK OR G = GPS, R = GLONASS, E = GALILEO, M = MIXED", 60); + } + if (version == 3) + { + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + } + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("GLONASS OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + line.clear(); + line += Rinex_Printer::leftJustify("GROUND_CRAFT", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + if (version == 2) + { + // --------- WAVELENGHT FACTOR + // put here real data! + line.clear(); + line +=Rinex_Printer::rightJustify("1",6); + line +=Rinex_Printer::rightJustify("1",6); + line += std::string(48, ' '); + line += Rinex_Printer::leftJustify("WAVELENGTH FACT L1/2", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + if (version == 3) + { + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = 4; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + + std::string signal_ = "1C"; + std::size_t found_1C = glonass_bands.find(signal_); + signal_ = "2C"; + std::size_t found_2C = glonass_bands.find(signal_); + + if(found_1C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G1_CA"]; + } + + if(found_2C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G2_CA"]; + } + + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + if (version == 2) + { + // -------- SYS / OBS TYPES + line.clear(); + std::stringstream strm; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 6); + // per type of observation + // GLONASS L1 C/A PSEUDORANGE + line += Rinex_Printer::rightJustify(observationType["PSEUDORANGE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 PHASE + line += Rinex_Printer::rightJustify(observationType["CARRIER_PHASE_CA_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS DOPPLER L1 + line += Rinex_Printer::rightJustify(observationType["DOPPLER_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + // GLONASS L1 SIGNAL STRENGTH + line += Rinex_Printer::rightJustify(observationType["SIGNAL_STRENGTH_v2"], 5); + line += observationCode["GLONASS_G1_CA_v2"]; + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("# / TYPES OF OBSERV", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + if (version == 3) + { + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + } + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GLONASS_time(eph,d_TOW_first_observation); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + std::string year (timestring, 0, 4); + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GLO"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS /PHASE SHIFTS + // -------- GLONASS SLOT / FRQ # + line.clear(); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0), 3); + line += std::string(1, ' '); + + // TODO Add this here, we need to know all satellites in system to get this done + line += satelliteSystem["GLONASS"]; + line += Rinex_Printer::rightJustify(boost::lexical_cast(0), 2); // Slot Number + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(boost::lexical_cast(0), 2); // Frequency Number + line += std::string(1, ' '); + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS SLOT / FRQ #", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- GLONASS CODE/PHS/BIS + // TODO This needs more study, not really suer on what those values are. Setting it to zero to advance in code. + line.clear(); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_P"]; + line += std::string(1, ' '); + line += Rinex_Printer::rightJustify(asString(0.0, 3), 8); + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("GLONASS COD/PHS/BIS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- END OF HEADER + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double d_TOW_first_observation, const std::string glonass_bands) +{ + if(glonass_gnav_eph.d_m){} // avoid warning, not needed + std::string line; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += "3.02"; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GPS/GLONASS) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + line.clear(); + line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + // one line per available system + line.clear(); + line += satelliteSystem["GPS"]; + line += std::string(2, ' '); + std::stringstream strm; + numberTypesObservations = 4; + strm << numberTypesObservations; + line += Rinex_Printer::rightJustify(strm.str(), 3); + // per type of observation + // GPS L1 PSEUDORANGE + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 PHASE + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GPS_L1_CA"]; + // GPS DOPPLER L1 + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GPS_L1_CA"]; + // GPS L1 CA SIGNAL STRENGTH + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GPS_L1_CA"]; + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // Find GLONASS Signal in Mixed file + unsigned int number_of_observations_glo = 0; + std::string signal_("1C"); + std::size_t found_1C = glonass_bands.find(signal_); + if(found_1C != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + signal_ = "2C"; + std::size_t found_2C = glonass_bands.find(signal_); + if(found_2C != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + + line.clear(); + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_glo), 3); + + if(found_1C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G1_CA"]; + } + + if(found_2C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_G2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_G2_CA"]; + } + + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, d_TOW_first_observation); + std::string timestring=boost::posix_time::to_iso_string(p_gps_time); + std::string year (timestring, 0, 4); + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + double gps_t = d_TOW_first_observation; + double seconds = fmod(gps_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("GPS"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + +void Rinex_Printer::rinex_obs_header(std::fstream& out, const Galileo_Ephemeris& galileo_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const double d_TOW_first_observation, const std::string galileo_bands, const std::string glonass_bands) +{ + if(glonass_gnav_eph.d_m){} // avoid warning, not needed + std::string line; + version = 3; + + // -------- Line 1 + line = std::string(5, ' '); + line += "3.02"; + line += std::string(11, ' '); + line += Rinex_Printer::leftJustify("OBSERVATION DATA", 20); + line += satelliteSystem["Mixed"]; + line += std::string(19, ' '); + line += std::string("RINEX VERSION / TYPE"); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 2 + line.clear(); + line += Rinex_Printer::leftJustify("G = GPS R = GLONASS E = GALILEO S = GEO M = MIXED", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line 3 + line.clear(); + line += Rinex_Printer::getLocalTime(); + line += std::string("PGM / RUN BY / DATE"); + line += std::string(1, ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("MIXED (GALILEO/GLONASS) OBSERVATION DATA FILE GENERATED BY GNSS-SDR", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + std::string gnss_sdr_version(GNSS_SDR_VERSION); + line += "GNSS-SDR VERSION "; + line += Rinex_Printer::leftJustify(gnss_sdr_version, 43); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line COMMENT + line.clear(); + line += Rinex_Printer::leftJustify("See http://gnss-sdr.org", 60); + line += Rinex_Printer::leftJustify("COMMENT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER NAME + line.clear(); + line += Rinex_Printer::leftJustify("DEFAULT MARKER NAME", 60); // put a flag or a property, + line += Rinex_Printer::leftJustify("MARKER NAME", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line MARKER TYPE + //line.clear(); + //line += Rinex_Printer::leftJustify("NON_GEODETIC", 20); // put a flag or a property + //line += std::string(40, ' '); + //line += Rinex_Printer::leftJustify("MARKER TYPE", 20); + //Rinex_Printer::lengthCheck(line); + //out << line << std::endl; + + // -------- Line OBSERVER / AGENCY + line.clear(); + std::string username; + char c_username[20] = {0}; + int nGet = getlogin_r(c_username, sizeof(c_username) - 1); + if (nGet == 0) + { + username = c_username; + } + else + { + username = "UNKNOWN USER"; + } + line += leftJustify(username, 20); + line += Rinex_Printer::leftJustify("CTTC", 40); // add flag and property + line += Rinex_Printer::leftJustify("OBSERVER / AGENCY", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Line REC / TYPE VERS + line.clear(); + line += Rinex_Printer::leftJustify("GNSS-SDR", 20); // add flag and property + line += Rinex_Printer::leftJustify("Software Receiver", 20); // add flag and property + //line += Rinex_Printer::leftJustify(google::VersionString(), 20); // add flag and property + if(gnss_sdr_version.length() > 20) gnss_sdr_version.resize(9, ' '); + line += Rinex_Printer::leftJustify(gnss_sdr_version, 20); + line += Rinex_Printer::leftJustify("REC # / TYPE / VERS", 20); + lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA TYPE + line.clear(); + line += Rinex_Printer::leftJustify("Antenna number", 20); // add flag and property + line += Rinex_Printer::leftJustify("Antenna type", 20); // add flag and property + line += std::string(20, ' '); + line += Rinex_Printer::leftJustify("ANT # / TYPE", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- APPROX POSITION (optional for moving platforms) + // put here real data! + double antena_x = 0.0; + double antena_y = 0.0; + double antena_z = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_x, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_y, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_z, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("APPROX POSITION XYZ", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- ANTENNA: DELTA H/E/N + // put here real data! + double antena_h = 0.0; + double antena_e = 0.0; + double antena_n = 0.0; + line.clear(); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_h, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_e, 4), 14); + line += Rinex_Printer::rightJustify(Rinex_Printer::asString(antena_n, 4), 14); + line += std::string(18, ' '); + line += Rinex_Printer::leftJustify("ANTENNA: DELTA H/E/N", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- SYS / OBS TYPES + line.clear(); + unsigned int number_of_observations_gal = 0; + std::string signal_("1B"); + std::size_t found_1B = galileo_bands.find(signal_); + if(found_1B != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + signal_ = "5X"; + std::size_t found_5X = galileo_bands.find(signal_); + if(found_5X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + + line.clear(); + signal_ = "7X"; + std::size_t found_7X = galileo_bands.find(signal_); + if(found_7X != std::string::npos) + { + number_of_observations_gal = number_of_observations_gal + 4; + } + + + line += satelliteSystem["Galileo"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_gal), 3); + + if(found_1B != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E1_B"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E1_B"]; + } + + if(found_5X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5a_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5a_IQ"]; + } + + if(found_7X != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GALILEO_E5b_IQ"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GALILEO_E5b_IQ"]; + } + + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + line.clear(); + unsigned int number_of_observations_glo = 0; + signal_ = "1C"; + std::size_t found_1C = glonass_bands.find(signal_); + if(found_1C != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + signal_ = "2C"; + std::size_t found_2C = glonass_bands.find(signal_); + if(found_2C != std::string::npos) + { + number_of_observations_glo = number_of_observations_glo + 4; + } + + line += satelliteSystem["GLONASS"]; + line += std::string(2, ' '); + line += Rinex_Printer::rightJustify(std::to_string(number_of_observations_glo), 3); + + if(found_1C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_L1_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_L1_CA"]; + } + + if(found_2C != std::string::npos) + { + line += std::string(1, ' '); + line += observationType["PSEUDORANGE"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["CARRIER_PHASE"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["DOPPLER"]; + line += observationCode["GLONASS_L2_CA"]; + line += std::string(1, ' '); + line += observationType["SIGNAL_STRENGTH"]; + line += observationCode["GLONASS_L2_CA"]; + } + + line += std::string(60-line.size(), ' '); + line += Rinex_Printer::leftJustify("SYS / # / OBS TYPES", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- Signal Strength units + line.clear(); + line += Rinex_Printer::leftJustify("DBHZ", 20); + line += std::string(40, ' '); + line += Rinex_Printer::leftJustify("SIGNAL STRENGTH UNIT", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- TIME OF FIRST OBS + line.clear(); + boost::posix_time::ptime p_galileo_time = Rinex_Printer::compute_Galileo_time(galileo_eph, d_TOW_first_observation); + std::string timestring=boost::posix_time::to_iso_string(p_galileo_time); + std::string year (timestring, 0, 4); + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + double galileo_t = d_TOW_first_observation; + double seconds = fmod(galileo_t, 60); + line += Rinex_Printer::rightJustify(year, 6); + line += Rinex_Printer::rightJustify(month, 6); + line += Rinex_Printer::rightJustify(day, 6); + line += Rinex_Printer::rightJustify(hour, 6); + line += Rinex_Printer::rightJustify(minutes, 6); + line += Rinex_Printer::rightJustify(asString(seconds, 7), 13); + line += Rinex_Printer::rightJustify(std::string("Galileo"), 8); + line += std::string(9, ' '); + line += Rinex_Printer::leftJustify("TIME OF FIRST OBS", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + // -------- end of header + line.clear(); + line += std::string(60, ' '); + line += Rinex_Printer::leftJustify("END OF HEADER", 20); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; +} + + void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& eph, const double d_TOW_first_observation) { std::string line; @@ -3448,6 +5190,14 @@ void Rinex_Printer::rinex_obs_header(std::fstream& out, const Gps_Ephemeris& gps out << line << std::endl; } +void Rinex_Printer::update_obs_header(std::fstream& out, const Glonass_Gnav_Utc_Model& utc_model) +{ + if(utc_model.d_N_4) + { + + } +} + void Rinex_Printer::update_obs_header(std::fstream& out, const Gps_Utc_Model& utc_model) { @@ -3651,6 +5401,719 @@ void Rinex_Printer::update_obs_header(std::fstream& out, const Galileo_Utc_Model } +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Glonass_Gnav_Ephemeris& eph, const double obs_time, const std::map& observables, const std::string glonass_band) +{ + // RINEX observations timestamps are GPS timestamps. + std::string line; + + // Avoid compiler warning + if(glonass_band.size()){} + + boost::posix_time::ptime p_glonass_time = Rinex_Printer::compute_GLONASS_time(eph, obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_glonass_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double glonass_t = obs_time; + + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + + if (version == 2) + { + line.clear(); + std::string year (timestring, 2, 2); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + if (month.compare(0, 1 , "0") == 0) + { + line += std::string(1, ' '); + line += month.substr(1, 1); + } + else + { + line += month; + } + line += std::string(1, ' '); + if (day.compare(0, 1 , "0") == 0) + { + line += std::string(1, ' '); + line += day.substr(1, 1); + } + else + { + line += day; + } + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + line += std::string(1, ' '); + double second_ = fmod(glonass_t, 60); + if (second_ < 10) + { + line += std::string(1, ' '); + } + line += Rinex_Printer::asString(second_, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + //Number of satellites observed in current epoch + int numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + line += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) line += std::string(1, '0'); + line += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + } + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + line.clear(); + // GPS L1 PSEUDORANGE + line += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GPS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + // GPS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + //GPS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } + + if (version == 3) + { + std::string year (timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(glonass_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line += std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + int numSatellitesObserved = 0; + std::map::const_iterator observables_iter; + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + numSatellitesObserved++; + } + line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string lineObs; + lineObs.clear(); + lineObs += satelliteSystem["GLONASS"]; + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + //lineObs += std::string(2, ' '); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS L1 CA PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GLONASS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS L1 CA DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + //GLONASS L1 SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& gps_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double gps_obs_time, const std::map& observables) +{ + if(glonass_gnav_eph.d_m){} // avoid warning, not needed + std::string line; + + boost::posix_time::ptime p_gps_time = Rinex_Printer::compute_GPS_time(gps_eph, gps_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_gps_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double gps_t = gps_obs_time; + + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + + std::string year (timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(gps_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line +=std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + + //Get maps with observations + std::map observablesG1C; + std::map observablesR1C; + std::map observablesR2C; + std::map::const_iterator observables_iter; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesR1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesR2C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("G") == 0) && (sig_.compare("1C") == 0)) + { + observablesG1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_glo_map; + std::set available_glo_prns; + std::set::iterator it; + for(observables_iter = observablesR1C.begin(); + observables_iter != observablesR1C.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if(it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + for(observables_iter = observablesR2C.begin(); + observables_iter != observablesR2C.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if(it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + int numGloSatellitesObserved = available_glo_prns.size(); + int numGpsSatellitesObserved = observablesG1C.size(); + int numSatellitesObserved = numGloSatellitesObserved + numGpsSatellitesObserved; + line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + std::string s; + std::string lineObs; + for(observables_iter = observablesG1C.begin(); + observables_iter != observablesG1C.end(); + observables_iter++) + { + lineObs.clear(); + + s.assign(1, observables_iter->second.System); + if(s.compare("G") == 0) lineObs += satelliteSystem["GPS"]; + if(s.compare("R") == 0) lineObs += satelliteSystem["GLONASS"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + + std::pair ::iterator, std::multimap::iterator> ret; + for(it = available_glo_prns.begin(); + it != available_glo_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["GLONASS"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += boost::lexical_cast(static_cast(*it)); + ret = total_glo_map.equal_range(*it); + for (std::multimap::iterator iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GALILEO_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + +void Rinex_Printer::log_rinex_obs(std::fstream& out, const Galileo_Ephemeris& galileo_eph, const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double galileo_obs_time, const std::map& observables) +{ + if(glonass_gnav_eph.d_m){} // avoid warning, not needed + std::string line; + + boost::posix_time::ptime p_galileo_time = Rinex_Printer::compute_Galileo_time(galileo_eph, galileo_obs_time); + std::string timestring = boost::posix_time::to_iso_string(p_galileo_time); + //double utc_t = nav_msg.utc_time(nav_msg.sv_clock_correction(obs_time)); + //double gps_t = eph.sv_clock_correction(obs_time); + double galileo_t = galileo_obs_time; + + std::string month (timestring, 4, 2); + std::string day (timestring, 6, 2); + std::string hour (timestring, 9, 2); + std::string minutes (timestring, 11, 2); + + std::string year (timestring, 0, 4); + line += std::string(1, '>'); + line += std::string(1, ' '); + line += year; + line += std::string(1, ' '); + line += month; + line += std::string(1, ' '); + line += day; + line += std::string(1, ' '); + line += hour; + line += std::string(1, ' '); + line += minutes; + + line += std::string(1, ' '); + double seconds = fmod(galileo_t, 60); + // Add extra 0 if seconds are < 10 + if (seconds < 10) + { + line +=std::string(1, '0'); + } + line += Rinex_Printer::asString(seconds, 7); + line += std::string(2, ' '); + // Epoch flag 0: OK 1: power failure between previous and current epoch <1: Special event + line += std::string(1, '0'); + + //Number of satellites observed in current epoch + + //Get maps with observations + std::map observablesE1B; + std::map observablesR1C; + std::map observablesR2C; + std::map::const_iterator observables_iter; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesR1C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("R") == 0) && (sig_.compare("2C") == 0)) + { + observablesR2C.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("E") == 0) && (sig_.compare("1B") == 0)) + { + observablesE1B.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::multimap total_glo_map; + std::set available_glo_prns; + std::set::iterator it; + for(observables_iter = observablesR1C.begin(); + observables_iter != observablesR1C.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if(it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + for(observables_iter = observablesR2C.begin(); + observables_iter != observablesR2C.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + total_glo_map.insert(std::pair(prn_, observables_iter->second)); + it = available_glo_prns.find(prn_); + if(it == available_glo_prns.end()) + { + available_glo_prns.insert(prn_); + } + } + + int numGloSatellitesObserved = available_glo_prns.size(); + int numGalSatellitesObserved = observablesE1B.size(); + int numSatellitesObserved = numGalSatellitesObserved + numGloSatellitesObserved; + line += Rinex_Printer::rightJustify(boost::lexical_cast(numSatellitesObserved), 3); + + // Receiver clock offset (optional) + //line += rightJustify(asString(clockOffset, 12), 15); + + line += std::string(80 - line.size(), ' '); + Rinex_Printer::lengthCheck(line); + out << line << std::endl; + + std::string s; + std::string lineObs; + for(observables_iter = observablesE1B.begin(); + observables_iter != observablesE1B.end(); + observables_iter++) + { + lineObs.clear(); + + s.assign(1, observables_iter->second.System); + if(s.compare("E") == 0) lineObs += satelliteSystem["Galileo"]; + if(s.compare("R") == 0) lineObs += satelliteSystem["GLONASS"]; // should not happen + if (static_cast(observables_iter->second.PRN) < 10) lineObs += std::string(1, '0'); + lineObs += boost::lexical_cast(static_cast(observables_iter->second.PRN)); + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(observables_iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // PHASE + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_phase_rads/GPS_TWO_PI, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(observables_iter->second.CN0_dB_hz, 3), 14); + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } + + std::pair ::iterator, std::multimap::iterator> ret; + for(it = available_glo_prns.begin(); + it != available_glo_prns.end(); + it++) + { + lineObs.clear(); + lineObs += satelliteSystem["Galileo"]; + if (static_cast(*it) < 10) lineObs += std::string(1, '0'); + lineObs += boost::lexical_cast(static_cast(*it)); + ret = total_glo_map.equal_range(*it); + for (std::multimap::iterator iter = ret.first; iter != ret.second; ++iter) + { + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Pseudorange_m, 3), 14); + + //Loss of lock indicator (LLI) + int lli = 0; // Include in the observation!! + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + + // Signal Strength Indicator (SSI) + int ssi = Rinex_Printer::signalStrength(iter->second.CN0_dB_hz); + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS CARRIER PHASE + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_phase_rads / (GLONASS_TWO_PI), 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS DOPPLER + lineObs += Rinex_Printer::rightJustify(asString(iter->second.Carrier_Doppler_hz, 3), 14); + if (lli == 0) + { + lineObs += std::string(1, ' '); + } + else + { + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(lli), 1); + } + lineObs += Rinex_Printer::rightJustify(Rinex_Printer::asString(ssi), 1); + + // GLONASS SIGNAL STRENGTH + lineObs += Rinex_Printer::rightJustify(asString(iter->second.CN0_dB_hz, 3), 14); + } + + if (lineObs.size() < 80) lineObs += std::string(80 - lineObs.size(), ' '); + out << lineObs << std::endl; + } +} + + void Rinex_Printer::log_rinex_obs(std::fstream& out, const Gps_Ephemeris& eph, const double obs_time, const std::map& observables) { // RINEX observations timestamps are GPS timestamps. @@ -4909,6 +7372,11 @@ boost::posix_time::ptime Rinex_Printer::compute_Galileo_time(const Galileo_Ephem } +boost::posix_time::ptime Rinex_Printer::compute_GLONASS_time(const Glonass_Gnav_Ephemeris& eph, const double obs_time) +{ + boost::posix_time::ptime p_time = eph.compute_GLONASS_time(obs_time); + return p_time; +} /* enum RINEX_enumMarkerType { diff --git a/src/algorithms/PVT/libs/rinex_printer.h b/src/algorithms/PVT/libs/rinex_printer.h index d9aee967e..901fd0a60 100644 --- a/src/algorithms/PVT/libs/rinex_printer.h +++ b/src/algorithms/PVT/libs/rinex_printer.h @@ -61,8 +61,10 @@ #include "gps_navigation_message.h" #include "gps_cnav_navigation_message.h" #include "galileo_navigation_message.h" +#include "glonass_gnav_navigation_message.h" #include "GPS_L1_CA.h" #include "Galileo_E1.h" +#include "GLONASS_L1_CA.h" #include "gnss_synchro.h" class Sbas_Raw_Msg; @@ -88,6 +90,7 @@ public: std::fstream navFile ; // & gps_eph_map, const std::map & galileo_eph_map); + /*! + * \brief Writes data from the GLONASS GNAV navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream & out, const std::map & eph_map); + + /*! + * \brief Writes data from the Mixed (GPS/GLONASS GNAV) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream & out, const std::map & gps_eph_map, const std::map & glonass_gnav_eph_map); + + /*! + * \brief Writes data from the Mixed (Galileo/ GLONASS GNAV) navigation message into the RINEX file + */ + void log_rinex_nav(std::fstream & out, const std::map & galileo_eph_map, const std::map & glonass_gnav_eph_map); + /*! * \brief Writes GPS L1 observables into the RINEX file */ @@ -205,6 +258,21 @@ public: */ void log_rinex_obs(std::fstream & out, const Gps_Ephemeris & gps_eph, const Galileo_Ephemeris & galileo_eph, const double gps_obs_time, const std::map & observables); + /*! + * \brief Writes GLONASS GNAV observables into the RINEX file. Example: glonass_bands("1C"), galileo_bands("1B 5X"), galileo_bands("5X"), ... Default: "1B". + */ + void log_rinex_obs(std::fstream & out, const Glonass_Gnav_Ephemeris & eph, double obs_time, const std::map & observables, const std::string glonass_bands = "1C"); + + /*! + * \brief Writes Mixed GPS L1 C/A - GLONASS observables into the RINEX file + */ + void log_rinex_obs(std::fstream & out, const Gps_Ephemeris & gps_eph, const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const double gps_obs_time, const std::map & observables); + + /*! + * \brief Writes Mixed Galileo/GLONASS observables into the RINEX file + */ + void log_rinex_obs(std::fstream & out, const Galileo_Ephemeris & galileo_eph, const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const double gps_obs_time, const std::map & observables); + /*! * \brief Represents GPS time in the date time format. Leap years are considered, but leap seconds are not. */ @@ -223,12 +291,20 @@ public: void update_nav_header(std::fstream & out, const Galileo_Iono & galileo_iono, const Galileo_Utc_Model & utc_model, const Galileo_Almanac & galileo_almanac); + void update_nav_header(std::fstream & out, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model, const Glonass_Gnav_Almanac & glonass_gnav_almanac); + + void update_nav_header(std::fstream & out, const Gps_Iono & gps_iono, const Gps_Utc_Model & gps_utc, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model, const Glonass_Gnav_Almanac & glonass_gnav_almanac); + + void update_nav_header(std::fstream & out, const Galileo_Iono & galileo_iono, const Galileo_Utc_Model & galileo_utc_model, const Galileo_Almanac& galileo_almanac, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model, const Glonass_Gnav_Almanac & glonass_gnav_almanac); + void update_obs_header(std::fstream & out, const Gps_Utc_Model & utc_model); void update_obs_header(std::fstream & out, const Gps_CNAV_Utc_Model & utc_model); void update_obs_header(std::fstream & out, const Galileo_Utc_Model & galileo_utc_model); + void update_obs_header(std::fstream & out, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + std::map satelliteSystem; // observationType; // observationCode; // & observables) +{ + std::string m1009 = rtcm->print_MT1009(glonass_gnav_eph, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1009); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map & observables) +{ + std::string m1010 = rtcm->print_MT1010(glonass_gnav_eph, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1010); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables) +{ + std::string m1011 = rtcm->print_MT1011(glonass_gnav_ephL1, glonass_gnav_ephL2, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1011); + return true; +} + + +bool Rtcm_Printer::Print_Rtcm_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables) +{ + std::string m1012 = rtcm->print_MT1012(glonass_gnav_ephL1, glonass_gnav_ephL2, obs_time, observables, station_id); + Rtcm_Printer::Print_Message(m1012); + return true; +} + + bool Rtcm_Printer::Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph) { std::string m1019 = rtcm->print_MT1019(gps_eph); @@ -194,6 +226,14 @@ bool Rtcm_Printer::Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph) } +bool Rtcm_Printer::Print_Rtcm_MT1020(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + std::string m1020 = rtcm->print_MT1020(glonass_gnav_eph, glonass_gnav_utc_model); + Rtcm_Printer::Print_Message(m1020); + return true; +} + + bool Rtcm_Printer::Print_Rtcm_MT1045(const Galileo_Ephemeris & gal_eph) { std::string m1045 = rtcm->print_MT1045(gal_eph); @@ -205,6 +245,7 @@ bool Rtcm_Printer::Print_Rtcm_MT1045(const Galileo_Ephemeris & gal_eph) bool Rtcm_Printer::Print_Rtcm_MSM(unsigned int msm_number, const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int clock_steering_indicator, @@ -216,31 +257,31 @@ bool Rtcm_Printer::Print_Rtcm_MSM(unsigned int msm_number, const Gps_Ephemeris & std::string msm; if(msm_number == 1) { - msm = rtcm->print_MSM_1(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_1(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 2) { - msm = rtcm->print_MSM_2(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_2(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 3) { - msm = rtcm->print_MSM_3(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_3(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 4) { - msm = rtcm->print_MSM_4(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_4(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 5) { - msm = rtcm->print_MSM_5(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_5(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 6) { - msm = rtcm->print_MSM_6(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_6(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else if(msm_number == 7) { - msm = rtcm->print_MSM_7(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); + msm = rtcm->print_MSM_7(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables, station_id, clock_steering_indicator, external_clock_indicator, smooth_int, divergence_free, more_messages); } else { @@ -348,3 +389,9 @@ unsigned int Rtcm_Printer::lock_time(const Galileo_Ephemeris& eph, double obs_ti { return rtcm->lock_time(eph, obs_time, gnss_synchro); } + + +unsigned int Rtcm_Printer::lock_time(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + return rtcm->lock_time(eph, obs_time, gnss_synchro); +} diff --git a/src/algorithms/PVT/libs/rtcm_printer.h b/src/algorithms/PVT/libs/rtcm_printer.h index 0b59001e6..21fdaeddf 100644 --- a/src/algorithms/PVT/libs/rtcm_printer.h +++ b/src/algorithms/PVT/libs/rtcm_printer.h @@ -59,12 +59,66 @@ public: bool Print_Rtcm_MT1002(const Gps_Ephemeris& gps_eph, double obs_time, const std::map & observables); bool Print_Rtcm_MT1003(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables); bool Print_Rtcm_MT1004(const Gps_Ephemeris& gps_eph, const Gps_CNAV_Ephemeris& cnav_eph, double obs_time, const std::map & observables); + /*! + * \brief Prints L1-Only GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1009(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map & observables); + /*! + * \brief Prints Extended L1-Only GLONASS RTK Observables + * \details This GLONASS message type is used when only L1 data is present and bandwidth is very tight, often 1012 is used in such cases. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map & observables); + /*! + * \brief Prints L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_ephL1 GLONASS L1 GNAV Broadcast Ephemeris for satellite + * \param glonass_gnav_ephL2 GLONASS L2 GNAV Broadcast Ephemeris for satellite + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables); + /*! + * \brief Prints Extended L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is the most common observational message type, with L1/L2/SNR content. This is one of the most common messages found. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_ephL1 GLONASS L1 GNAV Broadcast Ephemeris for satellite + * \param glonass_gnav_ephL2 GLONASS L2 GNAV Broadcast Ephemeris for satellite + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return true or false upon operation success + */ + bool Print_Rtcm_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables); + bool Print_Rtcm_MT1019(const Gps_Ephemeris & gps_eph); // & observables, unsigned int clock_steering_indicator, @@ -77,6 +131,15 @@ public: unsigned int lock_time(const Gps_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro); unsigned int lock_time(const Gps_CNAV_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro); unsigned int lock_time(const Galileo_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro); + /*! + * \brief Locks time for logging given GLONASS GNAV Broadcast Ephemeris + * \note Code added as part of GSoC 2017 program + * \params glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \params obs_time Time of observation at the moment of printing + * \params observables Set of observables as defined by the platform + * \return locked time during logging process + */ + unsigned int lock_time(const Glonass_Gnav_Ephemeris& eph, double obs_time, const Gnss_Synchro & gnss_synchro); private: std::string rtcm_filename; // String with the RTCM log filename diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index 344888f67..c19dd7f4b 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -56,6 +56,7 @@ #include "rtklib_conversions.h" #include "GPS_L1_CA.h" #include "Galileo_E1.h" +#include "GLONASS_L1_CA.h" using google::LogMessage; @@ -114,6 +115,7 @@ bool rtklib_solver::get_PVT(const std::map & gnss_observables_ std::map::const_iterator galileo_ephemeris_iter; std::map::const_iterator gps_ephemeris_iter; std::map::const_iterator gps_cnav_ephemeris_iter; + std::map::const_iterator glonass_gnav_ephemeris_iter; this->set_averaging_flag(flag_averaging); @@ -124,6 +126,7 @@ bool rtklib_solver::get_PVT(const std::map & gnss_observables_ obsd_t obs_data[MAXOBS]; eph_t eph_data[MAXOBS]; + geph_t geph_data[MAXOBS]; for(gnss_observables_iter = gnss_observables_map.cbegin(); gnss_observables_iter != gnss_observables_map.cend(); @@ -133,70 +136,75 @@ bool rtklib_solver::get_PVT(const std::map & gnss_observables_ { case 'E': { - std::string sig_(gnss_observables_iter->second.Signal); - // Galileo E1 - if(sig_.compare("1B") == 0) - { - // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key - galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) - { - //convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); - //convert observation from GNSS-SDR class to RTKLIB structure - obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; - obs_data[valid_obs] = insert_obs_to_rtklib(newobs, - gnss_observables_iter->second, - galileo_ephemeris_iter->second.WN_5, - 0); - valid_obs++; - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; - } + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.end()) + { + std::string sig_(gnss_observables_iter->second.Signal); + // Galileo E1 + if(sig_.compare("1B") == 0) + { + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) + { + //convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + //convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 0); + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } - } - // Galileo E5 - if(sig_.compare("5X") == 0) - { + } + // Galileo E5 + if(sig_.compare("5X") == 0) + { - // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key - galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); - if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) - { - bool found_E1_obs=false; - for (int i = 0; i < valid_obs; i++) - { - if (eph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN + NSATGPS + NSATGLO))) - { - obs_data[i] = insert_obs_to_rtklib(obs_data[i], - gnss_observables_iter->second, - galileo_ephemeris_iter->second.WN_5, - 2);//Band 3 (L5/E5) - found_E1_obs=true; - break; - } - } - if (!found_E1_obs) - { - //insert Galileo E5 obs as new obs and also insert its ephemeris - //convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); - //convert observation from GNSS-SDR class to RTKLIB structure - obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; - obs_data[valid_obs] = insert_obs_to_rtklib(newobs, - gnss_observables_iter->second, - galileo_ephemeris_iter->second.WN_5, - 2); //Band 3 (L5/E5) - valid_obs++; - } - } - else // the ephemeris are not available for this SV - { - DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; - } - } + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) + { + bool found_E1_obs=false; + for (int i = 0; i < valid_obs; i++) + { + if (eph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN + NSATGPS + NSATGLO))) + { + obs_data[i] = insert_obs_to_rtklib(obs_data[i], + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 2);//Band 3 (L5/E5) + found_E1_obs=true; + break; + } + } + if (!found_E1_obs) + { + //insert Galileo E5 obs as new obs and also insert its ephemeris + //convert ephemeris from GNSS-SDR class to RTKLIB structure + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + //convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 2); //Band 3 (L5/E5) + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + } + } break; } case 'G': @@ -270,6 +278,76 @@ bool rtklib_solver::get_PVT(const std::map & gnss_observables_ } break; } + case 'R': //TODO This should be using rtk lib nomenclature + { + std::string sig_(gnss_observables_iter->second.Signal); + // GLONASS GNAV L1 + if(sig_.compare("1C") == 0) + { + // 1 Glo - find the ephemeris for the current GLONASS SV observation. The SV Slot Number (PRN ID) is the map key + glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != glonass_gnav_ephemeris_map.end()) + { + //convert ephemeris from GNSS-SDR class to RTKLIB structure + geph_data[valid_obs] = eph_to_rtklib(glonass_gnav_ephemeris_iter->second); + //convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + glonass_gnav_ephemeris_iter->second.d_WN, + 0);//TODO are THESE VALUES OK + valid_obs++; + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + + } + // GLONASS GNAV L2 + if(sig_.compare("2C") == 0) + { + // 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key + glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map.find(gnss_observables_iter->second.PRN); + if (glonass_gnav_ephemeris_iter != glonass_gnav_ephemeris_map.end()) + { + bool found_L1_obs=false; + for (int i = 0; i < valid_obs; i++) + { + // TODO what is this? + if (geph_data[i].sat == (static_cast(gnss_observables_iter->second.PRN+NSATGPS+NSATGLO))) + { + obs_data[i] = insert_obs_to_rtklib(obs_data[i], + gnss_observables_iter->second, + glonass_gnav_ephemeris_iter->second.d_WN, + 2);//Band 3 (L5/E5) + found_L1_obs=true; + break; + } + } + if (!found_L1_obs) + { + //insert GLONASS GNAV L2 obs as new obs and also insert its ephemeris + //convert ephemeris from GNSS-SDR class to RTKLIB structure + geph_data[valid_obs] = eph_to_rtklib(glonass_gnav_ephemeris_iter->second); + //convert observation from GNSS-SDR class to RTKLIB structure + obsd_t newobs = {{0,0}, '0', '0', {}, {}, {}, {}, {}, {}}; + obs_data[valid_obs] = insert_obs_to_rtklib(newobs, + gnss_observables_iter->second, + galileo_ephemeris_iter->second.WN_5, + 2); //Band 3 (L5/E5) + valid_obs++; + } + } + else // the ephemeris are not available for this SV + { + DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN; + } + + + } + break; + } default : DLOG(INFO) << "Hybrid observables: Unknown GNSS"; break; @@ -364,7 +442,7 @@ bool rtklib_solver::get_PVT(const std::map & gnss_observables_ LOG(WARNING) << "Exception writing PVT LS dump file " << e.what(); } } - } - } - return this->is_valid_position(); -} + } + } + return this->is_valid_position(); + } diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h index 6f441f4a6..40e0ab250 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.h +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -62,6 +62,7 @@ #include "galileo_navigation_message.h" #include "gps_navigation_message.h" #include "gps_cnav_navigation_message.h" +#include "glonass_gnav_navigation_message.h" #include "gnss_synchro.h" #include "pvt_solution.h" @@ -86,6 +87,7 @@ public: std::map galileo_ephemeris_map; //!< Map storing new Galileo_Ephemeris std::map gps_ephemeris_map; //!< Map storing new GPS_Ephemeris std::map gps_cnav_ephemeris_map; //!< Map storing new GPS_CNAV_Ephemeris + std::map glonass_gnav_ephemeris_map; //!< Map storing new GLONASS GNAV Ephmeris Galileo_Utc_Model galileo_utc_model; Galileo_Iono galileo_iono; @@ -97,6 +99,9 @@ public: Gps_CNAV_Iono gps_cnav_iono; Gps_CNAV_Utc_Model gps_cnav_utc_model; + Glonass_Gnav_Utc_Model glonass_gnav_utc_model; //!< Map storing GLONASS GNAV UTC Model + Glonass_Gnav_Almanac glonass_gnav_almanac; //!< Map storing GLONASS GNAV Almanac Model + int count_valid_position; }; diff --git a/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc index f495076a9..1066eae1f 100644 --- a/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc +++ b/src/algorithms/acquisition/adapters/glonass_l1_ca_pcps_acquisition.cc @@ -2,7 +2,7 @@ #include #include #include "glonass_l1_signal_processing.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "configuration_interface.h" @@ -64,7 +64,7 @@ GlonassL1CaPcpsAcquisition::GlonassL1CaPcpsAcquisition( stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - + if (item_type_.compare("cbyte") == 0) { cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); @@ -358,4 +358,3 @@ gr::basic_block_sptr GlonassL1CaPcpsAcquisition::get_right_block() return acquisition_cc_; } } - diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc index 29506fbeb..b61c6d4a1 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.cc @@ -42,7 +42,7 @@ #include #include "control_message_factory.h" #include "GPS_L1_CA.h" //GPS_TWO_PI -#include "Glonass_L1_CA.h" //GLONASS_TWO_PI +#include "GLONASS_L1_CA.h" //GLONASS_TWO_PI using google::LogMessage; @@ -178,12 +178,12 @@ void pcps_acquisition_cc::set_local_code(std::complex * code) int offset = d_fft_size/2; std::fill_n( d_fft_if->get_inbuf(), offset, gr_complex( 0.0, 0.0 ) ); memcpy(d_fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * offset); - } - else + } + else { memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size); } - + d_fft_if->execute(); // We need the FFT of local code volk_32fc_conjugate_32fc(d_fft_codes, d_fft_if->get_outbuf(), d_fft_size); } @@ -195,7 +195,7 @@ bool pcps_acquisition_cc::is_fdma() if( strcmp(d_gnss_synchro->Signal,"1G") == 0 ) { d_freq += DFRQ1_GLO * GLONASS_PRN.at(d_gnss_synchro->PRN); - LOG(INFO) << "Trying to acquire SV PRN " << d_gnss_synchro->PRN << " with freq " << DFRQ1_GLO * GLONASS_PRN.at(d_gnss_synchro->PRN) << " in Glonass Channel " << GLONASS_PRN.at(d_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Trying to acquire SV PRN " << d_gnss_synchro->PRN << " with freq " << d_freq << " in Glonass Channel " << GLONASS_PRN.at(d_gnss_synchro->PRN) << std::endl; return true; } else diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h index 4bd5ab857..272a0f9bc 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_cc.h @@ -56,7 +56,7 @@ #include #include #include "gnss_synchro.h" -#include "Glonass_L1_CA.h" //GLONASS_TWO_PI +#include "GLONASS_L1_CA.h" //GLONASS_TWO_PI class pcps_acquisition_cc; diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc index 7200ce946..5a15e2037 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_sc.cc @@ -41,7 +41,7 @@ #include #include "control_message_factory.h" #include "GPS_L1_CA.h" //GPS_TWO_PI -#include "Glonass_L1_CA.h" //GLONASS_TWO_PI +#include "GLONASS_L1_CA.h" //GLONASS_TWO_PI using google::LogMessage; diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.cc b/src/algorithms/libs/rtklib/rtklib_conversions.cc index c5e673b9c..c495fc210 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.cc +++ b/src/algorithms/libs/rtklib/rtklib_conversions.cc @@ -51,6 +51,10 @@ obsd_t insert_obs_to_rtklib(obsd_t & rtklib_obs, const Gnss_Synchro & gnss_synch case 'E': rtklib_obs.sat = gnss_synchro.PRN+NSATGPS+NSATGLO; break; + case 'R': + rtklib_obs.sat = gnss_synchro.PRN; + break; + default: rtklib_obs.sat = gnss_synchro.PRN; } @@ -60,6 +64,56 @@ obsd_t insert_obs_to_rtklib(obsd_t & rtklib_obs, const Gnss_Synchro & gnss_synch return rtklib_obs; } +geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + geph_t rtklib_sat = {0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0.0, 0.0, 0.0}, {0.0, 0.0, + 0.0}, {0.0, 0.0, 0.0}, 0.0, 0.0, 0.0}; + gtime_t t_utc; + struct tm utcinfo; + + rtklib_sat.sat = glonass_gnav_eph.i_satellite_slot_number; /* satellite number */ + rtklib_sat.iode = glonass_gnav_eph.d_iode; /* IODE (0-6 bit of tb field) */ + rtklib_sat.frq = glonass_gnav_eph.i_satellite_freq_channel; /* satellite frequency number */ + rtklib_sat.svh = glonass_gnav_eph.d_l3rd_n; /* satellite health*/ + rtklib_sat.sva = glonass_gnav_eph.d_F_T; /* satellite accuracy*/ + rtklib_sat.age = glonass_gnav_eph.d_E_n; /* satellite age*/ + rtklib_sat.pos[0] = glonass_gnav_eph.d_Xn*1000; /* satellite position (ecef) (m) */ + rtklib_sat.pos[1] = glonass_gnav_eph.d_Yn*1000; /* satellite position (ecef) (m) */ + rtklib_sat.pos[2] = glonass_gnav_eph.d_Zn*1000; /* satellite position (ecef) (m) */ + rtklib_sat.vel[0] = glonass_gnav_eph.d_VXn*1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.vel[1] = glonass_gnav_eph.d_VYn*1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.vel[2] = glonass_gnav_eph.d_VZn*1000; /* satellite velocity (ecef) (m/s) */ + rtklib_sat.acc[0] = glonass_gnav_eph.d_AXn*1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.acc[1] = glonass_gnav_eph.d_AYn*1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.acc[2] = glonass_gnav_eph.d_AZn*1000; /* satellite acceleration (ecef) (m/s^2) */ + rtklib_sat.taun = glonass_gnav_eph.d_tau_n; /* SV clock bias (s) */ + rtklib_sat.gamn = glonass_gnav_eph.d_gamma_n; /* SV relative freq bias */ + rtklib_sat.age = glonass_gnav_eph.d_Delta_tau_n; /* delay between L1 and L2 (s) */ + + utcinfo.tm_mon = 0; + utcinfo.tm_mday = glonass_gnav_eph.d_N_T; + utcinfo.tm_year = glonass_gnav_eph.d_yr - 1900; + utcinfo.tm_hour = 6; // Diff between utc and (utc(su) + 3.00h) + utcinfo.tm_min = 0; + utcinfo.tm_sec = glonass_gnav_eph.d_t_b; + t_utc.time = mktime(&utcinfo); + t_utc.sec = glonass_gnav_eph.d_tau_c; + rtklib_sat.toe = utc2gpst(t_utc); /* epoch of epherides (gpst) */ + + utcinfo.tm_mon = 0; + utcinfo.tm_mday = glonass_gnav_eph.d_N_T; + utcinfo.tm_year = glonass_gnav_eph.d_yr - 1900; + utcinfo.tm_hour = 6; + utcinfo.tm_min = 0; + utcinfo.tm_sec = glonass_gnav_eph.d_t_k; + t_utc.time = mktime(&utcinfo); + t_utc.sec = glonass_gnav_eph.d_tau_c; + rtklib_sat.tof = utc2gpst(t_utc); /* message frame time (gpst) */ + + + return rtklib_sat; +} + eph_t eph_to_rtklib(const Galileo_Ephemeris & gal_eph) { eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.h b/src/algorithms/libs/rtklib/rtklib_conversions.h index 18336754f..e620adaaa 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.h +++ b/src/algorithms/libs/rtklib/rtklib_conversions.h @@ -36,10 +36,17 @@ #include "galileo_ephemeris.h" #include "gps_ephemeris.h" #include "gps_cnav_ephemeris.h" +#include "glonass_gnav_ephemeris.h" eph_t eph_to_rtklib(const Galileo_Ephemeris & gal_eph); eph_t eph_to_rtklib(const Gps_Ephemeris & gps_eph); eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris & gps_cnav_eph); +/*! + * \brief Transforms a Glonass_Gnav_Ephemeris to its RTKLIB counterpart + * \param glonass_gnav_eph GLONASS GNAV Ephemeris structure + * \return Ephemeris structure for RTKLIB parsing + */ +geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); obsd_t insert_obs_to_rtklib(obsd_t & rtklib_obs, const Gnss_Synchro & gnss_synchro, int week, int band); diff --git a/src/algorithms/signal_generator/adapters/signal_generator.cc b/src/algorithms/signal_generator/adapters/signal_generator.cc index a2ef90cdf..57e3c0aa0 100644 --- a/src/algorithms/signal_generator/adapters/signal_generator.cc +++ b/src/algorithms/signal_generator/adapters/signal_generator.cc @@ -36,7 +36,7 @@ #include "Galileo_E1.h" #include "GPS_L1_CA.h" #include "Galileo_E5a.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" using google::LogMessage; diff --git a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc index a99c4751d..6d84c3084 100644 --- a/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc +++ b/src/algorithms/signal_generator/gnuradio_blocks/signal_generator_c.cc @@ -40,7 +40,7 @@ #include "Galileo_E1.h" #include "Galileo_E5a.h" #include "GPS_L1_CA.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" /* * Create a new instance of signal_generator_c and return @@ -115,7 +115,7 @@ void signal_generator_c::init() / (GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS))); num_of_codes_per_vector_.push_back(galileo_signal ? 4 * static_cast(Galileo_E1_C_SECONDARY_CODE_LENGTH) : 1); - data_bit_duration_ms_.push_back(1e3 / GLONASS_CA_TELEMETRY_RATE_BITS_SECOND); + data_bit_duration_ms_.push_back(1e3 / GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND); } else if (system_[sat] == "E") { diff --git a/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt b/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt index 974adfb53..41e9bffd1 100644 --- a/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/adapters/CMakeLists.txt @@ -16,12 +16,13 @@ # along with GNSS-SDR. If not, see . # -set(TELEMETRY_DECODER_ADAPTER_SOURCES - gps_l1_ca_telemetry_decoder.cc - gps_l2c_telemetry_decoder.cc +set(TELEMETRY_DECODER_ADAPTER_SOURCES + gps_l1_ca_telemetry_decoder.cc + gps_l2c_telemetry_decoder.cc galileo_e1b_telemetry_decoder.cc sbas_l1_telemetry_decoder.cc galileo_e5a_telemetry_decoder.cc + glonass_l1_ca_telemetry_decoder.cc ) include_directories( diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc new file mode 100644 index 000000000..924efd2da --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.cc @@ -0,0 +1,102 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder.cc + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_telemetry_decoder.h" +#include +#include +#include "concurrent_queue.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_utc_model.h" +#include "configuration_interface.h" + +using google::LogMessage; + +GlonassL1CaTelemetryDecoder::GlonassL1CaTelemetryDecoder(ConfigurationInterface* configuration, + std::string role, + unsigned int in_streams, + unsigned int out_streams) : + role_(role), + in_streams_(in_streams), + out_streams_(out_streams) +{ + std::string default_dump_filename = "./navigation.dat"; + DLOG(INFO) << "role " << role; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + // make telemetry decoder object + telemetry_decoder_ = glonass_l1_ca_make_telemetry_decoder_cc(satellite_, dump_); + DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; + + DLOG(INFO) << "global navigation message queue assigned to telemetry_decoder ("<< telemetry_decoder_->unique_id() << ")"; + channel_ = 0; +} + + +GlonassL1CaTelemetryDecoder::~GlonassL1CaTelemetryDecoder() +{} + + +void GlonassL1CaTelemetryDecoder::set_satellite(Gnss_Satellite satellite) +{ + satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + telemetry_decoder_->set_satellite(satellite_); + DLOG(INFO) << "TELEMETRY DECODER: satellite set to " << satellite_; +} + + +void GlonassL1CaTelemetryDecoder::connect(gr::top_block_sptr top_block) +{ + if(top_block) { /* top_block is not null */}; + // Nothing to connect internally + DLOG(INFO) << "nothing to connect internally"; +} + + +void GlonassL1CaTelemetryDecoder::disconnect(gr::top_block_sptr top_block) +{ + if(top_block) { /* top_block is not null */}; + // Nothing to disconnect +} + + +gr::basic_block_sptr GlonassL1CaTelemetryDecoder::get_left_block() +{ + return telemetry_decoder_; +} + + +gr::basic_block_sptr GlonassL1CaTelemetryDecoder::get_right_block() +{ + return telemetry_decoder_; +} diff --git a/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h new file mode 100644 index 000000000..e79f586c9 --- /dev/null +++ b/src/algorithms/telemetry_decoder/adapters/glonass_l1_ca_telemetry_decoder.h @@ -0,0 +1,92 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder.h + * \brief Interface of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_H_ +#define GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_H_ + +#include +#include "telemetry_decoder_interface.h" +#include "glonass_l1_ca_telemetry_decoder_cc.h" + + +class ConfigurationInterface; + +/*! + * \brief This class implements a NAV data decoder for GLONASS L1 C/A + */ +class GlonassL1CaTelemetryDecoder : public TelemetryDecoderInterface +{ +public: + GlonassL1CaTelemetryDecoder(ConfigurationInterface* configuration, + std::string role, + unsigned int in_streams, + unsigned int out_streams); + + virtual ~GlonassL1CaTelemetryDecoder(); + std::string role() + { + return role_; + } + + //! Returns "GLONASS_L1_CA_Telemetry_Decoder" + std::string implementation() + { + return "GLONASS_L1_CA_Telemetry_Decoder"; + } + void connect(gr::top_block_sptr top_block); + void disconnect(gr::top_block_sptr top_block); + gr::basic_block_sptr get_left_block(); + gr::basic_block_sptr get_right_block(); + void set_satellite(Gnss_Satellite satellite); + void set_channel(int channel){telemetry_decoder_->set_channel(channel);} + void reset() + { + return; + } + size_t item_size() + { + return 0; + } + +private: + glonass_l1_ca_telemetry_decoder_cc_sptr telemetry_decoder_; + Gnss_Satellite satellite_; + int channel_; + bool dump_; + std::string dump_filename_; + std::string role_; + unsigned int in_streams_; + unsigned int out_streams_; +}; + +#endif diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt index 7de1a365b..043440927 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt @@ -16,14 +16,15 @@ # along with GNSS-SDR. If not, see . # -set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES +set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES gps_l1_ca_telemetry_decoder_cc.cc gps_l2c_telemetry_decoder_cc.cc galileo_e1b_telemetry_decoder_cc.cc sbas_l1_telemetry_decoder_cc.cc galileo_e5a_telemetry_decoder_cc.cc + glonass_l1_ca_telemetry_decoder_cc.cc ) - + include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src/core/system_parameters @@ -40,4 +41,4 @@ file(GLOB TELEMETRY_DECODER_GR_BLOCKS_HEADERS "*.h") list(SORT TELEMETRY_DECODER_GR_BLOCKS_HEADERS) add_library(telemetry_decoder_gr_blocks ${TELEMETRY_DECODER_GR_BLOCKS_SOURCES} ${TELEMETRY_DECODER_GR_BLOCKS_HEADERS}) source_group(Headers FILES ${TELEMETRY_DECODER_GR_BLOCKS_HEADERS}) -target_link_libraries(telemetry_decoder_gr_blocks telemetry_decoder_libswiftcnav telemetry_decoder_lib gnss_system_parameters ${GNURADIO_RUNTIME_LIBRARIES}) \ No newline at end of file +target_link_libraries(telemetry_decoder_gr_blocks telemetry_decoder_libswiftcnav telemetry_decoder_lib gnss_system_parameters ${GNURADIO_RUNTIME_LIBRARIES}) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc new file mode 100644 index 000000000..f80748f80 --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.cc @@ -0,0 +1,431 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder_cc.cc + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "glonass_l1_ca_telemetry_decoder_cc.h" +#include +#include +#include +#include +#include +#include +#include "control_message_factory.h" +#include "gnss_synchro.h" +#include "convolutional.h" + + +#define CRC_ERROR_LIMIT 6 + +using google::LogMessage; + + +glonass_l1_ca_telemetry_decoder_cc_sptr +glonass_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump) +{ + return glonass_l1_ca_telemetry_decoder_cc_sptr(new glonass_l1_ca_telemetry_decoder_cc(satellite, dump)); +} + + +glonass_l1_ca_telemetry_decoder_cc::glonass_l1_ca_telemetry_decoder_cc( + Gnss_Satellite satellite, + bool dump) : + gr::block("glonass_l1_ca_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry Bit transition synchronization port out + this->message_port_register_out(pmt::mp("preamble_timestamp_s")); + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + LOG(INFO) << "Initializing GLONASS L1 CA TELEMETRY DECODING"; + // Define the number of sampes per symbol. Notice that GLONASS has 2 rates, + //one for the navigation data and the other for the preamble information + d_samples_per_symbol = ( GLONASS_L1_CA_CODE_RATE_HZ / GLONASS_L1_CA_CODE_LENGTH_CHIPS ) / GLONASS_L1_CA_SYMBOL_RATE_BPS; + + // Set the preamble information + unsigned short int preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS] = GLONASS_GNAV_PREAMBLE; + // Since preamble rate is different than navigation data rate we use a constant + d_symbols_per_preamble = GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS; + + memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GLONASS_GNAV_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int)); + + // preamble bits to sampled symbols + d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * d_symbols_per_preamble); + int n = 0; + for (int i = 0; i < GLONASS_GNAV_PREAMBLE_LENGTH_BITS; i++) + { + for (unsigned int j = 0; j < GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_PREAMBLE_BIT; j++) + { + if (d_preambles_bits[i] == 1) + { + d_preambles_symbols[n] = 1; + } + else + { + d_preambles_symbols[n] = -1; + } + n++; + } + } + d_sample_counter = 0; + d_stat = 0; + d_preamble_index = 0; + + d_flag_frame_sync = false; + + d_flag_parity = false; + d_TOW_at_current_symbol = 0; + delta_t = 0; + d_CRC_error_counter = 0; + d_flag_preamble = false; + d_channel = 0; + flag_TOW_set = false; +} + + +glonass_l1_ca_telemetry_decoder_cc::~glonass_l1_ca_telemetry_decoder_cc() +{ + delete d_preambles_symbols; + if(d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch(const std::exception & ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void glonass_l1_ca_telemetry_decoder_cc::decode_string(double *frame_symbols,int frame_length) +{ + double chip_acc = 0.0; + int chip_acc_counter = 0; + + // 1. Transform from symbols to bits + std::string bi_binary_code; + std::string relative_code; + // Group samples into bi-binary code + for(int i = 0; i < (frame_length); i++) + { + chip_acc += frame_symbols[i]; + chip_acc_counter += 1; + + if(chip_acc_counter == (GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT)) + { + if (chip_acc > 0) + { + bi_binary_code.push_back('1'); + chip_acc_counter = 0; + chip_acc = 0; + } + else + { + bi_binary_code.push_back('0'); + chip_acc_counter = 0; + chip_acc = 0; + } + } + } + // Convert from bi-binary code to relative code + for(int i = 0; i < (GLONASS_GNAV_STRING_BITS); i++) + { + if(bi_binary_code[2*i] == '1' && bi_binary_code[2*i + 1] == '0') + { + relative_code.push_back('1'); + } + else + { + relative_code.push_back('0'); + } + } + + // 2. Call the GLONASS GNAV string decoder + d_nav.string_decoder(relative_code); + + // 3. Check operation executed correctly + if(d_nav.flag_CRC_test == true) + { + LOG(INFO) << "GLONASS GNAV CRC correct on channel " << d_channel << " from satellite "<< d_satellite; + } + else + { + LOG(INFO) << "GLONASS GNAV CRC error on channel " << d_channel << " from satellite " << d_satellite; + } + + // 4. Push the new navigation data to the queues + if (d_nav.have_new_ephemeris() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + + } + if (d_nav.have_new_utc_model() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_nav.have_new_almanac() == true) + { + unsigned int slot_nbr = d_nav.get_ephemeris().i_satellite_slot_number; + std::shared_ptr tmp_obj= std::make_shared(d_nav.get_almanac(slot_nbr)); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } +} + + +int glonass_l1_ca_telemetry_decoder_cc::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) +{ + int corr_value = 0; + int preamble_diff = 0; + + Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; + const Gnss_Synchro **in = (const Gnss_Synchro **) &input_items[0]; //Get the input samples pointer + + Gnss_Synchro current_symbol; //structure to save the synchronization information and send the output object to the next block + //1. Copy the current tracking output + current_symbol = in[0][0]; + d_symbol_history.push_back(current_symbol); //add new symbol to the symbol queue + d_sample_counter++; //count for the processed samples + consume_each(1); + + d_flag_preamble = false; + unsigned int required_symbols=GLONASS_GNAV_STRING_SYMBOLS; + + if (d_symbol_history.size()>required_symbols) + { + //******* preamble correlation ******** + for (int i = 0; i < d_symbols_per_preamble; i++) + { + if (d_symbol_history.at(i).Prompt_I < 0) // symbols clipping + { + corr_value -= d_preambles_symbols[i]; + } + else + { + corr_value += d_preambles_symbols[i]; + } + } + } + + //******* frame sync ****************** + if (d_stat == 0) //no preamble information + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + // Record the preamble sample stamp + d_preamble_index = d_sample_counter; + LOG(INFO) << "Preamble detection for GLONASS L1 C/A SAT " << this->d_satellite; + // Enter into frame pre-detection status + d_stat = 1; + } + } + else if (d_stat == 1) // posible preamble lock + { + if (abs(corr_value) >= d_symbols_per_preamble) + { + //check preamble separation + preamble_diff = d_sample_counter - d_preamble_index; + if (abs(preamble_diff - GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) == 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 + d_stat = 2; + } + else + { + if (preamble_diff > GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS) + { + d_stat = 0; // start again + } + DLOG(INFO) << "Failed string decoder for GLONASS L1 C/A SAT " << this->d_satellite; + } + } + } + else if (d_stat == 2) + { + // FIXME: The preamble index marks the first symbol of the string count. Here I just wait for another full string to be received before processing + if (d_sample_counter == d_preamble_index + GLONASS_GNAV_STRING_SYMBOLS) + { + // NEW GLONASS string received + // 0. fetch the symbols into an array + int string_length = GLONASS_GNAV_STRING_SYMBOLS - d_symbols_per_preamble; + double string_symbols[GLONASS_GNAV_DATA_SYMBOLS] = {0}; + + //******* SYMBOL TO BIT ******* + for (int i = 0; i < string_length; i++) + { + if (corr_value > 0) + { + string_symbols[i] = d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + + } + else + { + string_symbols[i] = -d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! + } + } + + //call the decoder + decode_string(string_symbols, string_length); + if (d_nav.flag_CRC_test == true) + { + d_CRC_error_counter = 0; + d_flag_preamble = true; //valid preamble indicator (initialized to false every work()) + d_preamble_index = d_sample_counter; //record the preamble sample stamp (t_P) + if (!d_flag_frame_sync) + { + d_flag_frame_sync = true; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " + << d_symbol_history.at(0).Tracking_sample_counter << " [samples]"; + } + } + else + { + d_CRC_error_counter++; + d_preamble_index = d_sample_counter; //record the preamble sample stamp + if (d_CRC_error_counter > CRC_ERROR_LIMIT) + { + LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; + d_flag_frame_sync = false; + d_stat = 0; + } + } + } + } + + // UPDATE GNSS SYNCHRO DATA + //2. Add the telemetry decoder information + if (this->d_flag_preamble == true and d_nav.flag_TOW_set == true) + //update TOW at the preamble instant + { + d_TOW_at_current_symbol = floor((d_nav.d_TOW + 2*GLONASS_L1_CA_CODE_PERIOD + GLONASS_GNAV_PREAMBLE_DURATION_S)*1000.0)/1000.0; + + } + else //if there is not a new preamble, we define the TOW of the current symbol + { + d_TOW_at_current_symbol = d_TOW_at_current_symbol + GLONASS_L1_CA_CODE_PERIOD; + } + + //if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true) + + // if(d_nav.flag_GGTO_1 == true and d_nav.flag_GGTO_2 == true and d_nav.flag_GGTO_3 == true and d_nav.flag_GGTO_4 == true) //all GGTO parameters arrived + // { + // delta_t = d_nav.A_0G_10 + d_nav.A_1G_10 * (d_TOW_at_current_symbol - d_nav.t_0G_10 + 604800.0 * (fmod((d_nav.WN_0 - d_nav.WN_0G_10), 64))); + // } + + if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true) + { + current_symbol.Flag_valid_word = true; + } + else + { + current_symbol.Flag_valid_word = false; + } + + current_symbol.TOW_at_current_symbol_s = floor(d_TOW_at_current_symbol*1000.0)/1000.0; + current_symbol.TOW_at_current_symbol_s -=delta_t; //Galileo to GPS TOW + + if(d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + unsigned long int tmp_ulong_int; + tmp_double = d_TOW_at_current_symbol; + d_dump_file.write((char*)&tmp_double, sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write((char*)&tmp_ulong_int, sizeof(unsigned long int)); + tmp_double = 0; + d_dump_file.write((char*)&tmp_double, sizeof(double)); + } + catch (const std::ifstream::failure & e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } + + // remove used symbols from history + if (d_symbol_history.size()>required_symbols) + { + d_symbol_history.pop_front(); + } + //3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; + + return 1; +} + + +void glonass_l1_ca_telemetry_decoder_cc::set_satellite(Gnss_Satellite satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite "<< d_satellite; + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} + + +void glonass_l1_ca_telemetry_decoder_cc::set_channel(int channel) +{ + d_channel = channel; + LOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry"; + d_dump_filename.append(boost::lexical_cast(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit ); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure& e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h new file mode 100644 index 000000000..5e4ff6df7 --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/glonass_l1_ca_telemetry_decoder_cc.h @@ -0,0 +1,118 @@ +/*! + * \file glonass_l1_ca_telemetry_decoder_cc.h + * \brief Implementation of an adapter of a GLONASS L1 C/A NAV data decoder block + * to a TelemetryDecoderInterface + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_CC_H +#define GNSS_SDR_GLONASS_L1_CA_TELEMETRY_DECODER_CC_H + +#include +#include +#include +#include "GLONASS_L1_CA.h" +#include "concurrent_queue.h" +#include "gnss_satellite.h" +#include "glonass_gnav_navigation_message.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_utc_model.h" +#include "gnss_synchro.h" + + + +class glonass_l1_ca_telemetry_decoder_cc; + +typedef boost::shared_ptr glonass_l1_ca_telemetry_decoder_cc_sptr; + +glonass_l1_ca_telemetry_decoder_cc_sptr glonass_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + +/*! + * \brief This class implements a block that decodes the GNAV data defined in GLONASS ICD v5.1 + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + * + */ +class glonass_l1_ca_telemetry_decoder_cc : public gr::block +{ +public: + ~glonass_l1_ca_telemetry_decoder_cc(); //!< Class destructor + void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN + void set_channel(int channel); //!< Set receiver's channel + + /*! + * \brief This is where all signal processing takes place + */ + int general_work (int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + +private: + friend glonass_l1_ca_telemetry_decoder_cc_sptr + glonass_l1_ca_make_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + glonass_l1_ca_telemetry_decoder_cc(Gnss_Satellite satellite, bool dump); + + void decode_string(double *symbols, int frame_length); + + //!< Preamble decoding + unsigned short int d_preambles_bits[GLONASS_GNAV_PREAMBLE_LENGTH_BITS]; + int *d_preambles_symbols; + unsigned int d_samples_per_symbol; + unsigned int d_samples_per_preamble_symbol; + int d_symbols_per_preamble; + + //!< Storage for incoming data + std::deque d_symbol_history; + + //!< Variables for internal functionality + long unsigned int d_sample_counter; //!< Sample counter as an index (1,2,3,..etc) indicating number of samples processed + long unsigned int d_preamble_index; //!< Index of sample number where preamble was found + unsigned int d_stat; //!< Status of decoder + bool d_flag_frame_sync; //!< Indicate when a frame sync is achieved + bool d_flag_parity; //!< Flag indicating when parity check was achieved (crc check) + bool d_flag_preamble; //!< Flag indicating when preamble was found + int d_CRC_error_counter; //!< Number of failed CRC operations + bool flag_TOW_set; //!< Indicates when time of week is set + double delta_t; //!< GPS-GLONASS time offset + + //!< Navigation Message variable + Glonass_Gnav_Navigation_Message d_nav; + + //!< Values to populate gnss synchronization structure + double d_TOW_at_current_symbol; + bool Flag_valid_word; + + //!< Satellite Information and logging capacity + Gnss_Satellite d_satellite; + int d_channel; + bool d_dump; + std::string d_dump_filename; + std::ofstream d_dump_file; +}; + +#endif diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc index c303be5d9..7d52ff931 100644 --- a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_c_aid_tracking.cc @@ -1,6 +1,6 @@ #include "glonass_l1_ca_dll_pll_c_aid_tracking.h" #include -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "configuration_interface.h" diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc index f9c0e6c9f..7035a1411 100644 --- a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.cc @@ -38,7 +38,7 @@ #include "glonass_l1_ca_dll_pll_tracking.h" #include -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "configuration_interface.h" diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc index fb48e295b..367bcb371 100644 --- a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.cc @@ -12,7 +12,7 @@ #include "glonass_l1_signal_processing.h" #include "tracking_discriminators.h" #include "lock_detectors.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "control_message_factory.h" @@ -196,7 +196,7 @@ void glonass_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); // Doppler effect // Fd=(C/(C+Vr))*F - d_glonass_freq_ch = GLONASS_L1_FREQ_HZ + (GLONASS_L1_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (DFRQ1_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; // new chip and prn sequence periods based on acq Doppler double T_chip_mod_seconds; @@ -224,7 +224,8 @@ void glonass_l1_ca_dll_pll_c_aid_tracking_cc::start_tracking() d_acq_code_phase_samples = corrected_acq_phase_samples; - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_if_freq + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz; d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); @@ -575,7 +576,8 @@ int glonass_l1_ca_dll_pll_c_aid_tracking_cc::general_work (int noutput_items __a d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_cycles), sizeof(double)); // carrier and code frequency - d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); + double if_freq_carrier = d_carrier_doppler_hz + d_if_freq + (DFRQ1_GLO * static_cast(GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN))); + d_dump_file.write(reinterpret_cast(&if_freq_carrier), sizeof(double)); d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); //PLL commands diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h index 280d590b1..262707535 100644 --- a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_cc.h @@ -85,7 +85,7 @@ private: long d_if_freq; long d_fs_in; - long d_glonass_freq_ch; + double d_glonass_freq_ch; double d_early_late_spc_chips; int d_n_correlator_taps; diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc index 621df090d..37b9ebaa7 100644 --- a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_c_aid_tracking_sc.cc @@ -13,7 +13,7 @@ #include "glonass_l1_signal_processing.h" #include "tracking_discriminators.h" #include "lock_detectors.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "control_message_factory.h" @@ -197,7 +197,7 @@ void glonass_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); // Doppler effect // Fd=(C/(C+Vr))*F - d_glonass_freq_ch = GLONASS_L1_FREQ_HZ + (GLONASS_L1_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; // new chip and prn sequence periods based on acq Doppler double T_chip_mod_seconds; @@ -225,7 +225,8 @@ void glonass_l1_ca_dll_pll_c_aid_tracking_sc::start_tracking() d_acq_code_phase_samples = corrected_acq_phase_samples; - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_if_freq + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz; d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); diff --git a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc index 82bf4ee47..4bdb0abf3 100644 --- a/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc +++ b/src/algorithms/tracking/gnuradio_blocks/glonass_l1_ca_dll_pll_tracking_cc.cc @@ -10,7 +10,7 @@ #include "glonass_l1_signal_processing.h" #include "tracking_discriminators.h" #include "lock_detectors.h" -#include "Glonass_L1_CA.h" +#include "GLONASS_L1_CA.h" #include "control_message_factory.h" @@ -161,7 +161,7 @@ void Glonass_L1_Ca_Dll_Pll_Tracking_cc::start_tracking() acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); // Doppler effect // Fd=(C/(C+Vr))*F - d_glonass_freq_ch = GLONASS_L1_FREQ_HZ + (GLONASS_L1_FREQ_HZ * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + d_glonass_freq_ch = GLONASS_L1_CA_FREQ_HZ + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); double radial_velocity = (d_glonass_freq_ch + d_acq_carrier_doppler_hz) / d_glonass_freq_ch; // new chip and prn sequence periods based on acq Doppler double T_chip_mod_seconds; @@ -189,7 +189,8 @@ void Glonass_L1_Ca_Dll_Pll_Tracking_cc::start_tracking() d_acq_code_phase_samples = corrected_acq_phase_samples; - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_if_freq + (DFRQ1_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN)); + // d_carrier_doppler_hz = d_acq_carrier_doppler_hz; d_carrier_phase_step_rad = GLONASS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); // DLL/PLL filter initialization diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 7cba2a649..927aaf0fe 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -92,6 +92,7 @@ #include "gps_l2c_telemetry_decoder.h" #include "galileo_e1b_telemetry_decoder.h" #include "galileo_e5a_telemetry_decoder.h" +#include "glonass_l1_ca_telemetry_decoder.h" #include "sbas_l1_telemetry_decoder.h" #include "hybrid_observables.h" #include "rtklib_pvt.h" @@ -528,7 +529,7 @@ std::unique_ptr GNSSBlockFactory::GetChannel_1G( stream << channel; std::string id = stream.str(); LOG(INFO) << "Instantiating Channel " << channel << " with Acquisition Implementation: " - << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder implementation: " << tlm; + << acq << ", Tracking Implementation: " << trk << ", Telemetry Decoder Implementation: " << tlm; std::string aux = configuration->property("Acquisition_1G" + boost::lexical_cast(channel) + ".implementation", std::string("W")); std::string appendix1; @@ -1203,6 +1204,12 @@ std::unique_ptr GNSSBlockFactory::GetBlock( out_streams)); block = std::move(block_); } + else if (implementation.compare("GLONASS_L1_CA_Telemetry_Decoder") == 0) + { + std::unique_ptr block_(new GlonassL1CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } // OBSERVABLES ----------------------------------------------------------------- else if ((implementation.compare("Hybrid_Observables") == 0) || (implementation.compare("GPS_L1_CA_Observables") == 0) || (implementation.compare("GPS_L2C_Observables") == 0) || @@ -1483,6 +1490,12 @@ std::unique_ptr GNSSBlockFactory::GetTlmBlock( out_streams)); block = std::move(block_); } + else if (implementation.compare("GLONASS_L1_CA_Telemetry_Decoder") == 0) + { + std::unique_ptr block_(new GlonassL1CaTelemetryDecoder(configuration.get(), role, in_streams, + out_streams)); + block = std::move(block_); + } else { // Log fatal. This causes execution to stop. diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4529a1fba..c83bf1e92 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -597,8 +597,8 @@ void GNSSFlowgraph::set_signals_list() 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}; - std::set available_glonass_prn = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + // Removing satellites sharing same frequency number(1 and 5, 2 and 6, 3 and 7, 4 and 6, 11 and 15, 12 and 16, 14 and 18, 17 and 21 + std::set available_glonass_prn = { 1, 2, 3, 4, 9, 10, 11, 12, 18, 19, 20, 21 }; std::string sv_list = configuration_->property("Galileo.prns", std::string("") ); @@ -735,19 +735,19 @@ void GNSSFlowgraph::set_signals_list() } } - if (configuration_->property("Channels_1G.count", 0) > 0 ) - { - /* - * Loop to create the list of GLONASS L1 C/A signals - */ - for (available_gnss_prn_iter = available_glonass_prn.begin(); - available_gnss_prn_iter != available_glonass_prn.end(); - available_gnss_prn_iter++) - { - available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("Glonass"), - *available_gnss_prn_iter), std::string("1G"))); - } - } + if (configuration_->property("Channels_1G.count", 0) > 0 ) + { + /* + * Loop to create the list of GLONASS L1 C/A signals + */ + for (available_gnss_prn_iter = available_glonass_prn.begin(); + available_gnss_prn_iter != available_glonass_prn.end(); + available_gnss_prn_iter++) + { + available_GNSS_signals_.push_back(Gnss_Signal(Gnss_Satellite(std::string("Glonass"), + *available_gnss_prn_iter), std::string("1G"))); + } + } /* * Ordering the list of signals from configuration file */ diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index df419aebd..9143a038b 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -39,6 +39,10 @@ set(SYSTEM_PARAMETERS_SOURCES gps_cnav_iono.cc gps_cnav_utc_model.cc rtcm.cc + glonass_gnav_ephemeris.cc + glonass_gnav_almanac.cc + glonass_gnav_utc_model.cc + glonass_gnav_navigation_message.cc ) @@ -59,4 +63,3 @@ add_library(gnss_system_parameters ${SYSTEM_PARAMETERS_SOURCES} ${SYSTEM_PARAMET source_group(Headers FILES ${SYSTEM_PARAMETERS_HEADERS}) add_dependencies(gnss_system_parameters rtklib_lib glog-${glog_RELEASE}) target_link_libraries(gnss_system_parameters rtklib_lib ${Boost_LIBRARIES}) - diff --git a/src/core/system_parameters/GLONASS_L1_CA.h b/src/core/system_parameters/GLONASS_L1_CA.h new file mode 100644 index 000000000..ca71ccd08 --- /dev/null +++ b/src/core/system_parameters/GLONASS_L1_CA.h @@ -0,0 +1,244 @@ +/*! + * \file GLONASS_L1_CA.h + * \brief Defines system parameters for GLONASS L1 C/A signal and NAV data + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_L1_CA_H_ +#define GNSS_SDR_GLONASS_L1_CA_H_ + +#include +#include // std::pair +#include "MATH_CONSTANTS.h" +#include "gnss_frequencies.h" + +// Physical constants +const double GLONASS_C_m_s = SPEED_OF_LIGHT; //!< The speed of light, [m/s] +const double GLONASS_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] +const double GLONASS_PI = 3.1415926535898; //!< Pi as defined in IS-GPS-200E +const double GLONASS_TWO_PI = 6.283185307179586; //!< 2Pi as defined in IS-GPS-200E +const double GLONASS_OMEGA_EARTH_DOT = 7.292115e-5; //!< Earth rotation rate, [rad/s] +const double GLONASS_GM = 398600.4418e9; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] +const double GLONASS_fM_a = 0.35e9; //!< Gravitational constant of atmosphere [m^3/s^2] +const double GLONASS_SEMI_MAJOR_AXIS = 6378136; //!< Semi-major axis of Earth [m] +const double GLONASS_FLATTENING = 1/29825784; //!< Flattening parameter +const double GLONASS_GRAVITY = 97803284; //!< Equatorial acceleration of gravity [mGal] +const double GLONASS_GRAVITY_CORRECTION = 0.87; //!< Correction to acceleration of gravity at sea-level due to Atmosphere[мGal] +const double GLONASS_J2 = 1082625.75e-9; //!< Second zonal harmonic of the geopotential +const double GLONASS_J4 = -2370.89e-9; //! GLONASS_PRN = + {{ 0, 8,}, //For test + { 1, 1,}, //Plane 1 + { 2,-4,}, //Plane 1 + { 3, 5,}, //Plane 1 + { 4, 6,}, //Plane 1 + { 5, 1,}, //Plane 1 + { 6,-4,}, //Plane 1 + { 7, 5,}, //Plane 1 + { 8, 6,}, //Plane 1 + { 9,-2,}, //Plane 2 + {10,-7,}, //Plane 2 + {11, 0,}, //Plane 2 + {12,-1,}, //Plane 2 + {13,-2,}, //Plane 2 + {14,-7,}, //Plane 2 + {15, 0,}, //Plane 2 + {16,-1,}, //Plane 2 + {17, 4,}, //Plane 3 + {18,-3,}, //Plane 3 + {19, 3,}, //Plane 3 + {20, 2,}, //Plane 3 + {21, 4,}, //Plane 3 + {22,-3,}, //Plane 3 + {23, 3,}, //Plane 3 + {24, 2}}; //Plane 3 + +const double GLONASS_STARTOFFSET_ms = 68.802; //[ms] Initial sign. travel time (this cannot go here) + +// OBSERVABLE HISTORY DEEP FOR INTERPOLATION +const int GLONASS_L1_CA_HISTORY_DEEP = 100; + +// NAVIGATION MESSAGE DEMODULATION AND DECODING +#define GLONASS_GNAV_PREAMBLE {1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0} +const double GLONASS_GNAV_PREAMBLE_DURATION_S = 0.3; +const int GLONASS_GNAV_PREAMBLE_LENGTH_BITS = 30; +const int GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS = 300; +const int GLONASS_GNAV_PREAMBLE_PERIOD_SYMBOLS = 2000; +const int GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND = 50; //!< NAV message bit rate [bits/s] +const int GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT = 10; +const int GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_PREAMBLE_BIT = 10; +const int GLONASS_GNAV_TELEMETRY_RATE_SYMBOLS_SECOND = GLONASS_GNAV_TELEMETRY_RATE_BITS_SECOND*GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; //!< NAV message bit rate [symbols/s] +const int GLONASS_GNAV_STRING_SYMBOLS = 2000; //!< Number of bits per string in the GNAV message (85 data bits + 30 time mark bits) [bits] +const int GLONASS_GNAV_STRING_BITS = 85; //!< Number of bits per string in the GNAV message (85 data bits + 30 time mark bits) [bits] +const int GLONASS_GNAV_HAMMING_CODE_BITS = 8; //!< Number of bits in hamming code sequence of GNAV message +const int GLONASS_GNAV_DATA_SYMBOLS = 1700; // STRING DATA WITHOUT PREAMBLE + +const std::vector GLONASS_GNAV_CRC_I_INDEX {9, 10, 12, 13, 15, 17, 19, 20, 22, 24, 26, 28, 30, 32, 34, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84}; +const std::vector GLONASS_GNAV_CRC_J_INDEX {9, 11, 12, 14, 15, 18, 19, 21, 22, 25, 26, 29, 30, 33, 34, 36, 37, 40, 41, 44, 45, 48, 49, 52, 53, 56, 57, 60, 61, 64, 65, 67, 68, 71, 72, 75, 76, 79, 80, 83, 84}; +const std::vector GLONASS_GNAV_CRC_K_INDEX {10, 11, 12, 16, 17, 18, 19, 23, 24, 25, 26, 31, 32, 33, 34, 38, 39, 40, 41, 46, 47, 48, 49, 54, 55, 56, 57, 62, 63, 64, 65, 69, 70, 71, 72, 77, 78, 79, 80, 85}; +const std::vector GLONASS_GNAV_CRC_L_INDEX {9, 11, 12, 14, 15, 18, 19, 21, 22, 25, 26, 29, 30, 33, 34, 36, 37, 40, 41, 44, 45, 48, 49, 52, 53, 56, 57, 60, 61, 64, 65, 67, 68, 71, 72, 75, 76, 79, 80, 83, 84}; +const std::vector GLONASS_GNAV_CRC_M_INDEX {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 81, 82, 83, 84, 85}; +const std::vector GLONASS_GNAV_CRC_N_INDEX {35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; +const std::vector GLONASS_GNAV_CRC_P_INDEX {66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; +const std::vector GLONASS_GNAV_CRC_Q_INDEX {9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; + +// GLONASS GNAV NAVIGATION MESSAGE STRUCTURE +// NAVIGATION MESSAGE FIELDS POSITIONS (from IS-GPS-200E Appendix II) + +// FRAME 1-4 +// COMMON FIELDS +const std::vector> STRING_ID({{2,4}}); +const std::vector> KX({{78,8}}); +//STRING 1 +const std::vector> P1({{8,2}}); +const std::vector> T_K_HR({{10,5}}); +const std::vector> T_K_MIN({{15,6}}); +const std::vector> T_K_SEC({{21,1}}); +const std::vector> X_N_DOT ({{22,24}}); +const std::vector> X_N_DOT_DOT ({{46,5}}); +const std::vector> X_N({{51,27}}); + +//STRING 2 +const std::vector> B_N({{6,3}}); +const std::vector> P2({{9,1}}); +const std::vector> T_B({{10,7}}); +const std::vector> Y_N_DOT ({{22,24}}); +const std::vector> Y_N_DOT_DOT ({{46,5}}); +const std::vector> Y_N({{51,27}}); + +//STRING 3 +const std::vector> P3({{6,1}}); +const std::vector> GAMMA_N({{7,11}}); +const std::vector> P({{19,2}}); +const std::vector> EPH_L_N({{21,1}}); +const std::vector> Z_N_DOT ({{22,24}}); +const std::vector> Z_N_DOT_DOT ({{46,5}}); +const std::vector> Z_N({{51,27}}); + +// STRING 4 +const std::vector> TAU_N({{6,22}}); +const std::vector> DELTA_TAU_N({{28,5}}); +const std::vector> E_N({{33,5}}); +const std::vector> P4 ({{52,1}}); +const std::vector> F_T ({{53,4}}); +const std::vector> N_T({{60,11}}); +const std::vector> N({{71,5}}); +const std::vector> M({{76,2}}); + +// STRING 5 +const std::vector> N_A({{6,11}}); +const std::vector> TAU_C({{17,32}}); +const std::vector> N_4({{50,5}}); +const std::vector> TAU_GPS({{55,22}}); +const std::vector> ALM_L_N({{77,1}}); + +// STRING 6, 8, 10, 12, 14 +const std::vector> C_N({{6,1}}); +const std::vector> M_N_A({{7,2}}); +const std::vector> n_A({{9,5}}); +const std::vector> TAU_N_A({{14,10}}); +const std::vector> LAMBDA_N_A({{24,21}}); +const std::vector> DELTA_I_N_A({{45,18}}); +const std::vector> EPSILON_N_A({{63,15}}); + +//STRING 7, 9, 11, 13, 15 +const std::vector> OMEGA_N_A({{6,16}}); +const std::vector> T_LAMBDA_N_A({{22,21}}); +const std::vector> DELTA_T_N_A({{43,22}}); +const std::vector> DELTA_T_DOT_N_A({{65,7}}); +const std::vector> H_N_A({{72,5}}); + +// STRING 14 FRAME 5 +const std::vector> B1({{6,11}}); +const std::vector> B2({{17,10}}); + + +#endif /* GNSS_SDR_GLONASS_L1_CA_H_ */ diff --git a/src/core/system_parameters/Glonass_L1_CA.h b/src/core/system_parameters/Glonass_L1_CA.h deleted file mode 100644 index bcdfd2b32..000000000 --- a/src/core/system_parameters/Glonass_L1_CA.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef GNSS_SDR_GLONASS_L1_CA_H_ -#define GNSS_SDR_GLONASS_L1_CA_H_ - -#include -#include // std::map -#include "MATH_CONSTANTS.h" -#include "gnss_frequencies.h" - -// Physical constants -const double GLONASS_C_m_s = 299792458.0; //!< The speed of light, [m/s] -const double GLONASS_C_m_ms = 299792.4580; //!< The speed of light, [m/ms] -const double GLONASS_PI = 3.1415926535898; //!< Pi as (NOT) defined in ICD-GLONASS-2008 -const double GLONASS_TWO_PI = 6.283185307179586;//!< 2Pi as (NOT) defined in ICD-GLONASS-2008 -const double GLONASS_OMEGA_EARTH_DOT = 7.292115e-5; //!< Earth rotation rate, [rad/s] -const double GLONASS_GM = 3.986004418e14; //!< Universal gravitational constant times the mass of the Earth, [m^3/s^2] -// const double F = -4.442807633e-10; //!< Constant, [s/(m)^(1/2)] - -// Geodesic constants and parameters -const double fMa = 0.35e9; //!< The Gravitational constant of atmosphere, [m^3/s^2] -const double SEMI_MAJOR_AXIS = 6378136; //!< The Semi-major axis, [m] -const double FLATTENING = 1/298.25784; //!< The Orbital Flattening -const double EQUATORIAL_GRAVITY = 978032.84; //!< The Equatorial acceleration of gravity, [mGal] -const double GRAVITY_CORRECTION = 0.87; //!< The Correction to acceleration of gravity at sea-level due to Atmosphere, [mGal] -const double SECOND_HARMONIC = 1082625.75e-9; //!< Second zonal harmonic of the geopotential (J_2^0) -const double FOURTH_HARMONIC = -2370.89e-9; //!< Fourth zonal harmonic of the geopotential (J_4^0) -const double SIXTH_HARMONIC = 6.08e-9; //!< Sixth zonal harmonic of the geopotential (J_6^0) -const double EIGHTH_HARMONIC = 1.40e-11; //!< Eighth zonal harmonic of the geopotential (J_8^0) -const double NORMAL_POTENCIAL = 62636861.4; //!< The Normal potential at surface of common terrestrial ellipsoid (U_0), [m^2/s^2] - - -// carrier and code frequencies -const double GLONASS_L1_FREQ_HZ = FREQ1_GLO; //!< L1 [Hz] -const double GLONASS_L1_CA_CODE_RATE_HZ = 0.511e6; //!< GLONASS L1 C/A code rate [chips/s] -const double GLONASS_L1_CA_CODE_LENGTH_CHIPS = 511.0; //!< GLONASS L1 C/A code length [chips] -const double GLONASS_L1_CA_CODE_PERIOD = 0.001; //!< GLONASS L1 C/A code period [seconds] -const double GLONASS_L1_CA_CHIP_PERIOD = 1.9569e-06; //!< GLONASS L1 C/A chip period [seconds] - -// GLONASS SV's orbital slots PRN = (orbital_slot - 1) -const std::map GLONASS_PRN = - {{ 0, 8,}, //For test - { 1, 1,}, //Plane 1 - { 2,-4,}, //Plane 1 - { 3, 5,}, //Plane 1 - { 4, 6,}, //Plane 1 - { 5, 1,}, //Plane 1 - { 6,-4,}, //Plane 1 - { 7, 5,}, //Plane 1 - { 8, 6,}, //Plane 1 - { 9,-2,}, //Plane 2 - {10,-7,}, //Plane 2 - {11, 0,}, //Plane 2 - {12,-1,}, //Plane 2 - {13,-2,}, //Plane 2 - {14,-7,}, //Plane 2 - {15, 0,}, //Plane 2 - {16,-1,}, //Plane 2 - {17, 4,}, //Plane 3 - {18,-3,}, //Plane 3 - {19, 3,}, //Plane 3 - {20, 2,}, //Plane 3 - {21, 4,}, //Plane 3 - {22,-3,}, //Plane 3 - {23, 3,}, //Plane 3 - {24, 2}}; //Plane 3 - - -const int GLONASS_CA_TELEMETRY_RATE_BITS_SECOND = 50; //!< NAV message bit rate [bits/s] - -#endif /* GNSS_SDR_GLONASS_L1_CA_H_ */ diff --git a/src/core/system_parameters/MATH_CONSTANTS.h b/src/core/system_parameters/MATH_CONSTANTS.h index 9be1a41cf..63db089c7 100644 --- a/src/core/system_parameters/MATH_CONSTANTS.h +++ b/src/core/system_parameters/MATH_CONSTANTS.h @@ -65,6 +65,7 @@ const double TWO_N14 = (0.00006103515625); //!< 2^-14 const double TWO_N15 = (0.00003051757813); //!< 2^-15 const double TWO_N16 = (0.0000152587890625); //!< 2^-16 const double TWO_N17 = (7.629394531250000e-006); //!< 2^-17 +const double TWO_N18 = (3.814697265625000e-006); //!< 2^-18 const double TWO_N19 = (1.907348632812500e-006); //!< 2^-19 const double TWO_N20 = (9.536743164062500e-007); //!< 2^-20 const double TWO_N21 = (4.768371582031250e-007); //!< 2^-21 diff --git a/src/core/system_parameters/glonass_gnav_almanac.cc b/src/core/system_parameters/glonass_gnav_almanac.cc new file mode 100644 index 000000000..049d3a4c0 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_almanac.cc @@ -0,0 +1,177 @@ +/*! + * \file glonass_gnav_almanac.cc + * \brief Interface of a GLONASS GNAV ALMANAC storage as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#include "glonass_gnav_almanac.h" +#include +#include "GLONASS_L1_CA.h" +#include "gnss_satellite.h" + +Glonass_Gnav_Almanac::Glonass_Gnav_Almanac() +{ + i_satellite_freq_channel = 0; + i_satellite_PRN = 0; + i_satellite_slot_number = 0; + + d_n_A = 0.0; + d_H_n_A = 0.0; + d_lambda_n_A = 0.0; + d_t_lambda_n_A = 0.0; + d_Delta_i_n_A = 0.0; + d_Delta_T_n_A = 0.0; + d_Delta_T_n_A_dot = 0.0; + d_epsilon_n_A = 0.0; + d_omega_n_A = 0.0; + d_M_n_A = 0.0; + d_KP = 0.0; + d_tau_n_A = 0.0; + d_C_n = false; + d_l_n = false; +} + +void Glonass_Gnav_Almanac::satellite_position(double N_A, double N_i, double t_i) +{ + double T_nom = 43200; // [seconds] + double i_nom = D2R*63.0; // [rad] + + double Delta_t = 0.0; + double i = 0.0; + double T = 0.0; + double n = 0.0; + double a = 0.0; + double lambda_dot = 0.0; + double omega_dot = 0.0; + double lambda = 0.0; + double omega = 0.0; + double E_P = 0.0; + double Delta_T = 0.0; + double M = 0.0; + double E = 0.0; + double E_old = 0.0; + double dE = 0.0; + + double e1_x = 0.0; + double e1_y = 0.0; + double e1_z = 0.0; + + double e2_x = 0.0; + double e2_y = 0.0; + double e2_z = 0.0; + // Compute time difference to reference time + Delta_t = (N_i - N_A) * 86400 + (t_i + d_t_lambda_n_A); + + // Compute the actual inclination + i = i_nom + d_Delta_i_n_A; + + // Compute the actual orbital period: + T = T_nom + d_Delta_T_n_A; + + // Compute the mean motion + n = 2*GLONASS_PI/T; + + // Compute the semi-major axis: + a = cbrt(GLONASS_GM/(n*n)); + + // Compute correction to longitude of ascending node + lambda_dot = -10*pow(GLONASS_SEMI_MAJOR_AXIS / a, 7/2)*D2R*cos(i)/86400; + + // Compute correction to argument of perigee + omega_dot = 5*pow(GLONASS_SEMI_MAJOR_AXIS / a, 7/2)*D2R*(5*cos(i)*cos(i) - 1)/86400; + + // Compute corrected longitude of ascending node: + lambda = d_lambda_n_A + (lambda_dot - GLONASS_OMEGA_EARTH_DOT)*Delta_t; + + // Compute corrected argument of perigee: + omega = d_omega_n_A + omega_dot*Delta_t; + + // Compute eccentric anomaly at point P: Note: P is that point of the orbit the true anomaly of which is identical to the argument of perigee. + E_P = 2*atan(tan((omega/2)*(sqrt((1 - d_epsilon_n_A)*(1 + d_epsilon_n_A))))); + + // Compute time difference to perigee passing + if (omega < GLONASS_PI) + { + Delta_T = (E_P - d_epsilon_n_A*sin(E_P))/n; + } + else + { + Delta_T = (E_P - d_epsilon_n_A*sin(E_P))/n + T; + } + + // Compute mean anomaly at epoch t_i: + M = n * (Delta_t - Delta_T); + + // Compute eccentric anomaly at epoch t_i. Note: Kepler’s equation has to be solved iteratively + + // Initial guess of eccentric anomaly + E = M; + + // --- Iteratively compute eccentric anomaly ---------------------------- + for (int ii = 1; ii < 20; ii++) + { + E_old = E; + E = M + d_epsilon_n_A * sin(E); + dE = fmod(E - E_old, 2.0 * GLONASS_PI); + if (fabs(dE) < 1e-12) + { + //Necessary precision is reached, exit from the loop + break; + } + } + + // Compute position in orbital coordinate system + d_satpos_Xo = a*cos(E) - d_epsilon_n_A; + d_satpos_Yo = a*sqrt(1 - d_epsilon_n_A*d_epsilon_n_A)*sin(E); + d_satpos_Zo = a*0; + + // Compute velocity in orbital coordinate system + d_satvel_Xo = a/(1-d_epsilon_n_A*cos(E))*(-n*sin(E)); + d_satvel_Yo = a/(1-d_epsilon_n_A*cos(E))*(n*sqrt(1 - d_epsilon_n_A*d_epsilon_n_A)*cos(E)); + d_satvel_Zo = a/(1-d_epsilon_n_A*cos(E))*(0); + + // Determine orientation vectors of orbital coordinate system in ECEF system + e1_x = cos(omega)*cos(lambda) - sin(omega)*sin(lambda); + e1_y = cos(omega)*sin(lambda) + sin(omega)*cos(lambda)*cos(i); + e1_z = sin(omega)*sin(i); + + e2_x = -sin(omega)*cos(lambda) - sin(omega)*sin(lambda)*cos(i); + e2_y = -sin(omega)*sin(lambda) + cos(omega)*cos(lambda)*cos(i); + e2_z = cos(omega)*sin(i); + + // Convert position from orbital to ECEF system + d_satpos_X = d_satpos_Xo*e1_x + d_satpos_Xo*e2_x; + d_satpos_Y = d_satpos_Yo*e1_z + d_satpos_Yo*e2_y; + d_satpos_Z = d_satpos_Zo*e1_z + d_satpos_Zo*e2_z; + + // Convert position from orbital to ECEF system + d_satvel_X = d_satvel_Xo*e1_x + d_satvel_Xo*e2_x + GLONASS_OMEGA_EARTH_DOT*d_satpos_Y; + d_satvel_Y = d_satvel_Yo*e1_z + d_satvel_Yo*e2_y - GLONASS_OMEGA_EARTH_DOT*d_satpos_X; + d_satvel_Z = d_satvel_Zo*e1_z + d_satvel_Zo*e2_z; + +} diff --git a/src/core/system_parameters/glonass_gnav_almanac.h b/src/core/system_parameters/glonass_gnav_almanac.h new file mode 100644 index 000000000..3012708dd --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_almanac.h @@ -0,0 +1,123 @@ +/*! + * \file glonass_gnav_almanac.h + * \brief Interface of a GLONASS GNAV ALMANAC storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_ALMANAC_H_ +#define GNSS_SDR_GLONASS_ALMANAC_H_ + +#include +#include +#include "boost/assign.hpp" +#include + +/*! + * \brief This class is a storage for the GLONASS SV ALMANAC data as described GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Almanac +{ +public: + double d_n_A; //!< Conventional number of satellite within GLONASS space segment [dimensionless] + double d_H_n_A; //!< Carrier frequency number of navigation RF signal transmitted by d_nA satellite as table 4.10 (0-31) [dimensionless] + double d_lambda_n_A; //!< Longitude of the first (within the d_NA day) ascending node of d_nA [semi-circles] + double d_t_lambda_n_A; //!< Time of first ascending node passage [s] + double d_Delta_i_n_A; //!< Correction of the mean value of inclination of d_n_A satellite at instant t_lambda_n_A [semi-circles] + double d_Delta_T_n_A; //!< Correction to the mean value of Draconian period of d_n_A satellite at instant t_lambda_n_A[s / orbital period] + double d_Delta_T_n_A_dot; //!< Rate of change of Draconian period of d_n_A satellite at instant t_lambda_n_A [s / orbital period^2] + double d_epsilon_n_A; //!< Eccentricity of d_n_A satellite at instant t_lambda_n_A [dimensionless] + double d_omega_n_A; //!< Argument of preigree of d_n_A satellite at instant t_lambdan_A [semi-circles] + double d_M_n_A; //!< Type of satellite n_A [dimensionless] + double d_KP; //!< Notification on forthcoming leap second correction of UTC [dimensionless] + double d_tau_n_A; //!< Coarse value of d_n_A satellite time correction to GLONASS time at instant t_lambdan_A[s] + bool d_C_n; //!< Generalized “unhealthy flag” of n_A satellite at instant of almanac upload [dimensionless] + bool d_l_n; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + + // Satellite Identification Information + int i_satellite_freq_channel; //!< SV Frequency Channel Number + unsigned int i_satellite_PRN; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + unsigned int i_satellite_slot_number; //!< SV Slot Number + + // satellite positions + double d_satpos_Xo; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + double d_satpos_Yo; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + double d_satpos_Zo; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + // Satellite velocity + double d_satvel_Xo; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + double d_satvel_Yo; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + double d_satvel_Zo; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + + // satellite positions + double d_satpos_X; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + double d_satpos_Y; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + double d_satpos_Z; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + // Satellite velocity + double d_satvel_X; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + double d_satvel_Y; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + double d_satvel_Z; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + + template + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the almanac data on disk file. + */ + void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if(version){}; + + archive & make_nvp("i_satellite_freq_channel", i_satellite_freq_channel); + archive & make_nvp("i_satellite_PRN", i_satellite_PRN); + archive & make_nvp("i_satellite_slot_number", i_satellite_slot_number); + archive & make_nvp("d_n_A", d_n_A); + archive & make_nvp("d_H_n_A", d_H_n_A); + archive & make_nvp("d_lambda_n_A", d_lambda_n_A); + archive & make_nvp("d_t_lambda_n_A", d_t_lambda_n_A); + archive & make_nvp("d_Delta_i_n_A", d_Delta_i_n_A); + archive & make_nvp("d_Delta_T_n_A", d_Delta_T_n_A); + archive & make_nvp("d_Delta_T_n_A_dot", d_Delta_T_n_A_dot); + archive & make_nvp("d_epsilon_n_A", d_epsilon_n_A); + archive & make_nvp("d_omega_n_A", d_omega_n_A); + archive & make_nvp("d_M_n_A", d_M_n_A); + archive & make_nvp("d_KP", d_KP); + archive & make_nvp("d_tau_n_A", d_tau_n_A); + archive & make_nvp("d_C_n", d_C_n); + archive & make_nvp("d_l_n", d_l_n); + } + + void satellite_position(double N_A, double N_i, double t_i); + /*! + * Default constructor + */ + Glonass_Gnav_Almanac(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.cc b/src/core/system_parameters/glonass_gnav_ephemeris.cc new file mode 100644 index 000000000..b7b8e2d3a --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_ephemeris.cc @@ -0,0 +1,123 @@ +/*! + * \file glonass_gnav_ephemeris.cc + * \brief Interface of a GLONASS GNAV EPHEMERIS storage and orbital model functions + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_ephemeris.h" +#include +#include + +#include "GLONASS_L1_CA.h" +#include "gnss_satellite.h" + +Glonass_Gnav_Ephemeris::Glonass_Gnav_Ephemeris() +{ + d_m = 0.0; //!< String number within frame [dimensionless] + d_t_k = 0.0; //!< GLONASS Time (UTC(SU) + 3 h) referenced to the beginning of the frame within the current day [s] + d_t_b = 0.0; //!< Reference ephemeris relative time in GLONASS Time (UTC(SU) + 3 h). Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [s] + d_M = 0.0; //!< Type of satellite transmitting navigation signal [dimensionless] + d_gamma_n = 0.0; //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + d_tau_n = 0.0; //!< Correction to the nth satellite time (tn) relative to GLONASS time (te), + d_Xn = 0.0; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + d_Yn = 0.0; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + d_Zn = 0.0; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + d_VXn = 0.0; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + d_VYn = 0.0; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + d_VZn = 0.0; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + d_AXn = 0.0; //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + d_AYn = 0.0; //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + d_AZn = 0.0; //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + d_B_n = 0.0; //!< Health flag [dimensionless] + d_P = 0.0; //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + d_N_T = 0.0; //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + d_F_T = 0.0; //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + d_n = 0.0; //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + d_Delta_tau_n = 0.0; //!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + d_E_n = 0.0; //!< Characterises "age" of a current information [days] + d_P_1 = 0.0; //!< Flag of the immediate data updating [minutes] + d_P_2 = false; //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + d_P_3 = false; //!< 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] + d_P_4 = false; //!< 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] + d_l3rd_n = false; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + d_l5th_n = false; //!< Health flag for nth satellite; ln = 0 indicates the n-th satellite is helthy, ln = 1 indicates malfunction of this nth satellite [dimensionless] + + // Satellite Identification Information + i_satellite_freq_channel = 0; //!< SV Frequency Channel Number + i_satellite_PRN = 0; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + i_satellite_slot_number = 0; //!< SV Slot Number + d_yr = 1972; //!< Current year, defaults to 1972 (UTC Epoch with leap seconds) + d_satClkDrift = 0.0; //!< GLONASS clock error + d_dtr = 0.0; //!< relativistic clock correction term + d_iode = 0.0; //!< Issue of data, ephemeris (Bit 0-6 of tb) + d_tau_c = 0.0; + d_TOW = 0.0; // tow of the start of frame + d_WN = 0.0; // week number of the start of frame +} + + +boost::posix_time::ptime Glonass_Gnav_Ephemeris::compute_GLONASS_time(const double offset_time) const +{ + boost::posix_time::time_duration t(0, 0, offset_time + d_tau_c); + boost::gregorian::date d1(d_yr, 1, 1); + boost::gregorian::days d2(d_N_T); + boost::posix_time::ptime glonass_time(d1+d2, t); + + return glonass_time; +} + + +double Glonass_Gnav_Ephemeris::check_t(double time) +{ + double corrTime; + double half_day = 43200.0; // seconds + corrTime = time; + if (time > half_day) + { + corrTime = time - 2.0 * half_day; + } + else if (time < -half_day) + { + corrTime = time + 2.0 * half_day; + } + return corrTime; +} + +// FIXME Fix reference here +// 20.3.3.3.3.1 User Algorithm for SV Clock Correction. +double Glonass_Gnav_Ephemeris::sv_clock_drift(double transmitTime, double timeCorrUTC) +{ + double dt; + dt = check_t(transmitTime - d_t_b); + d_satClkDrift = -(d_tau_n + timeCorrUTC - d_gamma_n * dt); + //Correct satellite group delay and missing relativistic term here + //d_satClkDrift-=d_TGD; + + return d_satClkDrift; +} diff --git a/src/core/system_parameters/glonass_gnav_ephemeris.h b/src/core/system_parameters/glonass_gnav_ephemeris.h new file mode 100644 index 000000000..281237b48 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_ephemeris.h @@ -0,0 +1,167 @@ +/*! + * \file glonass_gnav_ephemeris.h + * \brief Interface of a GLONASS EPHEMERIS storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_EPHEMERIS_H_ +#define GNSS_SDR_GLONASS_GNAV_EPHEMERIS_H_ + + +#include +#include +#include "boost/assign.hpp" +#include +#include + + + +/*! + * \brief This class is a storage and orbital model functions for the GLONASS SV ephemeris data as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Ephemeris +{ +private: + /* + * Accounts for the beginning or end of week crossover + * + * See paragraph 20.3.3.3.3.1 (IS-GPS-200E) + * \param[in] - time in seconds + * \param[out] - corrected time, in seconds + */ + double check_t(double time); + +public: + double d_m; //!< String number within frame [dimensionless] + double d_t_k; //!< GLONASS Time (UTC(SU) + 3 h) referenced to the beginning of the frame within the current day [s] + double d_t_b; //!< Reference ephemeris relative time in GLONASS Time (UTC(SU) + 3 h). Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [s] + double d_M; //!< Type of satellite transmitting navigation signal [dimensionless] + double d_gamma_n; //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + double d_tau_n; //!< Correction to the nth satellite time (tn) relative to GLONASS time (te), + double d_Xn; //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + double d_Yn; //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + double d_Zn; //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + double d_VXn; //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + double d_VYn; //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + double d_VZn; //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + double d_AXn; //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_AYn; //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_AZn; //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + double d_B_n; //!< Health flag [dimensionless] + double d_P; //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + double d_N_T; //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + double d_F_T; //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + double d_n; //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + double d_Delta_tau_n; //!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + double d_E_n; //!< Characterises "age" of a current information [days] + double d_P_1; //!< Flag of the immediate data updating [minutes] + bool d_P_2; //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + bool 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] + bool 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] + bool 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] + bool 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 + // Satellite Identification Information + int i_satellite_freq_channel; //!< SV Frequency Channel Number + unsigned int i_satellite_PRN; //!< SV PRN Number, equivalent to slot number for compatibility with GPS + unsigned int i_satellite_slot_number; //!< SV Slot Number + double d_yr; //!< Current year + double d_satClkDrift; //!< GLONASS clock error + double d_dtr; //!< relativistic clock correction term + double d_iode; //!< Issue of data, ephemeris (Bit 0-6 of tb) + double d_tau_c; + double d_TOW; // tow of the start of frame + double d_WN; // week number of the start of frame + + template + + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the ephemeris data on disk file. + */ + void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if(version){}; + + archive & make_nvp("i_satellite_freq_channel", i_satellite_freq_channel); //!< SV PRN frequency channel number + archive & make_nvp("i_satellite_PRN", i_satellite_PRN); + archive & make_nvp("i_satellite_slot_number", i_satellite_slot_number); + archive & make_nvp("d_m", d_m); //!< String number within frame [dimensionless] + archive & make_nvp("d_t_k", d_t_k); //!< Time referenced to the beginning of the frame within the current day [hours, minutes, seconds] + archive & make_nvp("d_t_b", d_t_b); //!< Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. [minutes] + archive & make_nvp("d_M", d_M); //!< Type of satellite transmitting navigation signal [dimensionless] + archive & make_nvp("d_gamma_n", d_gamma_n); //!< Relative deviation of predicted carrier frequency value of n- satellite from nominal value at the instant tb [dimensionless] + archive & make_nvp("d_tau_n", d_tau_n); //!< Correction to the nth satellite time (tn) relative to GLONASS time (te) + archive & make_nvp("d_Xn", d_Xn); //!< Earth-fixed coordinate x of the satellite in PZ-90.02 coordinate system [km]. + archive & make_nvp("d_Yn", d_Yn); //!< Earth-fixed coordinate y of the satellite in PZ-90.02 coordinate system [km] + archive & make_nvp("d_Zn", d_Zn); //!< Earth-fixed coordinate z of the satellite in PZ-90.02 coordinate system [km] + archive & make_nvp("d_VXn", d_VXn); //!< Earth-fixed velocity coordinate x of the satellite in PZ-90.02 coordinate system [km/s] + archive & make_nvp("d_VYn", d_VYn); //!< Earth-fixed velocity coordinate y of the satellite in PZ-90.02 coordinate system [km/s] + archive & make_nvp("d_VZn", d_VZn); //!< Earth-fixed velocity coordinate z of the satellite in PZ-90.02 coordinate system [km/s] + archive & make_nvp("d_AXn", d_AXn); //!< Earth-fixed acceleration coordinate x of the satellite in PZ-90.02 coordinate system [km/s^2] + archive & make_nvp("d_AYn", d_AYn); //!< Earth-fixed acceleration coordinate y of the satellite in PZ-90.02 coordinate system [km/s^2] + archive & make_nvp("d_AZn", d_AZn); //!< Earth-fixed acceleration coordinate z of the satellite in PZ-90.02 coordinate system [km/s^2] + archive & make_nvp("d_B_n", d_B_n); //!< Health flag [dimensionless] + archive & make_nvp("d_P", d_P); //!< Technological parameter of control segment, indication the satellite operation mode in respect of time parameters [dimensionless] + archive & make_nvp("d_N_T", d_N_T); //!< Current date, calendar number of day within four-year interval starting from the 1-st of January in a leap year [days] + archive & make_nvp("d_F_T", d_F_T); //!< Parameter that provides the predicted satellite user range accuracy at time tb [dimensionless] + archive & make_nvp("d_n", d_n); //!< Index of the satellite transmitting given navigation signal. It corresponds to a slot number within GLONASS constellation + archive & make_nvp("d_Delta_tau_n", d_Delta_tau_n);//!< Time difference between navigation RF signal transmitted in L2 sub- band and aviation RF signal transmitted in L1 sub-band by nth satellite. [dimensionless] + archive & make_nvp("d_E_n", d_E_n); //!< Characterises "age" of a current information [days] + archive & make_nvp("d_P_1", d_P_1); //!< Flag of the immediate data updating. + archive & make_nvp("d_P_2", d_P_2); //!< Flag of oddness ("1") or evenness ("0") of the value of (tb) [dimensionless] + archive & make_nvp("d_P_3", 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] + archive & make_nvp("d_P_4", 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] + archive & make_nvp("d_l3rd_n", 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] + archive & make_nvp("d_l5th_n", 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] + } + + /*! + * \brief Sets (\a d_satClkDrift)and returns the clock drift in seconds according to the User Algorithm for SV Clock Correction + * (IS-GPS-200E, 20.3.3.3.3.1) + */ + double sv_clock_drift(double transmitTime, double timeCorrUTC); + + /*! + * \brief Computes the GLONASS System Time and returns a boost::posix_time::ptime object + * \ param offset_time Is the start of day offset to compute the time + */ + boost::posix_time::ptime compute_GLONASS_time(const double offset_time) const; + + /*! + * Default constructor + */ + Glonass_Gnav_Ephemeris(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.cc b/src/core/system_parameters/glonass_gnav_navigation_message.cc new file mode 100644 index 000000000..7555324ef --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_navigation_message.cc @@ -0,0 +1,769 @@ +/*! + * \file glonass_gnav_navigation_message.cc + * \brief Implementation of a GLONASS GNAV Data message decoder as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_navigation_message.h" +#include +#include +#include +#include +#include +#include +#include + + +void Glonass_Gnav_Navigation_Message::reset() +{ + //!< Satellite Identification + i_channel_ID = 0; //!< Channel ID assigned by the receiver + i_satellite_freq_channel = 0; //!< SV Frequency Slot Number + i_satellite_slot_number = 0; //!< SV Orbit Slot Number + + //!< Ephmeris Flags + flag_all_ephemeris = false; + flag_ephemeris_str_1 = false; + flag_ephemeris_str_2 = false; + flag_ephemeris_str_3 = false; + flag_ephemeris_str_4 = false; + + //!< Almanac Flags + flag_all_almanac = false; + flag_almanac_str_6 = false; + flag_almanac_str_7 = false; + flag_almanac_str_8 = false; + flag_almanac_str_9 = false; + flag_almanac_str_10 = false; + flag_almanac_str_11 = false; + flag_almanac_str_12 = false; + flag_almanac_str_13 = false; + flag_almanac_str_14 = false; + flag_almanac_str_15 = false; + + //!< UTC and System Clocks Flags + flag_utc_model_valid = false; //!< If set, it indicates that the UTC model parameters are filled + flag_utc_model_str_5 = false; //!< Clock info send in string 5 of navigation data + flag_utc_model_str_15 = false; //!< Clock info send in string 15 of frame 5 of navigation data + + //broadcast orbit 1 + flag_TOW_set = false; + d_TOW = 0.0; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + d_TOW_F1 = 0.0; //!< Time of GPS Week from HOW word of Subframe 1 [s] + d_TOW_F2 = 0.0; //!< Time of GPS Week from HOW word of Subframe 2 [s] + d_TOW_F3 = 0.0; //!< Time of GPS Week from HOW word of Subframe 3 [s] + d_TOW_F4 = 0.0; //!< Time of GPS Week from HOW word of Subframe 4 [s] + d_TOW_F5 = 0.0; //!< Time of GPS Week from HOW word of Subframe 5 [s] + + flag_CRC_test = false; + d_frame_ID = 0; + d_string_ID = 0; + + // Clock terms + d_satClkCorr = 0.0; + d_dtr = 0.0; + d_satClkDrift = 0.0; + + + std::map satelliteBlock; //!< Map that stores to which block the PRN belongs http://www.navcen.uscg.gov/?Do=constellationStatus + + auto gnss_sat = Gnss_Satellite(); + std::string _system ("GLONASS"); + //TODO SHould number of channels be hardcoded? + for(unsigned int i = 1; i < 14; i++) + { + satelliteBlock[i] = gnss_sat.what_block(_system, i); + } +} + + +Glonass_Gnav_Navigation_Message::Glonass_Gnav_Navigation_Message() +{ + reset(); +} + + +bool Glonass_Gnav_Navigation_Message::CRC_test(std::bitset bits) +{ + int sum_bits = 0; + int sum_hamming = 0; + int C1 = 0; + int C2 = 0; + int C3 = 0; + int C4 = 0; + int C5 = 0; + int C6 = 0; + int C7 = 0; + int C_Sigma = 0; + std::vector string_bits(GLONASS_GNAV_STRING_BITS); + + //!< Populate data and hamming code vectors + for(int i = 0; i < static_cast(GLONASS_GNAV_STRING_BITS); i++) + { + string_bits[i] = static_cast(bits[i]); + } + + + //!< Compute C1 term + sum_bits = 0; + for(int i = 0; i < static_cast(GLONASS_GNAV_CRC_I_INDEX.size()); i++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_I_INDEX[i]]; + } + C1 = string_bits[0]^(sum_bits%2); + + //!< Compute C2 term + sum_bits = 0; + for(int j = 0; j < static_cast(GLONASS_GNAV_CRC_J_INDEX.size()); j++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_J_INDEX[j]]; + } + C2 = (string_bits[1])^(sum_bits%2); + + //!< Compute C3 term + sum_bits = 0; + for(int k = 0; k < static_cast(GLONASS_GNAV_CRC_K_INDEX.size()); k++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_K_INDEX[k]]; + } + C3 = string_bits[2]^(sum_bits%2); + + //!< Compute C4 term + sum_bits = 0; + for(int l = 0; l < static_cast(GLONASS_GNAV_CRC_L_INDEX.size()); l++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_L_INDEX[l]]; + } + C4 = string_bits[3]^(sum_bits%2); + + //!< Compute C5 term + sum_bits = 0; + for(int m = 0; m < static_cast(GLONASS_GNAV_CRC_M_INDEX.size()); m++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_M_INDEX[m]]; + } + C5 = string_bits[4]^(sum_bits%2); + + //!< Compute C6 term + sum_bits = 0; + for(int n = 0; n < static_cast(GLONASS_GNAV_CRC_N_INDEX.size()); n++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_N_INDEX[n]]; + } + C6 = string_bits[5]^(sum_bits%2); + + //!< Compute C7 term + sum_bits = 0; + for(int p = 0; p < static_cast(GLONASS_GNAV_CRC_P_INDEX.size()); p++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_P_INDEX[p]]; + } + C7 = string_bits[6]^(sum_bits%2); + + //!< Compute C_Sigma term + sum_bits = 0; + sum_hamming = 0; + for(int q = 0; q < static_cast(GLONASS_GNAV_CRC_Q_INDEX.size()); q++) + { + sum_bits += string_bits[GLONASS_GNAV_CRC_Q_INDEX[q]]; + } + for(int q = 0; q < 8; q++) + { + sum_hamming += string_bits[q]; + } + C_Sigma = (sum_hamming%2)^(sum_bits%2); + + //!< Verification of the data + // All of the checksums are equal to zero + if((C1 & C2 & C3 & C4 & C5 & C6 & C7 & C_Sigma) == 0 ) + { + return true; + } + // only one of the checksums (C1,...,C7) is equal to zero but C_Sigma = 1 + else if(C_Sigma == 1 && C1+C2+C3+C4+C5+C6+C7 == 6) + { + return true; + } + else + { + return false; + } +} + + +bool Glonass_Gnav_Navigation_Message::read_navigation_bool(std::bitset bits, const std::vector> parameter) +{ + bool value; + + if (bits[GLONASS_GNAV_STRING_BITS - parameter[0].first] == 1) + { + value = true; + } + else + { + value = false; + } + return value; +} + + +unsigned long int Glonass_Gnav_Navigation_Message::read_navigation_unsigned(std::bitset bits, const std::vector> parameter) +{ + unsigned long int value = 0; + int num_of_slices = parameter.size(); + for (int i = 0; i < num_of_slices; i++) + { + for (int j = 0; j < parameter[i].second; j++) + { + value <<= 1; //shift left + if (bits[GLONASS_GNAV_STRING_BITS - parameter[i].first - j] == 1) + { + value += 1; // insert the bit + } + } + } + return value; +} + + +signed long int Glonass_Gnav_Navigation_Message::read_navigation_signed(std::bitset bits, const std::vector> parameter) +{ + signed long int value = 0; + signed long int sign = 0; + int num_of_slices = parameter.size(); + // read the MSB and perform the sign extension + if (bits[GLONASS_GNAV_STRING_BITS - parameter[0].first] == 1) + { + sign = -1; + } + else + { + sign = 1; + } + for (int i = 0; i < num_of_slices; i++) + { + for (int j = 1; j < parameter[i].second; j++) + { + value <<= 1; //shift left + if (bits[GLONASS_GNAV_STRING_BITS - parameter[i].first - j] == 1) + { + value += 1; // insert the bit + } + } + } + return (sign*value); +} + + +unsigned int Glonass_Gnav_Navigation_Message::get_frame_number(unsigned int satellite_slot_number) +{ + unsigned int frame_ID = 0; + + if(satellite_slot_number >= 1 and satellite_slot_number <= 5 ) + { + frame_ID = 1; + } + else if(satellite_slot_number >= 6 and satellite_slot_number <= 10 ) + { + frame_ID = 2; + } + else if(satellite_slot_number >= 11 and satellite_slot_number <= 15 ) + { + frame_ID = 3; + } + else if(satellite_slot_number >= 16 and satellite_slot_number <= 20 ) + { + frame_ID = 4; + } + else if(satellite_slot_number >= 21 and satellite_slot_number <= 24 ) + { + frame_ID = 5; + } + else + { + //TODO Find print statement and make it an error + frame_ID = 0; + } + + return frame_ID; +} + + +double Glonass_Gnav_Navigation_Message::get_TOW() +{ + double TOW = 0.0; + double utcsu2utc = 3*3600; + double glot2utcsu = 3*3600; + int i = 0; + + TOW = gnav_ephemeris.d_t_k + glot2utcsu + utcsu2utc + gnav_utc_model.d_tau_c + gnav_utc_model.d_tau_gps; + + for (i = 0; GLONASS_LEAP_SECONDS[i][0]>0; i++) + { + if (GLONASS_LEAP_SECONDS[i][0] == gnav_ephemeris.d_yr) + { + TOW -= GLONASS_LEAP_SECONDS[i][6]; + } + } + return TOW; +} + + +int Glonass_Gnav_Navigation_Message::string_decoder(std::string frame_string) +{ + int J = 0; + d_string_ID = 0; + d_frame_ID = 0; + + // UNPACK BYTES TO BITS AND REMOVE THE CRC REDUNDANCE + std::bitset string_bits = std::bitset((frame_string)); + d_string_ID = static_cast(read_navigation_unsigned(string_bits, STRING_ID)); + + flag_CRC_test = CRC_test(string_bits); + + // Decode all 15 string messages + switch (d_string_ID) + { + case 1: + //--- It is string 1 ----------------------------------------------- + gnav_ephemeris.d_P_1 = (static_cast(read_navigation_unsigned(string_bits, P1)) + 1)*15; + gnav_ephemeris.d_t_k = static_cast(read_navigation_unsigned(string_bits, T_K_HR)) * 3600 + + static_cast(read_navigation_unsigned(string_bits, T_K_MIN)) * 60 + + static_cast(read_navigation_unsigned(string_bits, T_K_SEC)) * 30; + gnav_ephemeris.d_VXn = static_cast(read_navigation_signed(string_bits, X_N_DOT)) * TWO_N20; + gnav_ephemeris.d_AXn = static_cast(read_navigation_signed(string_bits, X_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Xn = static_cast(read_navigation_signed(string_bits, X_N)) * TWO_N11; + + flag_ephemeris_str_1 = true; + + break; + + case 2: + //--- It is string 2 ----------------------------------------------- + if (flag_ephemeris_str_1 == true) + { + gnav_ephemeris.d_B_n = static_cast(read_navigation_unsigned(string_bits, B_N)); + gnav_ephemeris.d_P_2 = static_cast(read_navigation_bool(string_bits, P2)); + gnav_ephemeris.d_t_b = static_cast(read_navigation_unsigned(string_bits, T_B))*gnav_ephemeris.d_P_1*60; + gnav_ephemeris.d_VYn = static_cast(read_navigation_signed(string_bits, Y_N_DOT))* TWO_N20; + gnav_ephemeris.d_AYn = static_cast(read_navigation_signed(string_bits, Y_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Yn = static_cast(read_navigation_signed(string_bits, Y_N)) * TWO_N11; + + gnav_ephemeris.d_iode = read_navigation_unsigned(string_bits, T_B); + flag_ephemeris_str_2 = true; + } + + break; + + case 3: + // --- It is string 3 ---------------------------------------------- + gnav_ephemeris.d_P_3 = static_cast(read_navigation_bool(string_bits, P3)); + gnav_ephemeris.d_gamma_n = static_cast(read_navigation_signed(string_bits, GAMMA_N)) * TWO_N40; + gnav_ephemeris.d_P = static_cast(read_navigation_unsigned(string_bits, P)); + gnav_ephemeris.d_l3rd_n = static_cast(read_navigation_bool(string_bits, EPH_L_N)); + gnav_ephemeris.d_VZn = static_cast(read_navigation_signed(string_bits, Z_N_DOT)) * TWO_N20; + gnav_ephemeris.d_AZn = static_cast(read_navigation_signed(string_bits, Z_N_DOT_DOT)) * TWO_N30; + gnav_ephemeris.d_Zn = static_cast(read_navigation_signed(string_bits, Z_N)) * TWO_N11; + + flag_ephemeris_str_3 = true; + + break; + + case 4: + // --- It is string 4 ---------------------------------------------- + gnav_ephemeris.d_tau_n = static_cast(read_navigation_signed(string_bits, TAU_N)) * TWO_N30; + gnav_ephemeris.d_Delta_tau_n = static_cast(read_navigation_signed(string_bits, DELTA_TAU_N)) * TWO_N30; + gnav_ephemeris.d_E_n = static_cast(read_navigation_unsigned(string_bits, E_N)); + gnav_ephemeris.d_P_4 = static_cast(read_navigation_bool(string_bits, P4)); + gnav_ephemeris.d_F_T = static_cast(read_navigation_unsigned(string_bits, F_T)); + gnav_ephemeris.d_N_T = static_cast(read_navigation_unsigned(string_bits, N_T)); + gnav_ephemeris.d_n = static_cast(read_navigation_unsigned(string_bits, N)); + gnav_ephemeris.d_M = static_cast(read_navigation_unsigned(string_bits, M)); + + // Fill in ephemeris deliverables in the code + gnav_ephemeris.i_satellite_slot_number = gnav_ephemeris.d_n; + gnav_ephemeris.i_satellite_PRN = gnav_ephemeris.d_n; + + flag_ephemeris_str_4 = true; + + break; + + case 5: + // --- It is string 5 ---------------------------------------------- + gnav_utc_model.d_N_A = static_cast(read_navigation_unsigned(string_bits, N_A)); + gnav_utc_model.d_tau_c = static_cast(read_navigation_signed(string_bits, TAU_C)) * TWO_N31; + gnav_utc_model.d_N_4 = static_cast(read_navigation_unsigned(string_bits, N_4)); + gnav_utc_model.d_tau_gps = static_cast(read_navigation_signed(string_bits, TAU_GPS)) * TWO_N30; + gnav_ephemeris.d_l5th_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + flag_utc_model_str_5 = true; + // Compute Year and DoY based on Algorithm A3.11 of GLONASS ICD + if(flag_ephemeris_str_4 == true) + { + //Current year number J in the four-year interval is calculated: + if(gnav_ephemeris.d_N_T >= 1 && gnav_ephemeris.d_N_T <= 366) + { + J = 1; + } + else if ( gnav_ephemeris.d_N_T >= 367 && gnav_ephemeris.d_N_T <= 731) + { + J = 2; + } + else if (gnav_ephemeris.d_N_T >= 732 && gnav_ephemeris.d_N_T <= 1096) + { + J = 3; + } + else if (gnav_ephemeris.d_N_T >= 1097 && gnav_ephemeris.d_N_T <= 1461) + { + J = 4; + } + // 2). Current year in common form is calculated by the following formula: + gnav_ephemeris.d_yr = 1996 + 4.0*(gnav_utc_model.d_N_4 - 1.0) + (J - 1.0); + gnav_ephemeris.d_tau_c = gnav_utc_model.d_tau_c; + + // 3). Set TOW once the year has been defined, it helps with leap second determination + if(flag_ephemeris_str_1 == true) + { + d_TOW = get_TOW(); + flag_TOW_set = true; + } + + } + break; + + case 6: + // --- It is string 6 ---------------------------------------------- + i_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_satellite_slot_number); + + gnav_almanac[i_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_6 = true; + + break; + + case 7: + // --- It is string 7 ---------------------------------------------- + if (flag_almanac_str_6 == true) + { + gnav_almanac[i_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15; + gnav_almanac[i_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if(gnav_almanac[i_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + + if(i_satellite_slot_number == gnav_ephemeris.i_satellite_slot_number) + { + gnav_ephemeris.i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel; + } + flag_almanac_str_7 = true; + } + + + break; + case 8: + // --- It is string 8 ---------------------------------------------- + i_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_satellite_slot_number); + + gnav_almanac[i_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_8 = true; + + break; + case 9: + // --- It is string 9 ---------------------------------------------- + if (flag_almanac_str_8 == true) + { + // TODO signed vs unsigned reading from datasheet + gnav_almanac[i_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15; + gnav_almanac[i_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)) -32.0; + gnav_almanac[i_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if(gnav_almanac[i_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_9 = true; + } + break; + case 10: + // --- It is string 10 --------------------------------------------- + i_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_satellite_slot_number); + + gnav_almanac[i_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_10 = true; + + break; + + case 11: + // --- It is string 11 --------------------------------------------- + if (flag_almanac_str_10 == true) + { + gnav_almanac[i_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15; + gnav_almanac[i_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)) - 32.0; + gnav_almanac[i_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if(gnav_almanac[i_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_11 = true; + } + break; + case 12: + // --- It is string 12 --------------------------------------------- + i_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_satellite_slot_number); + + gnav_almanac[i_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_12 = true; + + break; + + case 13: + // --- It is string 13 --------------------------------------------- + if (flag_almanac_str_12 == true) + { + gnav_almanac[i_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15; + gnav_almanac[i_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)) - 32.0; + gnav_almanac[i_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if(gnav_almanac[i_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_13 = true; + } + break; + case 14: + // --- It is string 14 --------------------------------------------- + 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)); + } + else + { + i_satellite_slot_number = static_cast(read_navigation_unsigned(string_bits, n_A)); + d_frame_ID = get_frame_number(i_satellite_slot_number); + + gnav_almanac[i_satellite_slot_number - 1].d_C_n = static_cast(read_navigation_bool(string_bits, C_N)); + gnav_almanac[i_satellite_slot_number - 1].d_M_n_A = static_cast(read_navigation_unsigned(string_bits, M_N_A)); + gnav_almanac[i_satellite_slot_number - 1].d_n_A = static_cast(read_navigation_unsigned(string_bits, n_A)); + gnav_almanac[i_satellite_slot_number - 1].d_tau_n_A = static_cast(read_navigation_unsigned(string_bits, TAU_N_A)) * TWO_N18; + gnav_almanac[i_satellite_slot_number - 1].d_lambda_n_A = static_cast(read_navigation_signed(string_bits, LAMBDA_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_i_n_A = static_cast(read_navigation_signed(string_bits, DELTA_I_N_A)) * TWO_N20; + gnav_almanac[i_satellite_slot_number - 1].d_epsilon_n_A = static_cast(read_navigation_unsigned(string_bits, EPSILON_N_A)) * TWO_N20; + + flag_almanac_str_14 = true; + } + + + break; + + case 15: + // --- It is string 9 ---------------------------------------------- + if (d_frame_ID != 5 and flag_almanac_str_14 == true ) + { + gnav_almanac[i_satellite_slot_number - 1].d_omega_n_A = static_cast(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15; + gnav_almanac[i_satellite_slot_number - 1].d_t_lambda_n_A = static_cast(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A = static_cast(read_navigation_signed(string_bits, DELTA_T_N_A)) * TWO_N9; + gnav_almanac[i_satellite_slot_number - 1].d_Delta_T_n_A_dot = static_cast(read_navigation_signed(string_bits, DELTA_T_DOT_N_A)) * TWO_N14; + gnav_almanac[i_satellite_slot_number - 1].d_H_n_A = static_cast(read_navigation_unsigned(string_bits, H_N_A)) - 32.0; + gnav_almanac[i_satellite_slot_number - 1].d_l_n = static_cast(read_navigation_bool(string_bits, ALM_L_N)); + + // Set satellite information for redundancy purposes + if(gnav_almanac[i_satellite_slot_number - 1].d_H_n_A > 24) + { + gnav_almanac[i_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_satellite_slot_number - 1].d_H_n_A - 32.0; + } + gnav_almanac[i_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + gnav_almanac[i_satellite_slot_number - 1].i_satellite_PRN = gnav_almanac[i_satellite_slot_number - 1].d_n_A; + + flag_almanac_str_15 = true; + } + break; + default: + LOG(INFO) << "GLONASS GNAV: Invalid String ID of received. Received " << d_string_ID << ", but acceptable range is from 1-15"; + + + break; + } // switch string ID ... + + return d_string_ID; +} + + +double Glonass_Gnav_Navigation_Message::utc_time(const double glonass_time_corrected) const +{ + double t_utc; + + t_utc = glonass_time_corrected + 3*3600 + gnav_utc_model.d_tau_c; + return t_utc; +} + + +Glonass_Gnav_Ephemeris Glonass_Gnav_Navigation_Message::get_ephemeris() +{ + return gnav_ephemeris; +} + + +Glonass_Gnav_Utc_Model Glonass_Gnav_Navigation_Message::get_utc_model() +{ + return gnav_utc_model; +} + + +Glonass_Gnav_Almanac Glonass_Gnav_Navigation_Message::get_almanac(unsigned int satellite_slot_number) +{ + return gnav_almanac[satellite_slot_number - 1]; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_ephemeris() //Check if we have a new ephemeris stored in the galileo navigation class +{ + if ((flag_ephemeris_str_1 == true) and (flag_ephemeris_str_2 == true) and (flag_ephemeris_str_3 == true) and (flag_ephemeris_str_4 == true)) + { + if (gnav_ephemeris.d_P_4 == 1) + { + flag_ephemeris_str_1 = false;// clear the flag + flag_ephemeris_str_2 = false;// clear the flag + flag_ephemeris_str_3 = false;// clear the flag + flag_ephemeris_str_4 = false;// clear the flag + flag_all_ephemeris = true; + DLOG(INFO) << "Ephemeris (1, 2, 3, 4) have been received and belong to the same batch" << std::endl; + + return true; + } + else + { + return false; + } + } + else + return false; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_utc_model() // Check if we have a new utc data set stored in the galileo navigation class +{ + if (flag_utc_model_valid == true) + { + flag_utc_model_valid = false; // clear the flag + return true; + } + else + return false; +} + + +bool Glonass_Gnav_Navigation_Message::have_new_almanac() //Check if we have a new almanac data set stored in the galileo navigation class +{ + if ((flag_almanac_str_6 == true) and (flag_almanac_str_7 == true) and + (flag_almanac_str_8 == true) and (flag_almanac_str_9 == true) and + (flag_almanac_str_10 == true) and (flag_almanac_str_11 == true) and + (flag_almanac_str_12 == true) and (flag_almanac_str_13 == true) and + (flag_almanac_str_14 == true) and (flag_almanac_str_15 == true)) + { + //All almanac have been received + flag_almanac_str_6 = false; + flag_almanac_str_7 = false; + flag_almanac_str_8 = false; + flag_almanac_str_9 = false; + flag_almanac_str_10 = false; + flag_almanac_str_11 = false; + flag_almanac_str_12 = false; + flag_almanac_str_13 = false; + flag_almanac_str_14 = false; + flag_almanac_str_15 = false; + flag_all_almanac = true; + return true; + } + else + return false; +} diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.h b/src/core/system_parameters/glonass_gnav_navigation_message.h new file mode 100644 index 000000000..04836fc62 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_navigation_message.h @@ -0,0 +1,176 @@ +/*! + * \file glonass_gnav_navigation_message.h + * \brief Interface of a GLONASS GNAV Data message decoder as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_NAVIGATION_MESSAGE_H_ +#define GNSS_SDR_GLONASS_GNAV_NAVIGATION_MESSAGE_H_ + + +#include +#include +#include +#include +#include +#include "GLONASS_L1_CA.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_utc_model.h" + + + +/*! + * \brief This class decodes a GLONASS GNAV Data message as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Navigation_Message +{ +private: + unsigned long int read_navigation_unsigned(std::bitset bits, const std::vector> parameter); + signed long int read_navigation_signed(std::bitset bits, const std::vector> parameter); + bool read_navigation_bool(std::bitset bits, const std::vector> parameter); + +public: + bool flag_CRC_test; + unsigned int d_frame_ID; + unsigned int d_string_ID; + + Glonass_Gnav_Ephemeris gnav_ephemeris; //!< Ephemeris information decoded + Glonass_Gnav_Utc_Model gnav_utc_model; //!< UTC model information + Glonass_Gnav_Almanac gnav_almanac[24]; //!< Almanac information for all 24 satellites + + //!< Satellite Identification + int i_channel_ID; //!< Channel ID assigned by the receiver + unsigned int i_satellite_freq_channel; //!< SV Frequency Slot Number + unsigned int i_satellite_slot_number; //!< SV Orbit Slot Number + + //!< Ephmeris Flags + bool flag_all_ephemeris; //!< Flag indicating that all strings containing ephemeris have been received + bool flag_ephemeris_str_1; //!< Flag indicating that ephemeris 1/4 (string 1) have been received + bool flag_ephemeris_str_2; //!< Flag indicating that ephemeris 2/4 (string 2) have been received + bool flag_ephemeris_str_3; //!< Flag indicating that ephemeris 3/4 (string 3) have been received + bool flag_ephemeris_str_4; //!< Flag indicating that ephemeris 4/4 (string 4) have been received + + //!< Almanac Flags + bool flag_all_almanac; //!< Flag indicating that all almanac have been received + bool flag_almanac_str_6; //!< Flag indicating that almanac of string 6 have been received + bool flag_almanac_str_7; //!< Flag indicating that almanac of string 7 have been received + bool flag_almanac_str_8; //!< Flag indicating that almanac of string 8 have been received + bool flag_almanac_str_9; //!< Flag indicating that almanac of string 9 have been received + bool flag_almanac_str_10; //!< Flag indicating that almanac of string 10 have been received + bool flag_almanac_str_11; //!< Flag indicating that almanac of string 11 have been received + bool flag_almanac_str_12; //!< Flag indicating that almanac of string 12 have been received + bool flag_almanac_str_13; //!< Flag indicating that almanac of string 13 have been received + bool flag_almanac_str_14; //!< Flag indicating that almanac of string 14 have been received + bool flag_almanac_str_15; //!< Flag indicating that almanac of string 15 have been received + + //!< UTC and System Clocks Flags + bool flag_utc_model_valid; //!< If set, it indicates that the UTC model parameters are filled + bool flag_utc_model_str_5; //!< Clock info send in string 5 of navigation data + bool flag_utc_model_str_15; //!< Clock info send in string 15 of frame 5 of navigation data + + bool flag_TOW_set; + double d_TOW; //!< Time of GPS Week of the ephemeris set (taken from subframes TOW) [s] + double d_TOW_F1; //!< Time of GPS Week from HOW word of Subframe 1 [s] + double d_TOW_F2; //!< Time of GPS Week from HOW word of Subframe 2 [s] + double d_TOW_F3; //!< Time of GPS Week from HOW word of Subframe 3 [s] + double d_TOW_F4; //!< Time of GPS Week from HOW word of Subframe 4 [s] + double d_TOW_F5; //!< Time of GPS Week from HOW word of Subframe 5 [s] + + // Clock terms + double d_satClkCorr; // Satellite clock error + double d_dtr; // Relativistic clock correction term + double d_satClkDrift; // Satellite clock drift + + bool CRC_test(std::bitset bits); + + unsigned int get_frame_number(unsigned int satellite_slot_number); + + /*! + * \brief Reset GLONASS GNAV Navigation Information + */ + void reset(); + + /*! + * \brief Obtain a GLONASS GNAV SV Ephemeris class filled with current SV data + */ + Glonass_Gnav_Ephemeris get_ephemeris(); + + /*! + * \brief Obtain a GLONASS GNAV UTC model parameters class filled with current SV data + */ + Glonass_Gnav_Utc_Model get_utc_model(); + + /* + * \brief Returns a Galileo_Almanac object filled with the latest navigation data received + */ + Glonass_Gnav_Almanac get_almanac(unsigned int satellite_slot_number); + + /* + * \brief Returns true if new Ephemeris has arrived. The flag is set to false when the function is executed + */ + bool have_new_ephemeris(); + + /* + * \brief Returns true if new UTC model has arrived. The flag is set to false when the function is executed + */ + bool have_new_utc_model(); + + /* + * \brief Returns true if new UTC model has arrived. The flag is set to false when the function is executed + */ + bool have_new_almanac(); + + /*! + * \brief Decodes the GLONASS GNAV string + */ + int string_decoder(std::string frame_string); + + /*! + * \brief Gets the time of week in GPS Time + * \details This converts from GLONASS Time to GPS Time of Week based on the + * start of frame + */ + double get_TOW(); + + /*! + * \brief Computes the Coordinated Universal Time (UTC) and returns it in [s] + */ + double utc_time(const double glonasstime_corrected) const; + + /*! + * Default constructor + */ + Glonass_Gnav_Navigation_Message(); +}; + +#endif diff --git a/src/core/system_parameters/glonass_gnav_utc_model.cc b/src/core/system_parameters/glonass_gnav_utc_model.cc new file mode 100644 index 000000000..ec9d5e20e --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_utc_model.cc @@ -0,0 +1,55 @@ +/* + * \file glonass_gnav_utc_model.h + * \brief Interface of a GLONASS GNAV UTC MODEL storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "glonass_gnav_utc_model.h" +#include + +Glonass_Gnav_Utc_Model::Glonass_Gnav_Utc_Model() +{ + valid = false; + d_tau_c = 0.0; + d_tau_gps = 0.0; + d_N_4 = 0.0; + d_N_A = 0.0; + d_B1 = 0.0; + d_B2 = 0.0; +} + +double Glonass_Gnav_Utc_Model::utc_time(double glonass_time_corrected) +{ + double t_utc; + + // GLONASS Time is relative to UTC Moscow, so we simply add its time difference + t_utc = glonass_time_corrected + 3*3600 + d_tau_c; + + return t_utc; +} diff --git a/src/core/system_parameters/glonass_gnav_utc_model.h b/src/core/system_parameters/glonass_gnav_utc_model.h new file mode 100644 index 000000000..9e84762d6 --- /dev/null +++ b/src/core/system_parameters/glonass_gnav_utc_model.h @@ -0,0 +1,88 @@ +/*! + * \file glonass_gnav_utc_model.h + * \brief Interface of a GLONASS GNAV UTC MODEL storage + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GLONASS_GNAV_UTC_MODEL_H_ +#define GNSS_SDR_GLONASS_GNAV_UTC_MODEL_H_ + +#include "boost/assign.hpp" +#include +#include + +/*! + * \brief This class is a storage for the GLONASS GNAV UTC MODEL data as described in GLONASS ICD (Edition 5.1) + * \note Code added as part of GSoC 2017 program + * \see GLONASS ICD + */ +class Glonass_Gnav_Utc_Model +{ +public: + bool valid; + // Clock Parameters + double d_tau_c; //!< GLONASS time scale correction to UTC(SU) time. [s] + double d_tau_gps; //!< Correction to GPS time to GLONASS time [day] + double d_N_4; //!< Four year interval number starting from 1996 [4 year interval] + double d_N_A; //!< Calendar day number within the four-year period beginning since the leap year for Almanac data [days] + double d_B1; //!< Coefficient to determine DeltaUT1 [s] + double d_B2; //!< Coefficient to determine DeltaUT1 [s/msd] + + template + /*! + * \brief Serialize is a boost standard method to be called by the boost XML serialization. Here is used to save the almanac data on disk file. + */ + void serialize(Archive& archive, const unsigned int version) + { + using boost::serialization::make_nvp; + if(version){}; + archive & make_nvp("valid",valid); + archive & make_nvp("d_tau_c", d_tau_c); + archive & make_nvp("d_tau_gps", d_tau_gps); + archive & make_nvp("d_N_4", d_N_4); + archive & make_nvp("d_N_A", d_N_A); + archive & make_nvp("d_B1", d_B1); + archive & make_nvp("d_B2", d_B2); + } + + /*! + * Default constructor + */ + Glonass_Gnav_Utc_Model(); + + /*! + * \brief Computes the Coordinated Universal Time (UTC) and + * returns it in [s] (GLONASS ICD (Edition 5.1) Section 3.3.3 GLONASS Time) + */ + double utc_time(double glonass_time_corrected); + +}; + +#endif diff --git a/src/core/system_parameters/gnss_satellite.cc b/src/core/system_parameters/gnss_satellite.cc index b192224fb..7fb9c38ec 100644 --- a/src/core/system_parameters/gnss_satellite.cc +++ b/src/core/system_parameters/gnss_satellite.cc @@ -557,6 +557,3 @@ void Gnss_Satellite::set_block(const std::string& system_, unsigned int PRN_) { block = what_block(system_, PRN_); } - - - diff --git a/src/core/system_parameters/gps_ephemeris.h b/src/core/system_parameters/gps_ephemeris.h index 0a413a927..a08f34400 100644 --- a/src/core/system_parameters/gps_ephemeris.h +++ b/src/core/system_parameters/gps_ephemeris.h @@ -37,6 +37,7 @@ #include #include "boost/assign.hpp" #include +#include diff --git a/src/core/system_parameters/rtcm.cc b/src/core/system_parameters/rtcm.cc index 9999b3671..20c5141b2 100644 --- a/src/core/system_parameters/rtcm.cc +++ b/src/core/system_parameters/rtcm.cc @@ -316,6 +316,41 @@ long int Rtcm::bin_to_int(const std::string& s) const } +long int Rtcm::bin_to_sint(const std::string& s) const +{ + if(s.length() > 32) + { + LOG(WARNING) << "Cannot convert to a long int"; + return 0; + } + long int reading; + long int sign; + + // Check for sign bit as defined RTCM doc + if(s.substr(0,1).compare("0") == 0) + { + sign = 1; + // Get the magnitude of the value + reading = strtol((s.substr (1)).c_str(), NULL, 2); + } + else + { + sign = -1; + // Get the magnitude of the value + reading = strtol((s.substr (1)).c_str(), NULL, 2); + } + return sign*reading; +} + +// Find the sign for glonass data fields (neg = 1, pos = 0) +static inline unsigned long glo_sgn(double val) +{ + if (val < 0) return 1; // If value is negative return 1 + if (val==0) return 0; // Positive or equal to zero return 0 + return 0; +} + + double Rtcm::bin_to_double(const std::string& s) const { double reading; @@ -1080,6 +1115,410 @@ std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_ } +// ******************************************************** +// +// MESSAGE TYPE 1009 (GLONASS L1 Basic RTK Observables) +// +// ******************************************************** +std::bitset<61> Rtcm::get_MT1009_12_header(unsigned int msg_number, double obs_time, const std::map & observables, + unsigned int ref_id, unsigned int smooth_int, bool sync_flag, bool divergence_free) +{ + unsigned int reference_station_id = ref_id; // Max: 4095 + const std::map observables_ = observables; + bool synchronous_GNSS_flag = sync_flag; + bool divergence_free_smoothing_indicator = divergence_free; + unsigned int smoothing_interval = smooth_int; + Rtcm::set_DF002(msg_number); + Rtcm::set_DF003(reference_station_id); + Rtcm::set_DF034(obs_time); + Rtcm::set_DF005(synchronous_GNSS_flag); + Rtcm::set_DF035(observables_); + Rtcm::set_DF036(divergence_free_smoothing_indicator); + Rtcm::set_DF037(smoothing_interval); + + std::string header = DF002.to_string() + + DF003.to_string() + + DF034.to_string() + + DF005.to_string() + + DF035.to_string() + + DF036.to_string() + + DF037.to_string(); + + std::bitset<61> header_msg(header); + return header_msg; +} + + +std::bitset<64> Rtcm::get_MT1009_sat_content(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchro); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(eph.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchro); + Rtcm::set_DF042(gnss_synchro); + Rtcm::set_DF043(eph, obs_time, gnss_synchro); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string(); + + std::bitset<64> content_msg(content); + return content_msg; +} + + +std::string Rtcm::print_MT1009(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id) +{ + unsigned int ref_id = static_cast(station_id); + unsigned int smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get a map with GLONASS L1 only observations + std::map observablesL1; + std::map::const_iterator observables_iter; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1009, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for(observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + std::bitset<64> content = Rtcm::get_MT1009_sat_content(glonass_gnav_eph, obs_time, observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if(server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +// ******************************************************** +// +// MESSAGE TYPE 1010 (EXTENDED GLONASS L1 OBSERVATIONS) +// +// ******************************************************** + +std::string Rtcm::print_MT1010(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id) +{ + unsigned int ref_id = static_cast(station_id); + unsigned int smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get a map with GPS L1 only observations + std::map observablesL1; + std::map::const_iterator observables_iter; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1010, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for(observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + std::bitset<79> content = Rtcm::get_MT1010_sat_content(glonass_gnav_eph, obs_time, observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if(server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<79> Rtcm::get_MT1010_sat_content(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchro); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(eph.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchro); + Rtcm::set_DF042(gnss_synchro); + Rtcm::set_DF043(eph, obs_time, gnss_synchro); + Rtcm::set_DF044(gnss_synchro); + Rtcm::set_DF045(gnss_synchro); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF044.to_string() + + DF045.to_string(); + + std::bitset<79> content_msg(content); + return content_msg; +} + + + +// ******************************************************** +// +// MESSAGE TYPE 1011 (GLONASS L1 & L2 OBSERVATIONS) +// +// ******************************************************** + +std::string Rtcm::print_MT1011(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id) +{ + unsigned int ref_id = static_cast(station_id); + unsigned int smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get maps with GPS L1 and L2 observations + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("R") == 0) && (sig_.compare("2C") == 0)) + { + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + // Get common observables + std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables; + std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; + + for(observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + for(observables_iter2 = observablesL2.begin(); + observables_iter2 != observablesL2.end(); + observables_iter2++) + { + if(observables_iter2->second.PRN == prn_) + { + std::pair p; + Gnss_Synchro pr1 = observables_iter->second; + Gnss_Synchro pr2 = observables_iter2->second; + p = std::make_pair(pr1, pr2); + common_observables.push_back(p); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1011, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for(common_observables_iter = common_observables.begin(); + common_observables_iter != common_observables.end(); + common_observables_iter++) + { + std::bitset<107> content = Rtcm::get_MT1011_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if(server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<107> Rtcm::get_MT1011_sat_content(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchroL1); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(ephL1.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchroL1); + Rtcm::set_DF042(gnss_synchroL1); + Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1); + std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF046_.to_string() + + DF047.to_string() + + DF048.to_string() + + DF049.to_string(); + + std::bitset<107> content_msg(content); + return content_msg; +} + + + +// ****************************************************************** +// +// MESSAGE TYPE 1004 (EXTENDED GLONASS L1 & L2 OBSERVATIONS) +// +// ****************************************************************** + +std::string Rtcm::print_MT1012(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id) +{ + unsigned int ref_id = static_cast(station_id); + unsigned int smooth_int = 0; + bool sync_flag = false; + bool divergence_free = false; + + //Get maps with GLONASS L1 and L2 observations + std::map observablesL1; + std::map observablesL2; + std::map::const_iterator observables_iter; + std::map::const_iterator observables_iter2; + + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + std::string system_(&observables_iter->second.System, 1); + std::string sig_(observables_iter->second.Signal); + if((system_.compare("R") == 0) && (sig_.compare("1C") == 0)) + { + observablesL1.insert(std::pair(observables_iter->first, observables_iter->second)); + } + if((system_.compare("R") == 0) && (sig_.compare("2C") == 0)) + { + observablesL2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + + // Get common observables + std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables; + std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter; + std::map observablesL1_with_L2; + + for(observables_iter = observablesL1.begin(); + observables_iter != observablesL1.end(); + observables_iter++) + { + unsigned int prn_ = observables_iter->second.PRN; + for(observables_iter2 = observablesL2.begin(); + observables_iter2 != observablesL2.end(); + observables_iter2++) + { + if(observables_iter2->second.PRN == prn_) + { + std::pair p; + Gnss_Synchro pr1 = observables_iter->second; + Gnss_Synchro pr2 = observables_iter2->second; + p = std::make_pair(pr1, pr2); + common_observables.push_back(p); + observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second)); + } + } + } + + std::bitset<61> header = Rtcm::get_MT1009_12_header(1012, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free); + std::string data = header.to_string(); + + for(common_observables_iter = common_observables.begin(); + common_observables_iter != common_observables.end(); + common_observables_iter++) + { + std::bitset<130> content = Rtcm::get_MT1012_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second); + data += content.to_string(); + } + + std::string msg = build_message(data); + if(server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +std::bitset<130> Rtcm::get_MT1012_sat_content(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +{ + bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct + Rtcm::set_DF038(gnss_synchroL1); + Rtcm::set_DF039(code_indicator); + Rtcm::set_DF040(ephL1.i_satellite_freq_channel); + Rtcm::set_DF041(gnss_synchroL1); + Rtcm::set_DF042(gnss_synchroL1); + Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1); + Rtcm::set_DF044(gnss_synchroL1); + Rtcm::set_DF045(gnss_synchroL1); + std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y + Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2); + Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2); + Rtcm::set_DF050(gnss_synchroL2); + + std::string content = DF038.to_string() + + DF039.to_string() + + DF040.to_string() + + DF041.to_string() + + DF042.to_string() + + DF043.to_string() + + DF044.to_string() + + DF045.to_string() + + DF046_.to_string() + + DF047.to_string() + + DF048.to_string() + + DF049.to_string() + + DF050.to_string(); + + std::bitset<130> content_msg(content); + return content_msg; +} + + // ******************************************************** // // MESSAGE TYPE 1019 (GPS EPHEMERIS) @@ -1299,6 +1738,267 @@ int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph) } +// ******************************************************** +// +// MESSAGE TYPE 1020 (GLONASS EPHEMERIS) +// +// ******************************************************** + +std::string Rtcm::print_MT1020(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + unsigned int msg_number = 1020; + unsigned int glonass_gnav_alm_health = 0; + unsigned int glonass_gnav_alm_health_ind = 0; + unsigned int fifth_str_additional_data_ind = 1; + + Rtcm::set_DF002(msg_number); + Rtcm::set_DF038(glonass_gnav_eph); + Rtcm::set_DF040(glonass_gnav_eph); + Rtcm::set_DF104(glonass_gnav_alm_health); + Rtcm::set_DF105(glonass_gnav_alm_health_ind); + Rtcm::set_DF106(glonass_gnav_eph); + Rtcm::set_DF107(glonass_gnav_eph); + Rtcm::set_DF108(glonass_gnav_eph); + Rtcm::set_DF109(glonass_gnav_eph); + Rtcm::set_DF110(glonass_gnav_eph); + Rtcm::set_DF111(glonass_gnav_eph); + Rtcm::set_DF112(glonass_gnav_eph); + Rtcm::set_DF113(glonass_gnav_eph); + Rtcm::set_DF114(glonass_gnav_eph); + Rtcm::set_DF115(glonass_gnav_eph); + Rtcm::set_DF116(glonass_gnav_eph); + Rtcm::set_DF117(glonass_gnav_eph); + Rtcm::set_DF118(glonass_gnav_eph); + Rtcm::set_DF119(glonass_gnav_eph); + Rtcm::set_DF120(glonass_gnav_eph); + Rtcm::set_DF121(glonass_gnav_eph); + Rtcm::set_DF122(glonass_gnav_eph); + Rtcm::set_DF123(glonass_gnav_eph); + Rtcm::set_DF124(glonass_gnav_eph); + Rtcm::set_DF125(glonass_gnav_eph); + Rtcm::set_DF126(glonass_gnav_eph); + Rtcm::set_DF127(glonass_gnav_eph); + Rtcm::set_DF128(glonass_gnav_eph); + Rtcm::set_DF129(glonass_gnav_eph); + Rtcm::set_DF130(glonass_gnav_eph); + Rtcm::set_DF131(fifth_str_additional_data_ind); + Rtcm::set_DF132(glonass_gnav_utc_model); + Rtcm::set_DF133(glonass_gnav_utc_model); + Rtcm::set_DF134(glonass_gnav_utc_model); + Rtcm::set_DF135(glonass_gnav_utc_model); + Rtcm::set_DF136(glonass_gnav_eph); + + std::string data; + data.clear(); + data = DF002.to_string() + + DF038.to_string() + + DF040.to_string() + + DF104.to_string() + + DF105.to_string() + + DF106.to_string() + + DF107.to_string() + + DF108.to_string() + + DF109.to_string() + + DF110.to_string() + + DF111.to_string() + + DF112.to_string() + + DF113.to_string() + + DF114.to_string() + + DF115.to_string() + + DF116.to_string() + + DF117.to_string() + + DF118.to_string() + + DF119.to_string() + + DF120.to_string() + + DF121.to_string() + + DF122.to_string() + + DF123.to_string() + + DF124.to_string() + + DF125.to_string() + + DF126.to_string() + + DF127.to_string() + + DF128.to_string() + + DF129.to_string() + + DF130.to_string() + + DF131.to_string() + + DF132.to_string() + + DF133.to_string() + + DF134.to_string() + + DF135.to_string() + + DF136.to_string() + + std::bitset<7>().to_string(); // Reserved bits + + if (data.length() != 360) + { + LOG(WARNING) << "Bad-formatted RTCM MT1020 (360 bits expected, found " << data.length() << ")"; + } + + std::string msg = build_message(data); + if(server_is_running) + { + rtcm_message_queue->push(msg); + } + return msg; +} + + +int Rtcm::read_MT1020(const std::string & message, Glonass_Gnav_Ephemeris & glonass_gnav_eph, Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + // Convert message to binary + std::string message_bin = Rtcm::binary_data_to_bin(message); + int glonass_gnav_alm_health = 0; + int glonass_gnav_alm_health_ind = 0; + int fifth_str_additional_data_ind = 0; + + if(!Rtcm::check_CRC(message) ) + { + LOG(WARNING) << " Bad CRC detected in RTCM message MT1020"; + return 1; + } + + unsigned int preamble_length = 8; + unsigned int reserved_field_length = 6; + unsigned int index = preamble_length + reserved_field_length; + + unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10))); + index += 10; + + if (read_message_length != 45) // 360 bits = 45 bytes + { + LOG(WARNING) << " Message MT1020 seems too long (61 bytes expected, " << read_message_length << " received)"; + return 1; + } + + // Check than the message number is correct + unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12)); + index += 12; + + if (1020 != read_msg_number) + { + LOG(WARNING) << " This is not a MT1020 message"; + return 1; + } + + // Fill Gps Ephemeris with message data content + glonass_gnav_eph.i_satellite_slot_number = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6))); + index += 6; + + glonass_gnav_eph.i_satellite_freq_channel = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5)) - 7.0); + index += 5; + + glonass_gnav_alm_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + if(glonass_gnav_alm_health){} //Avoid comiler warning + + glonass_gnav_alm_health_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + if(glonass_gnav_alm_health_ind){} //Avoid comiler warning + + glonass_gnav_eph.d_P_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + glonass_gnav_eph.d_P_1 = (glonass_gnav_eph.d_P_1+1)*15; + index += 2; + + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 5)))*3600; + index += 5; + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 6)))*60; + index += 6; + glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 1)))*30; + index += 1; + + glonass_gnav_eph.d_B_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_P_2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_t_b = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 7)))*glonass_gnav_eph.d_P_1*60.0; + index += 7; + + // TODO Check for type spec for intS24 + glonass_gnav_eph.d_VXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20; + index += 24; + + glonass_gnav_eph.d_Xn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11; + index += 27; + + glonass_gnav_eph.d_AXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30; + index += 5; + + glonass_gnav_eph.d_VYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20; + index += 24; + + glonass_gnav_eph.d_Yn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11; + index += 27; + + glonass_gnav_eph.d_AYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30; + index += 5; + + glonass_gnav_eph.d_VZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20; + index += 24; + + glonass_gnav_eph.d_Zn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11; + index += 27; + + glonass_gnav_eph.d_AZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30; + index += 5; + + glonass_gnav_eph.d_P_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_gamma_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 11)))*TWO_N30; + index += 11; + + glonass_gnav_eph.d_P = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + index += 2; + + glonass_gnav_eph.d_l3rd_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22)))* TWO_N30; + index += 22; + + glonass_gnav_eph.d_Delta_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))* TWO_N30; + index += 5; + + glonass_gnav_eph.d_E_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5))); + index += 5; + + glonass_gnav_eph.d_P_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + glonass_gnav_eph.d_F_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4))); + index += 4; + + glonass_gnav_eph.d_N_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11))); + index += 11; + + glonass_gnav_eph.d_M = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2))); + index += 2; + + fifth_str_additional_data_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + index += 1; + + if(fifth_str_additional_data_ind == true) + { + glonass_gnav_utc_model.d_N_A = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11))); + index += 11; + + glonass_gnav_utc_model.d_tau_c = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 32)))* TWO_N31; + index += 32; + + glonass_gnav_utc_model.d_N_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5))); + index += 5; + + glonass_gnav_utc_model.d_tau_gps = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22)))* TWO_N30; + index += 22; + + glonass_gnav_eph.d_l5th_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1))); + } + + return 0; +} + + // ******************************************************** // // MESSAGE TYPE 1029 (UNICODE TEXT STRING) @@ -1582,6 +2282,7 @@ int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph) std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -1594,8 +2295,9 @@ std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1071; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1071; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1081; if(gal_eph.i_satellite_PRN != 0) msg_number = 1091; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -1640,9 +2342,12 @@ std::string Rtcm::get_MSM_header(unsigned int msg_number, bool divergence_free, bool more_messages) { + // Find first element in observables block and define type of message + std::map::const_iterator observables_iter = observables.begin(); + std::string sys(observables_iter->second.System, 1); + Rtcm::set_DF002(msg_number); Rtcm::set_DF003(ref_id); - Rtcm::set_DF004(obs_time); Rtcm::set_DF393(more_messages); Rtcm::set_DF409(0); // Issue of Data Station. 0: not utilized std::bitset<7> DF001_ = std::bitset<7>("0000000"); @@ -1655,7 +2360,20 @@ std::string Rtcm::get_MSM_header(unsigned int msg_number, Rtcm::set_DF395(observables); std::string header = DF002.to_string() + DF003.to_string(); - header += DF004.to_string(); + // GNSS Epoch Time Specific to each constellation + if((sys.compare("R") == 0 )) + { + // GLONASS Epoch Time + Rtcm::set_DF034(obs_time); + header += DF034.to_string(); + } + else + { + // GPS, Galileo Epoch Time + Rtcm::set_DF004(obs_time); + header += DF004.to_string(); + } + header = header + DF393.to_string() + DF409.to_string() + DF001_.to_string() + @@ -1747,6 +2465,7 @@ std::string Rtcm::get_MSM_1_content_signal_data(const std::map & observables, unsigned int ref_id, @@ -1759,8 +2478,9 @@ std::string Rtcm::print_MSM_2( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1072; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1072; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1082; if(gal_eph.i_satellite_PRN != 0) msg_number = 1092; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -1782,7 +2502,7 @@ std::string Rtcm::print_MSM_2( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_2_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_2_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -1794,7 +2514,12 @@ std::string Rtcm::print_MSM_2( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -1820,7 +2545,7 @@ std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, co for(unsigned int cell = 0; cell < Ncells ; cell++) { Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); first_data_type += DF401.to_string(); second_data_type += DF402.to_string(); @@ -1842,6 +2567,7 @@ std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -1854,8 +2580,9 @@ std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1073; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1073; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1083; if(gal_eph.i_satellite_PRN != 0) msg_number = 1093; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -1877,7 +2604,7 @@ std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_3_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_3_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -1889,7 +2616,12 @@ std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -1917,7 +2649,7 @@ std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, co { Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); first_data_type += DF400.to_string(); second_data_type += DF401.to_string(); @@ -1939,6 +2671,7 @@ std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -1951,8 +2684,9 @@ std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1074; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1074; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1084; if(gal_eph.i_satellite_PRN != 0) msg_number = 1094; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -1974,7 +2708,7 @@ std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_4_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_4_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -2026,7 +2760,12 @@ std::string Rtcm::get_MSM_4_content_sat_data(const std::map & } -std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -2055,7 +2794,7 @@ std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, co { Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second); first_data_type += DF400.to_string(); @@ -2079,6 +2818,7 @@ std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -2091,8 +2831,9 @@ std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1075; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1075; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1085; if(gal_eph.i_satellite_PRN != 0) msg_number = 1095; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -2114,7 +2855,7 @@ std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_5_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_5_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -2172,7 +2913,12 @@ std::string Rtcm::get_MSM_5_content_sat_data(const std::map & } -std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -2202,7 +2948,7 @@ std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, co { Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF404(ordered_by_PRN_pos.at( cell ).second); @@ -2229,6 +2975,7 @@ std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -2241,8 +2988,9 @@ std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1076; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1076; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1086; if(gal_eph.i_satellite_PRN != 0) msg_number = 1096; - if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -2264,7 +3012,7 @@ std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_6_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_6_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -2276,7 +3024,12 @@ std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -2305,7 +3058,7 @@ std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, co { Rtcm::set_DF405(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF406(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF408(ordered_by_PRN_pos.at( cell ).second); first_data_type += DF405.to_string(); @@ -2330,6 +3083,7 @@ std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, co std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -2342,8 +3096,9 @@ std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, unsigned int msg_number = 0; if(gps_eph.i_satellite_PRN != 0) msg_number = 1077; if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1077; + if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1087; if(gal_eph.i_satellite_PRN != 0) msg_number = 1097; - if(((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0)) + if(((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0) ) && (glo_gnav_eph.i_satellite_PRN != 0) && (gal_eph.i_satellite_PRN != 0)) { LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages? } @@ -2365,7 +3120,7 @@ std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables); - std::string signal_data = Rtcm::get_MSM_7_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, obs_time, observables); + std::string signal_data = Rtcm::get_MSM_7_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables); std::string message = build_message(header + sat_data + signal_data); if(server_is_running) @@ -2377,7 +3132,12 @@ std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph, } -std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables) +std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, + const Gps_CNAV_Ephemeris & ephCNAV, + const Galileo_Ephemeris & ephFNAV, + const Glonass_Gnav_Ephemeris & ephGNAV, + double obs_time, + const std::map & observables) { std::string signal_data; std::string first_data_type; @@ -2407,7 +3167,7 @@ std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, co { Rtcm::set_DF405(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF406(ordered_by_PRN_pos.at( cell ).second); - Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); + Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF408(ordered_by_PRN_pos.at( cell ).second); Rtcm::set_DF404(ordered_by_PRN_pos.at( cell ).second); @@ -2587,6 +3347,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; @@ -2662,6 +3429,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 @@ -3028,6 +3838,232 @@ int Rtcm::set_DF031(unsigned int antenna_setup_id) } +int Rtcm::set_DF034(double obs_time) +{ + // TOW in milliseconds from the beginning of the GLONASS day, measured in GLONASS time + unsigned long int tk = static_cast(std::round(obs_time * 1000)); + if(tk > 86400999) + { + LOG(WARNING) << "To large GLONASS Epoch Time (tk)! Set to the last millisecond of the day"; + tk = 86400999; + } + DF034 = std::bitset<27>(tk); + return 0; +} + + +int Rtcm::set_DF035(const std::map & observables) +{ + //Number of satellites observed in current epoch + unsigned short int nsats = 0; + std::map::const_iterator observables_iter; + for(observables_iter = observables.begin(); + observables_iter != observables.end(); + observables_iter++) + { + nsats++; + } + if (nsats > 31) + { + LOG(WARNING) << "The number of processed GLONASS satellites must be between 0 and 31, but it seems that you are processing " << nsats; + nsats = 31; + } + DF035 = std::bitset<5>(nsats); + return 0; +} + + +int Rtcm::set_DF036(bool divergence_free_smoothing_indicator) +{ + // 0 - Divergence-free smoothing not used 1 - Divergence-free smoothing used + DF036 = std::bitset<1>(divergence_free_smoothing_indicator); + return 0; +} + + +int Rtcm::set_DF037(short int smoothing_interval) +{ + DF037 = std::bitset<3>(smoothing_interval); + return 0; +} + + +int Rtcm::set_DF038(const Gnss_Synchro & gnss_synchro) +{ + unsigned int prn_ = gnss_synchro.PRN; + if(prn_ > 24) + { + LOG(WARNING) << "GLONASS satellite ID (Slot Number) must be between 1 and 24, but PRN " << prn_ << " was found"; + } + DF038 = std::bitset<6>(prn_); + return 0; +} + + +int Rtcm::set_DF038(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int prn_ = glonass_gnav_eph.i_satellite_slot_number; + if(prn_ > 24) + { + LOG(WARNING) << "GLONASS satellite ID (Slot Number) must be between 0 and 24, but PRN " << prn_ << " was found"; + } + DF038 = std::bitset<6>(prn_); + return 0; +} + + +int Rtcm::set_DF039(bool code_indicator) +{ + DF039 = std::bitset<1>(code_indicator); + return 0; +} + + +int Rtcm::set_DF040(int frequency_channel_number) +{ + unsigned int freq_ = frequency_channel_number + 7; + if(freq_ > 20) + { + LOG(WARNING) << "GLONASS Satellite Frequency Number Conversion Error." + << "Value must be between 0 and 20, but converted channel" + << "frequency number " << freq_ << " was found"; + } + + DF040 = std::bitset<5>(freq_); + return 0; +} + + +int Rtcm::set_DF040(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int freq_ = glonass_gnav_eph.i_satellite_freq_channel + 7; + if(freq_ > 20) + { + LOG(WARNING) << "GLONASS Satellite Frequency Number Conversion Error." + << "Value must be between 0 and 20, but converted channel" + << "frequency number " << freq_ << " was found"; + } + + DF040 = std::bitset<5>(freq_); + return 0; +} + + +int Rtcm::set_DF041(const Gnss_Synchro & gnss_synchro) +{ + double ambiguity = std::floor( gnss_synchro.Pseudorange_m / 599584.92 ); + unsigned long int glonass_L1_pseudorange = static_cast(std::round(( gnss_synchro.Pseudorange_m - ambiguity * 599584.92) / 0.02 )); + DF041 = std::bitset<25>(glonass_L1_pseudorange); + return 0; +} + + +int Rtcm::set_DF042(const Gnss_Synchro & gnss_synchro) +{ + const double lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + double ambiguity = std::floor( gnss_synchro.Pseudorange_m / 599584.92 ); + double glonass_L1_pseudorange = std::round(( gnss_synchro.Pseudorange_m - ambiguity * 599584.92) / 0.02 ); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 299792.458; + double L1_phaserange_c = gnss_synchro.Carrier_phase_rads / GLONASS_TWO_PI; + double L1_phaserange_c_r = std::fmod(L1_phaserange_c - glonass_L1_pseudorange_c / lambda + 1500.0, 3000.0) - 1500.0; + long int glonass_L1_phaserange_minus_L1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda / 0.0005 )); + DF042 = std::bitset<20>(glonass_L1_phaserange_minus_L1_pseudorange); + return 0; +} + + +int Rtcm::set_DF043(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + unsigned int lock_time_indicator; + unsigned int lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); + DF043 = std::bitset<7>(lock_time_indicator); + return 0; +} + + +int Rtcm::set_DF044(const Gnss_Synchro & gnss_synchro) +{ + unsigned int glonass_L1_pseudorange_ambiguity = static_cast(std::floor(gnss_synchro.Pseudorange_m / 599584.916)); + DF044 = std::bitset<7>(glonass_L1_pseudorange_ambiguity); + return 0; +} + + +int Rtcm::set_DF045(const Gnss_Synchro & gnss_synchro) +{ + double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; + if (CN0_dB_Hz_est > 63.75) + { + LOG(WARNING) << "GLONASS L1 CNR must be between 0 and 63.75, but CNR " << CN0_dB_Hz_est << " was found. Setting to 63.75 dB-Hz"; + CN0_dB_Hz_est = 63.75; + } + unsigned int CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25 )); + DF045 = std::bitset<8>(CN0_dB_Hz); + return 0; +} + + +int Rtcm::set_DF047(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +{ + double ambiguity = std::floor( gnss_synchroL1.Pseudorange_m / 599584.92 ); + double glonass_L1_pseudorange = std::round(( gnss_synchroL1.Pseudorange_m - ambiguity * 599584.92) / 0.02 ); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 599584.92; + + double l2_l1_pseudorange = gnss_synchroL2.Pseudorange_m - glonass_L1_pseudorange_c; + int pseudorange_difference = 0xFFFFE000; // invalid value; + if(std::fabs(l2_l1_pseudorange) <= 163.82) + { + pseudorange_difference = static_cast(std::round(l2_l1_pseudorange / 0.02)); + } + DF047 = std::bitset<14>(pseudorange_difference); + return 0; +} + +//TODO Need to consider frequency channel in this fields +int Rtcm::set_DF048(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2) +{ + const double lambda2 = GLONASS_C_m_s / GLONASS_L2_FREQ_HZ; + int l2_phaserange_minus_l1_pseudorange = 0xFFF80000; + double ambiguity = std::floor( gnss_synchroL1.Pseudorange_m / 599584.92 ); + double glonass_L1_pseudorange = std::round(( gnss_synchroL1.Pseudorange_m - ambiguity * 599584.92) / 0.02 ); + double glonass_L1_pseudorange_c = glonass_L1_pseudorange * 0.02 + ambiguity * 599584.92; + double L2_phaserange_c = gnss_synchroL2.Carrier_phase_rads / GLONASS_TWO_PI; + double L1_phaserange_c_r = std::fmod(L2_phaserange_c - glonass_L1_pseudorange_c / lambda2 + 1500.0, 3000.0) - 1500.0; + + if (std::fabs(L1_phaserange_c_r * lambda2) <= 262.1435 ) + { + l2_phaserange_minus_l1_pseudorange = static_cast(std::round(L1_phaserange_c_r * lambda2 / 0.0005)); + } + + DF048 = std::bitset<20>(l2_phaserange_minus_l1_pseudorange); + return 0; +} + + +int Rtcm::set_DF049(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro) +{ + unsigned int lock_time_indicator; + unsigned int lock_time_period_s = Rtcm::lock_time(eph, obs_time, gnss_synchro); + lock_time_indicator = Rtcm::lock_time_indicator(lock_time_period_s); + DF049 = std::bitset<7>(lock_time_indicator); + return 0; +} + + +int Rtcm::set_DF050(const Gnss_Synchro & gnss_synchro) +{ + double CN0_dB_Hz_est = gnss_synchro.CN0_dB_hz; + if (CN0_dB_Hz_est > 63.75) + { + CN0_dB_Hz_est = 63.75; + } + unsigned int CN0_dB_Hz = static_cast(std::round(CN0_dB_Hz_est / 0.25 )); + DF050 = std::bitset<8>(CN0_dB_Hz); + return 0; +} + + int Rtcm::set_DF051(const Gps_Ephemeris & gps_eph, double obs_time) { const double gps_t = obs_time; @@ -3288,6 +4324,318 @@ int Rtcm::set_DF103(const Gps_Ephemeris & gps_eph) } +int Rtcm::set_DF104(unsigned int glonass_gnav_alm_health) +{ + DF104 = std::bitset<1>(glonass_gnav_alm_health); + return 0; +} + + +int Rtcm::set_DF105(unsigned int glonass_gnav_alm_health_ind) +{ + DF105 = std::bitset<1>(glonass_gnav_alm_health_ind); + return 0; +} + + +int Rtcm::set_DF106(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + // Convert the value from (15, 30, 45, 60) to (00, 01, 10, 11) + unsigned int P_1 = static_cast(std::round(glonass_gnav_eph.d_P_1/15.0 -1.0)); + DF106 = std::bitset<2>(P_1); + return 0; +} + + +int Rtcm::set_DF107(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int hrs = 0; + unsigned int min = 0; + unsigned int sec = 0; + unsigned int tk = 0; + tk = static_cast(glonass_gnav_eph.d_t_k); + hrs = tk/3600; + min = (tk - hrs*3600)/60; + sec = (tk - hrs*3600 -min*60)/60; + + std::string _hrs = std::bitset< 5 >( hrs ).to_string(); // string conversion + std::string _min = std::bitset< 6 >( min ).to_string(); // string conversion + std::string _sec = std::bitset< 1 >( sec ).to_string(); // string conversion + + // Set hrs, min, sec in designed bit positions + DF107 = std::bitset<12>(_hrs + _min + _sec); + + return 0; +} + + +int Rtcm::set_DF108(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + DF108 = std::bitset<1>(glonass_gnav_eph.d_B_n); + return 0; +} + + +int Rtcm::set_DF109(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + DF109 = std::bitset<1>(glonass_gnav_eph.d_P_2); + return 0; +} + + +int Rtcm::set_DF110(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int t_b = static_cast(std::round(glonass_gnav_eph.d_t_b/(glonass_gnav_eph.d_P_1*60))); + DF110 = std::bitset<7>(t_b); + return 0; +} + + +int Rtcm::set_DF111(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int VXn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VXn/TWO_N20))); + unsigned int VXn_sgn = glo_sgn(glonass_gnav_eph.d_VXn); + + DF111 = std::bitset<24>(VXn_mag); + DF111.set(23,VXn_sgn); + return 0; +} + + +int Rtcm::set_DF112(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int Xn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Xn/TWO_N11))); + unsigned int Xn_sgn = glo_sgn(glonass_gnav_eph.d_Xn); + + DF112 = std::bitset<27>(Xn_mag); + DF112.set(26,Xn_sgn); + return 0; +} + + +int Rtcm::set_DF113(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int AXn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AXn/TWO_N30))); + unsigned int AXn_sgn = glo_sgn(glonass_gnav_eph.d_AXn); + + DF113 = std::bitset<5>(AXn_mag); + DF113.set(4,AXn_sgn); + return 0; +} + + +int Rtcm::set_DF114(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int VYn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VYn/TWO_N20))); + unsigned int VYn_sgn = glo_sgn(glonass_gnav_eph.d_VYn); + + DF114 = std::bitset<24>(VYn_mag); + DF114.set(23,VYn_sgn); + return 0; +} + + +int Rtcm::set_DF115(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int Yn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Yn/TWO_N11))); + unsigned int Yn_sgn = glo_sgn(glonass_gnav_eph.d_Yn); + + DF115 = std::bitset<27>(Yn_mag); + DF115.set(26,Yn_sgn); + return 0; +} + + +int Rtcm::set_DF116(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int AYn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AYn/TWO_N30))); + unsigned int AYn_sgn = glo_sgn(glonass_gnav_eph.d_AYn); + + DF116 = std::bitset<5>(AYn_mag); + DF116.set(4,AYn_sgn); + return 0; +} + + + +int Rtcm::set_DF117(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int VZn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_VZn/TWO_N20))); + unsigned int VZn_sgn = glo_sgn(glonass_gnav_eph.d_VZn); + + DF117 = std::bitset<24>(VZn_mag); + DF117.set(23,VZn_sgn); + return 0; +} + + + +int Rtcm::set_DF118(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int Zn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Zn/TWO_N11))); + unsigned int Zn_sgn = glo_sgn(glonass_gnav_eph.d_Zn); + + DF118 = std::bitset<27>(Zn_mag); + DF118.set(26,Zn_sgn); + return 0; +} + + + +int Rtcm::set_DF119(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int AZn_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_AZn/TWO_N30))); + unsigned int AZn_sgn = glo_sgn(glonass_gnav_eph.d_AZn); + + DF119 = std::bitset<5>(AZn_mag); + DF119.set(4,AZn_sgn); + return 0; +} + + +int Rtcm::set_DF120(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int P3 = static_cast(std::round(glonass_gnav_eph.d_P_3)); + DF120 = std::bitset<1>(P3); + return 0; +} + + +int Rtcm::set_DF121(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int gamma_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_gamma_n/TWO_N40))); + unsigned int gamma_sgn = glo_sgn(glonass_gnav_eph.d_gamma_n); + + DF121 = std::bitset<11>(gamma_mag); + DF121.set(10,gamma_sgn); + return 0; +} + + +int Rtcm::set_DF122(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int P = static_cast(std::round(glonass_gnav_eph.d_P)); + DF122 = std::bitset<2>(P); + return 0; +} + + +int Rtcm::set_DF123(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int ln = static_cast((glonass_gnav_eph.d_l3rd_n)); + DF123 = std::bitset<1>(ln); + return 0; +} + + +int Rtcm::set_DF124(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int tau_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_tau_n/TWO_N30))); + unsigned int tau_sgn = glo_sgn(glonass_gnav_eph.d_tau_n); + + DF124 = std::bitset<22>(tau_mag); + DF124.set(21,tau_sgn); + return 0; +} + + +int Rtcm::set_DF125(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + int delta_tau_mag = static_cast(std::round(fabs(glonass_gnav_eph.d_Delta_tau_n/TWO_N30))); + unsigned int delta_tau_sgn = glo_sgn(glonass_gnav_eph.d_Delta_tau_n); + + DF125 = std::bitset<5>(delta_tau_mag); + DF125.set(4,delta_tau_sgn); + return 0; +} + + +int Rtcm::set_DF126(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int ecc = static_cast(std::round(glonass_gnav_eph.d_E_n)); + DF126 = std::bitset<5>(ecc); + return 0; +} + + +int Rtcm::set_DF127(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int P4= static_cast(std::round(glonass_gnav_eph.d_P_4)); + DF127 = std::bitset<1>(P4); + return 0; +} + + +int Rtcm::set_DF128(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int F_t = static_cast(std::round(glonass_gnav_eph.d_F_T)); + DF128 = std::bitset<4>(F_t); + return 0; +} + + +int Rtcm::set_DF129(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int N_t = static_cast(std::round(glonass_gnav_eph.d_N_T)); + DF129 = std::bitset<11>(N_t); + return 0; +} + + +int Rtcm::set_DF130(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int M = static_cast(std::round(glonass_gnav_eph.d_M)); + DF130 = std::bitset<2>(M); + return 0; +} + + +int Rtcm::set_DF131(unsigned int fifth_str_additional_data_ind) +{ + unsigned int fith_str_data = static_cast(fifth_str_additional_data_ind); + DF131 = std::bitset<1>(fith_str_data); + return 0; +} + + +int Rtcm::set_DF132(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + unsigned int N_A = static_cast(std::round(glonass_gnav_utc_model.d_N_A)); + DF132 = std::bitset<11>(N_A); + return 0; +} + + +int Rtcm::set_DF133(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + int tau_c = static_cast(std::round(glonass_gnav_utc_model.d_tau_c/TWO_N31)); + DF133 = std::bitset<32>(tau_c); + return 0; +} + + +int Rtcm::set_DF134(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + unsigned int N_4 = static_cast(std::round(glonass_gnav_utc_model.d_N_4)); + DF134 = std::bitset<5>(N_4); + return 0; +} + + +int Rtcm::set_DF135(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model) +{ + int tau_gps = static_cast(std::round(glonass_gnav_utc_model.d_tau_gps)/TWO_N30); + DF135 = std::bitset<22>(tau_gps); + return 0; +} + + +int Rtcm::set_DF136(const Glonass_Gnav_Ephemeris & glonass_gnav_eph) +{ + unsigned int l_n = static_cast(std::round(glonass_gnav_eph.d_l5th_n)); + DF136 = std::bitset<1>(l_n); + return 0; +} int Rtcm::set_DF137(const Gps_Ephemeris & gps_eph) @@ -3628,6 +4976,16 @@ int Rtcm::set_DF395(const std::map & gnss_synchro) mask_position = 32 - 16; DF395.set(mask_position, true); } + if ((sig.compare("1C") == 0) && (sys.compare("R") == 0 ) ) + { + mask_position = 32 - 2; + DF395.set(mask_position, true); + } + if ((sig.compare("2C") == 0) && (sys.compare("R") == 0 ) ) + { + mask_position = 32 - 8; + DF395.set(mask_position, true); + } } return 0; @@ -3888,27 +5246,37 @@ int Rtcm::set_DF401(const Gnss_Synchro & gnss_synchro) double lambda = 0.0; std::string sig_(gnss_synchro.Signal); std::string sig = sig_.substr(0,2); + std::string sys(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig.compare("1C") == 0) && (sys.compare("G") == 0 )) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig.compare("2S")) == 0 && (sys.compare("G") == 0 )) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig.compare("5X")) == 0 && (sys.compare("E") == 0 )) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig.compare("1B")) == 0 && (sys.compare("E") == 0 )) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig.compare("7X")) == 0 && (sys.compare("E") == 0 )) { lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } + if ((sig.compare("1C") == 0) && (sys.compare("R") == 0 )) + { + lambda = GLONASS_C_m_s / ((GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN)))); + } + if ((sig.compare("2C") == 0) && (sys.compare("R") == 0 )) + { + // TODO Need to add slot number and freq number to gnss_syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_FREQ_HZ); + } phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI ) * lambda - rough_range_m; @@ -3939,23 +5307,33 @@ int Rtcm::set_DF401(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro) +int Rtcm::set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro) { unsigned int lock_time_period_s = 0; unsigned int lock_time_indicator; std::string sig_(gnss_synchro.Signal); - if(sig_.compare("1C")) + std::string sys(&gnss_synchro.System, 1); + if ((sig_.compare("1C") == 0) && (sys.compare("G") == 0 )) { lock_time_period_s = Rtcm::lock_time(ephNAV, obs_time, gnss_synchro); } - if(sig_.compare("2S")) + if ((sig_.compare("2S") == 0) && (sys.compare("G") == 0 )) { lock_time_period_s = Rtcm::lock_time(ephCNAV, obs_time, gnss_synchro); } + // TODO Should add system for galileo satellites if(sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) { lock_time_period_s = Rtcm::lock_time(ephFNAV, obs_time, gnss_synchro); } + if ((sig_.compare("1C") == 0) && (sys.compare("R") == 0 )) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } + if ((sig_.compare("2C") == 0) && (sys.compare("R") == 0 )) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } lock_time_indicator = Rtcm::msm_lock_time_indicator(lock_time_period_s); DF402 = std::bitset<4>(lock_time_indicator); return 0; @@ -3977,28 +5355,37 @@ int Rtcm::set_DF404(const Gnss_Synchro & gnss_synchro) std::string sig_(gnss_synchro.Signal); std::string sig = sig_.substr(0,2); int fine_phaserange_rate; + std::string sys_(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig_.compare("1C") == 0) && (sys_.compare("G") == 0 )) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig_.compare("2S") == 0) && (sys_.compare("G") == 0 )) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig_.compare("5X") == 0) && (sys_.compare("E") == 0 )) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig_.compare("1B") == 0) && (sys_.compare("E") == 0 )) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig_.compare("7X") == 0 ) && (sys_.compare("E") == 0 )) { lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } - + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0 )) + { + lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0 )) + { + //TODO Need to add slot number and freq number to gnss syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_FREQ_HZ); + } double rough_phase_range_rate = std::round(- gnss_synchro.Carrier_Doppler_hz * lambda ); double phrr = (- gnss_synchro.Carrier_Doppler_hz * lambda - rough_phase_range_rate); @@ -4055,29 +5442,38 @@ int Rtcm::set_DF406(const Gnss_Synchro & gnss_synchro) double phrng_m; double lambda = 0.0; std::string sig_(gnss_synchro.Signal); - std::string sig = sig_.substr(0,2); + sig_ = sig_.substr(0,2); + std::string sys_(&gnss_synchro.System, 1); - if (sig.compare("1C") == 0 ) + if ((sig_.compare("1C") == 0) && (sys_.compare("G") == 0 ) ) { lambda = GPS_C_m_s / GPS_L1_FREQ_HZ; } - if (sig.compare("2S") == 0 ) + if ((sig_.compare("2S") == 0) && (sys_.compare("G") == 0 ) ) { lambda = GPS_C_m_s / GPS_L2_FREQ_HZ; } - if (sig.compare("5X") == 0 ) + if ((sig_.compare("5X") == 0) && (sys_.compare("E") == 0 ) ) { lambda = GPS_C_m_s / Galileo_E5a_FREQ_HZ; } - if (sig.compare("1B") == 0 ) + if ((sig_.compare("1B") == 0) && (sys_.compare("E") == 0 ) ) { lambda = GPS_C_m_s / Galileo_E1_FREQ_HZ; } - if (sig.compare("7X") == 0 ) + if ((sig_.compare("7X") == 0 ) && (sys_.compare("E") == 0 ) ) { lambda = GPS_C_m_s / 1.207140e9; // Galileo_E1b_FREQ_HZ; } - + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0 )) + { + lambda = GLONASS_C_m_s / (GLONASS_L1_CA_FREQ_HZ + (GLONASS_L1_CA_DFREQ_HZ * GLONASS_PRN.at(gnss_synchro.PRN))); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0 )) + { + //TODO Need to add slot number and freq number to gnss syncro + lambda = GLONASS_C_m_s / (GLONASS_L2_FREQ_HZ); + } phrng_m = (gnss_synchro.Carrier_phase_rads / GPS_TWO_PI ) * lambda - rough_range_m; /* Substract phase - pseudorange integer cycle offset */ @@ -4107,24 +5503,33 @@ int Rtcm::set_DF406(const Gnss_Synchro & gnss_synchro) } -int Rtcm::set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro) +int Rtcm::set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro) { unsigned int lock_time_indicator; unsigned int lock_time_period_s = 0; std::string sig_(gnss_synchro.Signal); - if(sig_.compare("1C")) + std::string sys_(&gnss_synchro.System, 1); + if((sig_.compare("1C")) && (sys_.compare("G") == 0 )) { lock_time_period_s = Rtcm::lock_time(ephNAV, obs_time, gnss_synchro); } - if(sig_.compare("2S")) + if((sig_.compare("2S")) && (sys_.compare("G") == 0 )) { lock_time_period_s = Rtcm::lock_time(ephCNAV, obs_time, gnss_synchro); } - if(sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X")) + if((sig_.compare("1B") || sig_.compare("5X") || sig_.compare("7X") || sig_.compare("8X") ) && (sys_.compare("E") == 0 )) { lock_time_period_s = Rtcm::lock_time(ephFNAV, obs_time, gnss_synchro); } + if ((sig_.compare("1C") == 0) && (sys_.compare("R") == 0 )) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } + if ((sig_.compare("2C") == 0) && (sys_.compare("R") == 0 )) + { + lock_time_period_s = Rtcm::lock_time(ephGNAV, obs_time, gnss_synchro); + } lock_time_indicator = Rtcm::msm_extended_lock_time_indicator(lock_time_period_s); DF407 = std::bitset<10>(lock_time_indicator); return 0; diff --git a/src/core/system_parameters/rtcm.h b/src/core/system_parameters/rtcm.h index 8b3333ffe..f19b71add 100644 --- a/src/core/system_parameters/rtcm.h +++ b/src/core/system_parameters/rtcm.h @@ -49,6 +49,7 @@ #include "galileo_fnav_message.h" #include "gps_navigation_message.h" #include "gps_cnav_navigation_message.h" +#include "glonass_gnav_navigation_message.h" /*! @@ -56,7 +57,7 @@ * defined in the RTCM 3.2 Standard, plus some utilities to handle messages. * * Generation of the following Message Types: - * 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1019, 1029, 1045 + * 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1019, 1020, 1029, 1045 * * Decoding of the following Message Types: * 1019, 1045 @@ -128,6 +129,47 @@ public: */ std::string print_MT1008(unsigned int ref_id, const std::string & antenna_descriptor, unsigned int antenna_setup_id, const std::string & antenna_serial_number); + /*! + * \brief Prints L1-Only GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1009(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id); + /*! + * \brief Prints Extended L1-Only GLONASS RTK Observables + * \details This GLONASS message type is used when only L1 data is present and bandwidth is very tight, often 1012 is used in such cases. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1010(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id); + /*! + * \brief Prints L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is not generally used or supported; type 1012 is to be preferred + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1011(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables, unsigned short station_id); + /*! + * \brief Prints Extended L1&L2 GLONASS RTK Observables + * \details This GLONASS message type is the most common observational message type, with L1/L2/SNR content. This is one of the most common messages found. + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \return string with message contents + */ + std::string print_MT1012(const Glonass_Gnav_Ephemeris& glonass_gnav_ephL1, const Glonass_Gnav_Ephemeris& glonass_gnav_ephL2, double obs_time, const std::map & observables, unsigned short station_id); + /*! * \brief Prints message type 1019 (GPS Ephemeris), should be broadcast in the event that * the IODC does not match the IODE, and every 2 minutes. @@ -139,6 +181,25 @@ public: */ int read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph); + /*! + * \brief Prints message type 1020 (GLONASS Ephemeris). + * \note Code added as part of GSoC 2017 program + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param glonass_gnav_utc_model GLONASS GNAV Clock Information + * \return Returns message type as a string type + */ + std::string print_MT1020(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + + /*! + * \brief Verifies and reads messages of type 1020 (GLONASS Ephemeris). + * \note Code added as part of GSoC 2017 program + * \param message Message to read as a string type + * \param glonass_gnav_eph GLONASS GNAV Broadcast Ephemeris + * \param glonass_gnav_utc_model GLONASS GNAV Clock Information + * \return Returns 1 if anything goes wrong, 0 otherwise. + */ + int read_MT1020(const std::string & message, Glonass_Gnav_Ephemeris & glonass_gnav_eph, Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + /*! * \brief Prints message type 1029 (Unicode Text String) */ @@ -160,6 +221,7 @@ public: std::string print_MSM_1( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -175,6 +237,7 @@ public: std::string print_MSM_2( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -190,6 +253,7 @@ public: std::string print_MSM_3( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -205,6 +269,7 @@ public: std::string print_MSM_4( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -220,6 +285,7 @@ public: std::string print_MSM_5( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -235,6 +301,7 @@ public: std::string print_MSM_6( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -250,6 +317,7 @@ public: std::string print_MSM_7( const Gps_Ephemeris & gps_eph, const Gps_CNAV_Ephemeris & gps_cnav_eph, const Galileo_Ephemeris & gal_eph, + const Glonass_Gnav_Ephemeris & glo_gnav_eph, double obs_time, const std::map & observables, unsigned int ref_id, @@ -262,6 +330,15 @@ public: unsigned int lock_time(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); // get_MT1005_test(); + /*! + * \brief Generates contents of message header for types 1009, 1010, 1011 and 1012. GLONASS RTK Message + * \note Code added as part of GSoC 2017 program + * \param msg_number Message type number, acceptable options include 1009 to 1012 + * \param obs_time Time of observation at the moment of printing + * \param observables Set of observables as defined by the platform + * \param ref_id + * \param smooth_int + * \param divergence_free + * \return Returns the message header content as set of bits + */ + std::bitset<61> get_MT1009_12_header(unsigned int msg_number, + double obs_time, + const std::map & observables, + unsigned int ref_id, + unsigned int smooth_int, + bool sync_flag, + bool divergence_free); + + /*! + * \brief Get the contents of the satellite specific portion of a type 1009 Message (GLONASS Basic RTK, L1 Only) + * \details Contents generated for each satellite. See table 3.5-11 + * \note Code added as part of GSoC 2017 program + * \param ephGNAV Ephemeris for GLONASS GNAV in L1 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchro Information generated by channels while processing the satellite + * \return Returns the message content as set of bits + */ + std::bitset<64> get_MT1009_sat_content(const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + /*! + * \brief Get the contents of the satellite specific portion of a type 1010 Message (GLONASS Extended RTK, L1 Only) + * \details Contents generated for each satellite. See table 3.5-12 + * \note Code added as part of GSoC 2017 program + * \param ephGNAV Ephemeris for GLONASS GNAV in L1 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchro Information generated by channels while processing the satellite + * \return Returns the message content as set of bits + */ + std::bitset<79> get_MT1010_sat_content(const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + /*! + * \brief Get the contents of the satellite specific portion of a type 1011 Message (GLONASS Basic RTK, L1 & L2) + * \details Contents generated for each satellite. See table 3.5-13 + * \note Code added as part of GSoC 2017 program + * \param ephGNAVL1 Ephemeris for GLONASS GNAV in L1 satellites + * \param ephGNAVL2 Ephemeris for GLONASS GNAV in L2 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchroL1 Information generated by channels while processing the GLONASS GNAV L1 satellite + * \param gnss_synchroL2 Information generated by channels while processing the GLONASS GNAV L2 satellite + * \return Returns the message content as set of bits + */ + std::bitset<107> get_MT1011_sat_content(const Glonass_Gnav_Ephemeris & ephGNAVL1, const Glonass_Gnav_Ephemeris & ephGNAVL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + /*! + * \brief Get the contents of the satellite specific portion of a type 1012 Message (GLONASS Extended RTK, L1 & L2) + * \details Contents generated for each satellite. See table 3.5-14 + * \note Code added as part of GSoC 2017 program + * \param ephGNAVL1 Ephemeris for GLONASS GNAV in L1 satellites + * \param ephGNAVL2 Ephemeris for GLONASS GNAV in L2 satellites + * \param obs_time Time of observation at the moment of printing + * \param gnss_synchroL1 Information generated by channels while processing the GLONASS GNAV L1 satellite + * \param gnss_synchroL2 Information generated by channels while processing the GLONASS GNAV L2 satellite + * \return Returns the message content as set of bits + */ + std::bitset<130> get_MT1012_sat_content(const Glonass_Gnav_Ephemeris & ephGNAVL1, const Glonass_Gnav_Ephemeris & ephGNAVL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + std::string get_MSM_header(unsigned int msg_number, double obs_time, const std::map & observables, @@ -318,12 +467,12 @@ private: std::string get_MSM_5_content_sat_data(const std::map & observables); std::string get_MSM_1_content_signal_data(const std::map & observables); - std::string get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); - std::string get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const std::map & observables); + std::string get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); + std::string get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); + std::string get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); + std::string get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); + std::string get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); + std::string get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const std::map & observables); // // Utilities @@ -335,10 +484,13 @@ private: boost::posix_time::ptime compute_GPS_time(const Gps_Ephemeris& eph, double obs_time) const; boost::posix_time::ptime compute_GPS_time(const Gps_CNAV_Ephemeris & eph, double obs_time) const; boost::posix_time::ptime compute_Galileo_time(const Galileo_Ephemeris& eph, double obs_time) const; + boost::posix_time::ptime compute_GLONASS_time(const Glonass_Gnav_Ephemeris& eph, double obs_time) const; boost::posix_time::ptime gps_L1_last_lock_time[64]; boost::posix_time::ptime gps_L2_last_lock_time[64]; boost::posix_time::ptime gal_E1_last_lock_time[64]; boost::posix_time::ptime gal_E5_last_lock_time[64]; + boost::posix_time::ptime glo_L1_last_lock_time[64]; + boost::posix_time::ptime glo_L2_last_lock_time[64]; unsigned int lock_time_indicator(unsigned int lock_time_period_s); unsigned int msm_lock_time_indicator(unsigned int lock_time_period_s); unsigned int msm_extended_lock_time_indicator(unsigned int lock_time_period_s); @@ -870,6 +1022,65 @@ private: std::bitset<8> DF032; + /*! + * \brief Sets the Data Field value + * \note Code added as part of GSoC 2017 program + * \param obs_time Time of observation at the moment of printing + * \return returns 0 upon success + */ + int set_DF034(double obs_time); + std::bitset<27> DF034; //!< GLONASS Epoch Time (tk) + + std::bitset<5> DF035; //!< No. of GLONASS Satellite Signals Processed + int set_DF035(const std::map & observables); + + std::bitset<1> DF036; //!< GLONASS Divergence-free Smoothing Indicator + int set_DF036(bool divergence_free_smoothing_indicator); + + std::bitset<3> DF037; //!< GLONASS Smoothing Interval + int set_DF037(short int smoothing_interval); + + std::bitset<6> DF038; //!< GLONASS Satellite ID (Satellite Slot Number) + int set_DF038(const Gnss_Synchro & gnss_synchro); + int set_DF038(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF039; //!< GLONASS L1 Code Indicator + int set_DF039(bool code_indicator); + + std::bitset<5> DF040; //!< GLONASS Satellite Frequency Number + int set_DF040(int frequency_channel_number); + int set_DF040(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<25> DF041; //!< GLONASS L1 Pseudorange + int set_DF041(const Gnss_Synchro & gnss_synchro); + + std::bitset<20> DF042; //!< GLONASS L1 PhaseRange - L1 Pseudorange + int set_DF042(const Gnss_Synchro & gnss_synchro); + + std::bitset<7> DF043; //!< GLONASS L1 Lock Time Indicator + int set_DF043(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); + + std::bitset<7> DF044; //!< GLONASS Integer L1 Pseudorange Modulus Ambiguity + int set_DF044(const Gnss_Synchro & gnss_synchro); + + std::bitset<8> DF045; //!< GLONASS L1 CNR + int set_DF045(const Gnss_Synchro & gnss_synchro); + + std::bitset<2> DF046; //!< GLONASS L2 code indicator + int set_DF046(unsigned short code_indicator); + + std::bitset<14> DF047; //!< GLONASS L2 - L1 Pseudorange Difference + int set_DF047(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + + std::bitset<20> DF048; //!< GLONASS L2 PhaseRange - L1 Pseudorange + int set_DF048(const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2); + + std::bitset<7> DF049; //!< GLONASS L2 Lock Time Indicator + int set_DF049(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro); + + std::bitset<8> DF050; //!< GLONASS L2 CNR + int set_DF050(const Gnss_Synchro & gnss_synchro); + std::bitset<16> DF051; int set_DF051(const Gps_Ephemeris & gps_eph, double obs_time); @@ -964,6 +1175,105 @@ private: std::bitset<1> DF103; int set_DF103(const Gps_Ephemeris & gps_eph); + std::bitset<1> DF104; //!< GLONASS Almanac Health + int set_DF104(unsigned int glonass_gnav_alm_health); + + std::bitset<1> DF105; //!< GLONASS Almanac Health Availability Indicator + int set_DF105(unsigned int glonass_gnav_alm_health_ind); + + std::bitset<2> DF106; //!< GLONASS P1 Word + int set_DF106(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<12> DF107; //!< GLONASS Epoch (tk) + int set_DF107(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF108; //!< GLONASS MSB of Bn Word + int set_DF108(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF109; //!< GLONASS P2 Word + int set_DF109(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<7> DF110; //!< GLONASS Ephmeris Epoch (tb) + int set_DF110(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<24> DF111; //!< GLONASS Xn first derivative + int set_DF111(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<27> DF112; //!< GLONASS Xn + int set_DF112(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<5> DF113; //!< GLONASS Xn second derivative + int set_DF113(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<24> DF114; //!< GLONASS Yn first derivative + int set_DF114(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<27> DF115; //!< GLONASS Yn + int set_DF115(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<5> DF116; //!< GLONASS Yn second derivative + int set_DF116(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<24> DF117; //!< GLONASS Zn first derivative + int set_DF117(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<27> DF118; //!< GLONASS Zn + int set_DF118(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<5> DF119; //!< GLONASS Zn second derivative + int set_DF119(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF120; //!< GLONASS P3 + int set_DF120(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<11> DF121; //!< GLONASS GAMMA_N + int set_DF121(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<2> DF122; //!< GLONASS P + int set_DF122(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF123; //!< GLONASS ln (third string) + int set_DF123(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<22> DF124; //!< GLONASS TAU_N + int set_DF124(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<5> DF125; //!< GLONASS DELTA_TAU_N + int set_DF125(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<5> DF126; //!< GLONASS Eccentricity + int set_DF126(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF127; //!< GLONASS P4 + int set_DF127(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<4> DF128; //!< GLONASS F_T + int set_DF128(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<11> DF129; //!< GLONASS N_T + int set_DF129(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<2> DF130; //!< GLONASS M + int set_DF130(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + + std::bitset<1> DF131; //!< GLONASS Availability of additional data + int set_DF131(unsigned int fifth_str_additional_data_ind); + + std::bitset<11> DF132; //!< GLONASS N_A + int set_DF132(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + + std::bitset<32> DF133; //!< GLONASS TAU_C + int set_DF133(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + + std::bitset<5> DF134; //!< GLONASS N_4 + int set_DF134(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + + std::bitset<22> DF135; //!< GLONASS TAU_GPS + int set_DF135(const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model); + + std::bitset<1> DF136; //!< GLONASS L_N (FIFTH STRING) + int set_DF136(const Glonass_Gnav_Ephemeris & glonass_gnav_eph); + std::bitset<1> DF137; int set_DF137(const Gps_Ephemeris & gps_eph); @@ -1092,7 +1402,7 @@ private: int set_DF401(const Gnss_Synchro & gnss_synchro); std::bitset<4> DF402; - int set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + int set_DF402(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro); std::bitset<6> DF403; int set_DF403(const Gnss_Synchro & gnss_synchro); @@ -1107,7 +1417,7 @@ private: int set_DF406(const Gnss_Synchro & gnss_synchro); std::bitset<10> DF407; - int set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, double obs_time, const Gnss_Synchro & gnss_synchro); + int set_DF407(const Gps_Ephemeris & ephNAV, const Gps_CNAV_Ephemeris & ephCNAV, const Galileo_Ephemeris & ephFNAV, const Glonass_Gnav_Ephemeris & ephGNAV, double obs_time, const Gnss_Synchro & gnss_synchro); std::bitset<10> DF408; int set_DF408(const Gnss_Synchro & gnss_synchro); diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 60b33a4d0..e27506c34 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -59,6 +59,10 @@ #include "sbas_ephemeris.h" +#include "glonass_gnav_ephemeris.h" +#include "glonass_gnav_almanac.h" +#include "glonass_gnav_utc_model.h" + using google::LogMessage; DECLARE_string(log_dir); @@ -139,7 +143,9 @@ DECLARE_string(log_dir); #endif #endif - +#include "unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc" +#include "unit-tests/system-parameters/glonass_gnav_almanac_test.cc" +#include "unit-tests/system-parameters/glonass_gnav_nav_message_test.cc" // For GPS NAVIGATION (L1) concurrent_queue global_gps_acq_assist_queue; 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..839df16dc 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 @@ -253,6 +253,7 @@ TEST(RtcmTest, MT1005) } + TEST(RtcmTest, MT1019) { auto rtcm = std::make_shared(); @@ -276,6 +277,41 @@ TEST(RtcmTest, MT1019) } +TEST(RtcmTest, MT1020) +{ + auto rtcm = std::make_shared(); + bool expected_true = true; + + // Objects to populate the ephemeris and utc fields + Glonass_Gnav_Ephemeris gnav_ephemeris = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model gnav_utc_model = Glonass_Gnav_Utc_Model(); + // Objects read, used for comparison + Glonass_Gnav_Ephemeris gnav_ephemeris_read = Glonass_Gnav_Ephemeris(); + Glonass_Gnav_Utc_Model gnav_utc_model_read = Glonass_Gnav_Utc_Model(); + + // Perform data read and print of special values types + gnav_ephemeris.d_P_1 = 15; + // Bit distribution per fields + gnav_ephemeris.d_t_k = 7560; + // Glonass signed values + gnav_ephemeris.d_VXn = -0.490900039672852; + // Bit distribution per fields dependant on other factors + gnav_ephemeris.d_t_b = 8100; + // Binary flag representation + gnav_ephemeris.d_P_3 = 1; + + std::string tx_msg = rtcm->print_MT1020(gnav_ephemeris, gnav_utc_model); + + EXPECT_EQ(0, rtcm->read_MT1020(tx_msg, gnav_ephemeris_read, gnav_utc_model_read)); + EXPECT_EQ(gnav_ephemeris.d_P_1, gnav_ephemeris_read.d_P_1); + EXPECT_TRUE(gnav_ephemeris.d_t_b - gnav_ephemeris_read.d_t_b < FLT_EPSILON); + EXPECT_TRUE( gnav_ephemeris.d_VXn - gnav_ephemeris_read.d_VXn < FLT_EPSILON); + EXPECT_TRUE( gnav_ephemeris.d_t_k - gnav_ephemeris.d_t_k < FLT_EPSILON); + EXPECT_EQ(gnav_ephemeris.d_P_3, gnav_ephemeris_read.d_P_3); + EXPECT_EQ(1, rtcm->read_MT1020(rtcm->bin_to_binary_data(rtcm->hex_to_bin("FFFFFFFFFFF")), gnav_ephemeris_read, gnav_utc_model_read)); +} + + TEST(RtcmTest, MT1029) { auto rtcm = std::make_shared(); @@ -321,6 +357,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 +365,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 +387,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((void*)gnss_synchro.Signal, x5.c_str(), 3); + std::memcpy((void*)gnss_synchro2.Signal, s2.c_str(), 3); + std::memcpy((void*)gnss_synchro3.Signal, c1.c_str(), 3); + std::memcpy((void*)gnss_synchro4.Signal, x5.c_str(), 3); + std::memcpy((void*)gnss_synchro5.Signal, c1.c_str(), 3); + std::memcpy((void*)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 +420,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, + {}, obs_time, pseudoranges, ref_id, @@ -397,14 +443,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, + {}, obs_time, pseudoranges2, ref_id, @@ -416,22 +465,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((void*)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 +548,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 +595,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, diff --git a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc index c75139ff6..633e63c81 100644 --- a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc @@ -1,6 +1,6 @@ /*! * \file gps_l1_ca_dll_pll_tracking_test.cc - * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * \brief This class implements a telemetry decoder test for GPS_L1_CA_Telemetry_Decoder * implementation based on some input parameters. * \author Javier Arribas, 2015. jarribas(at)cttc.es * @@ -477,4 +477,3 @@ TEST_F(GpsL1CATelemetryDecoderTest, ValidationOfResults) std::cout << "Test completed in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; } - diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_almanac_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_almanac_test.cc new file mode 100644 index 000000000..2c36f03cb --- /dev/null +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_almanac_test.cc @@ -0,0 +1,76 @@ +/*! + * \file code_generation_test.cc + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include "gps_sdr_signal_processing.h" +#include "gnss_signal_processing.h" + +#include +#include +#include "gnss_signal_processing.h" +#include "glonass_gnav_almanac.h" + +// See A 3.2.3 +TEST(GlonassGnavAlmanacTest, SatellitePosition) +{ + double N_i = 615; // [days] + double t_i = 33300.0; // [seconds] + double Xoi = 10947.021572; // [km] + double Yoi = 13078.978287; // [km] + double Zoi = 18922.063362; // [km] + double Vxoi = -3.375497; // [m/s] + double Vyoi = -0.161453; // [Кm/s] + double Vzoi = 2.060844; // [Кm/s] + double N_A = 615; // [days] + + Glonass_Gnav_Almanac gnav_almanac; + + + gnav_almanac.d_lambda_n_A = -0.189986229; // [half cycles] + gnav_almanac.d_t_lambda_n_A = 27122.09375; // [second] + gnav_almanac.d_Delta_i_n_A = 0.011929512; // [half cycle] + gnav_almanac.d_Delta_T_n_A = -2655.76171875; // [seconds] + gnav_almanac.d_Delta_T_n_A_dot = 0.000549316; // [Secjnds/cycle2] + gnav_almanac.d_epsilon_n_A = 0.001482010; // [unitless] + gnav_almanac.d_omega_n_A = 0.440277100; // [Half cycle] + + gnav_almanac.satellite_position(N_A, N_i, t_i); + + ASSERT_TRUE(gnav_almanac.d_satpos_Xo - Xoi < DBL_EPSILON ); + ASSERT_TRUE(gnav_almanac.d_satpos_Yo - Yoi < DBL_EPSILON ); + ASSERT_TRUE(gnav_almanac.d_satpos_Zo - Zoi < DBL_EPSILON ); + ASSERT_TRUE(gnav_almanac.d_satvel_Xo - Vxoi < DBL_EPSILON ); + ASSERT_TRUE(gnav_almanac.d_satvel_Yo - Vyoi < DBL_EPSILON ); + ASSERT_TRUE(gnav_almanac.d_satvel_Zo - Vzoi < DBL_EPSILON ); +} diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc new file mode 100644 index 000000000..b87cba16a --- /dev/null +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc @@ -0,0 +1,65 @@ +/*! + * \file code_generation_test.cc + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include "gnss_signal_processing.h" +#include "glonass_gnav_ephemeris.h" + + +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; + + 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(); + + // 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 ); +} diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc new file mode 100644 index 000000000..de814391f --- /dev/null +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc @@ -0,0 +1,243 @@ +/*! + * \file glonass_gnav_navigation_message_test.cc + * \brief This file implements tests for the decoding of the GLONASS GNAV navigation message + * \note Code added as part of GSoC 2017 program + * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com + * \see GLONASS ICD + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include +#include "gnss_signal_processing.h" +#include "glonass_gnav_navigation_message.h" + +/*! + * \brief Testing CRC computation for GLONASS GNAV data bits of a string + * \test The provided string was generated with a version of MATLAB GNSS-SDR that + * the author coded to perform proper decoding of GLONASS GNAV signals. + */ +TEST(GlonassGnavNavigationMessageTest, CRCTest) +{ + // Variables declarations in code + bool test_result; + std::bitset string_bits (std::string ("0010100100001100000000000000000000000000110011110001100000000000000001100100011000000")); + Glonass_Gnav_Navigation_Message gnav_nav_message; + gnav_nav_message.reset(); + + // Call function to test + test_result = gnav_nav_message.CRC_test(string_bits); + + // Check results in unit test assetions + ASSERT_TRUE(test_result); +} + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String1Decoder) +{ + // Variable declarations + std::string str1("0000100000001000011001000011111011010101110100000010101011000100011010101011000101111"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_P_1 = 15; + gnav_ephemeris.d_t_k = 7560; + gnav_ephemeris.d_VXn = -0.490900039672852; + gnav_ephemeris.d_AXn = 0; + gnav_ephemeris.d_Xn = -11025.6669921875; + + // Call target test method + gnav_nav_message.string_decoder(str1); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_P_1 - gnav_nav_message.gnav_ephemeris.d_P_1 < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_t_k - gnav_nav_message.gnav_ephemeris.d_t_k < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_VXn - gnav_nav_message.gnav_ephemeris.d_VXn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_AXn - gnav_nav_message.gnav_ephemeris.d_AXn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_Xn - gnav_nav_message.gnav_ephemeris.d_Xn < FLT_EPSILON ); +} + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String2Decoder) +{ + // Variable declarations + std::string str2("0001000010001001000001010101100001011001011000000010101100110000001011110000110011110"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_B_n = 0; + gnav_ephemeris.d_P_2 = 1; + gnav_ephemeris.d_t_b = 8100; + gnav_ephemeris.d_VYn = -2.69022750854492; + gnav_ephemeris.d_AYn = 0; + gnav_ephemeris.d_Yn = -11456.7348632812; + + // Call target test method + gnav_nav_message.flag_ephemeris_str_1 = true; + gnav_nav_message.gnav_ephemeris.d_P_1 = 15; + gnav_nav_message.string_decoder(str2); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_B_n - gnav_nav_message.gnav_ephemeris.d_B_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_P_2 - gnav_nav_message.gnav_ephemeris.d_P_2 < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_t_b - gnav_nav_message.gnav_ephemeris.d_t_b < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_VYn - gnav_nav_message.gnav_ephemeris.d_VYn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_AYn - gnav_nav_message.gnav_ephemeris.d_AYn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_Yn - gnav_nav_message.gnav_ephemeris.d_Yn < FLT_EPSILON ); +} + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String3Decoder) +{ + // Variable declarations + std::string str3("0001110000000001001101001110100011111011010011001101001101110110010011110011100100011"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_P_3 = 1; + gnav_ephemeris.d_gamma_n = 1.81898940354586e-12; + gnav_ephemeris.d_P = 3; + gnav_ephemeris.d_l3rd_n = 0; + gnav_ephemeris.d_VZn = -1.82016849517822; + gnav_ephemeris.d_AZn = -2.79396772384644e-09; + gnav_ephemeris.d_Zn = 19929.2377929688; + + // Call target test method + gnav_nav_message.string_decoder(str3); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_P_3 - gnav_nav_message.gnav_ephemeris.d_P_3 < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_gamma_n - gnav_nav_message.gnav_ephemeris.d_gamma_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_P - gnav_nav_message.gnav_ephemeris.d_P < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_l3rd_n - gnav_nav_message.gnav_ephemeris.d_l3rd_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_VZn - gnav_nav_message.gnav_ephemeris.d_VZn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_AZn - gnav_nav_message.gnav_ephemeris.d_AZn < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_Zn - gnav_nav_message.gnav_ephemeris.d_Zn < FLT_EPSILON ); +} + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String4Decoder) +{ + // Variable declarations + std::string str4("0010010000101011100100000100000100000000000000000000011000100100001100101010100011101"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Ephemeris gnav_ephemeris; + + // Fill out ephemeris values for truth + gnav_ephemeris.d_tau_n = -8.30907374620438e-05; + gnav_ephemeris.d_Delta_tau_n = 9.31322574615479e-10; + gnav_ephemeris.d_E_n = 0; + gnav_ephemeris.d_P_4 = 0; + gnav_ephemeris.d_F_T = 6; + gnav_ephemeris.d_N_T = 268; + gnav_ephemeris.d_n = 21; + gnav_ephemeris.d_M = 1; + + // Call target test method + gnav_nav_message.string_decoder(str4); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_ephemeris.d_tau_n - gnav_nav_message.gnav_ephemeris.d_tau_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_Delta_tau_n - gnav_nav_message.gnav_ephemeris.d_Delta_tau_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_E_n - gnav_nav_message.gnav_ephemeris.d_E_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_P_4 - gnav_nav_message.gnav_ephemeris.d_P_4 < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_F_T - gnav_nav_message.gnav_ephemeris.d_F_T < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_N_T - gnav_nav_message.gnav_ephemeris.d_N_T < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_n - gnav_nav_message.gnav_ephemeris.d_n < FLT_EPSILON ); + ASSERT_TRUE(gnav_ephemeris.d_M - gnav_nav_message.gnav_ephemeris.d_M < FLT_EPSILON ); +} + +/*! + * \brief Testing string decoding for GLONASS GNAV messages + * \test The provided string (str1.....str15) was generated with a version of + * MATLAB GNSS-SDR that the author coded to perform proper decoding of GLONASS + * GNAV signals. The same assumption is to be applied for ephemeris and almanac + * data provided. + */ +TEST(GlonassGnavNavigationMessageTest, String5Decoder) +{ + // Variable declarations + std::string str5("0010100100001100000000000000000000000000110011110001100000000000000001100100011000000"); + Glonass_Gnav_Navigation_Message gnav_nav_message; + Glonass_Gnav_Utc_Model gnav_utc_model; + + // Fill out ephemeris values for truth + gnav_utc_model.d_N_A = 268; + gnav_utc_model.d_tau_c = 9.6391886472702e-08; + gnav_utc_model.d_N_4 = 6; + gnav_utc_model.d_tau_gps = 9.313225746154785e-08; + + // Call target test method + gnav_nav_message.string_decoder(str5); + + // Perform assertions of decoded fields + ASSERT_TRUE(gnav_utc_model.d_N_A - gnav_nav_message.gnav_utc_model.d_N_A < FLT_EPSILON ); + ASSERT_TRUE(gnav_utc_model.d_tau_c - gnav_nav_message.gnav_utc_model.d_tau_c < FLT_EPSILON ); + ASSERT_TRUE(gnav_utc_model.d_N_4 - gnav_nav_message.gnav_utc_model.d_N_4 < FLT_EPSILON ); + ASSERT_TRUE(gnav_utc_model.d_tau_gps - gnav_nav_message.gnav_utc_model.d_tau_gps < FLT_EPSILON ); +} + +std::string str6("0011010100110100001100111100011100001101011000000110101111001000000101100011111011001"); +std::string str7("0011101101010001000010000110101111110000101101001011111110101110100010111100010001101"); +std::string str8("0100010100111000000001111110001101000000110000001000100111011100001010101111010011010"); +std::string str9("0100111010001001011100010000010100010101111101001011111110101011100010100101000110101"); +std::string str10("0101010101000000000011101111111101111001011000001000101010001100001111000110101111110"); +std::string str11("0101110111011011011100011001111011101111001101001011111111000110100100000110010001111"); +std::string str12("0110010101001100000011110110100110100100010100001000111110000100001110001010111000001"); +std::string str13("0110111011100100111110100001000110100010011101001011111110100100101010011010001101001"); +std::string str14("0111010101010000000100011000011110100110111100001110110100001000001111001101010000101"); +std::string str15("0111101110101010001110101010100111101100001101001011111111100010101010011001010011101"); diff --git a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m index 7e543b180..19bc3de13 100644 --- a/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m +++ b/src/utils/matlab/galileo_e1_dll_pll_veml_plot_sample.m @@ -68,6 +68,7 @@ for N=1:1:channels trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).L)); trackResults(N).Q_VL = zeros(1,length(GNSS_tracking(N).VL)); trackResults(N).PRN = GNSS_tracking(N).PRN.'; + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; % Use original MATLAB tracking plot function settings.numberOfChannels = channels; diff --git a/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m b/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m new file mode 100644 index 000000000..7cb6753b4 --- /dev/null +++ b/src/utils/matlab/glonass_ca_dll_pll_plot_sample.m @@ -0,0 +1,74 @@ +% /*! +% * \file glonass_ca_dll_pll_plot_sample.m +% * \brief Read GNSS-SDR Tracking dump binary file using the provided +% function and plot some internal variables +% * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com +% * ------------------------------------------------------------------------- +% * +% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) +% * +% * GNSS-SDR is a software defined Global Navigation +% * Satellite Systems receiver +% * +% * This file is part of GNSS-SDR. +% * +% * GNSS-SDR is free software: you can redistribute it and/or modify +% * it under the terms of the GNU General Public License as published by +% * the Free Software Foundation, either version 3 of the License, or +% * at your option) any later version. +% * +% * GNSS-SDR is distributed in the hope that it will be useful, +% * but WITHOUT ANY WARRANTY; without even the implied warranty of +% * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% * GNU General Public License for more details. +% * +% * You should have received a copy of the GNU General Public License +% * along with GNSS-SDR. If not, see . +% * +% * ------------------------------------------------------------------------- +% */ +close all; +clear all; + +if ~exist('glonass_ca_dll_pll_read_tracking_dump.m','file') + addpath('./libs') +end + + +samplingFreq = 6625000; %[Hz] +channels = 5; +first_channel = 0; + +path = '/archive/'; %% CHANGE THIS PATH + +for N=1:1:channels + tracking_log_path = [path 'glo_tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE epl_tracking_ch_ BY YOUR dump_filename + GNSS_tracking(N)= glonass_ca_dll_pll_read_tracking_dump(tracking_log_path); +end + +% GNSS-SDR format conversion to MATLAB GPS receiver + +for N=1:1:channels + trackResults(N).status = 'T'; %fake track + trackResults(N).codeFreq = GNSS_tracking(N).code_freq_hz.'; + trackResults(N).carrFreq = GNSS_tracking(N).carrier_freq_hz.'; + trackResults(N).dllDiscr = GNSS_tracking(N).code_error.'; + trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.'; + trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.'; + trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.'; + + trackResults(N).I_P = GNSS_tracking(N).prompt_I.'; + trackResults(N).Q_P = GNSS_tracking(N).prompt_Q.'; + + trackResults(N).I_E = GNSS_tracking(N).E.'; + trackResults(N).I_L = GNSS_tracking(N).L.'; + trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; + trackResults(N).PRN = ones(1,length(GNSS_tracking(N).E)); + + % Use original MATLAB tracking plot function + settings.numberOfChannels = channels; + settings.msToProcess = length(GNSS_tracking(N).E); + plotTracking(N,trackResults,settings); +end diff --git a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m b/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m index c1c884eaa..22ef63f79 100644 --- a/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m +++ b/src/utils/matlab/gps_l1_ca_dll_pll_plot_sample.m @@ -35,14 +35,14 @@ if ~exist('gps_l1_ca_dll_pll_read_tracking_dump.m','file') end -samplingFreq = 2600000; %[Hz] -channels = 2; +samplingFreq = 6625000; %[Hz] +channels = 5; first_channel = 0; -path = '/home/javier/git/gnss-sdr/build/'; %% CHANGE THIS PATH +path = '/archive/'; %% CHANGE THIS PATH for N=1:1:channels - tracking_log_path = [path 'tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE epl_tracking_ch_ BY YOUR dump_filename + tracking_log_path = [path 'glo_tracking_ch_' num2str(N+first_channel-1) '.dat']; %% CHANGE epl_tracking_ch_ BY YOUR dump_filename GNSS_tracking(N)= gps_l1_ca_dll_pll_read_tracking_dump(tracking_log_path); end @@ -65,6 +65,7 @@ for N=1:1:channels trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E)); trackResults(N).Q_L = zeros(1,length(GNSS_tracking(N).E)); trackResults(N).PRN = ones(1,length(GNSS_tracking(N).E)); + trackResults(N).CNo = GNSS_tracking(N).CN0_SNV_dB_Hz.'; % Use original MATLAB tracking plot function settings.numberOfChannels = channels; diff --git a/src/utils/matlab/libs/glonass_ca_dll_pll_read_tracking_dump.m b/src/utils/matlab/libs/glonass_ca_dll_pll_read_tracking_dump.m new file mode 100644 index 000000000..7141d1970 --- /dev/null +++ b/src/utils/matlab/libs/glonass_ca_dll_pll_read_tracking_dump.m @@ -0,0 +1,191 @@ +% /*! +% * \file glonass_ca_dll_pll_read_tracking_dump.m +% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. +% * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com +% * ------------------------------------------------------------------------- +% * +% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) +% * +% * GNSS-SDR is a software defined Global Navigation +% * Satellite Systems receiver +% * +% * This file is part of GNSS-SDR. +% * +% * GNSS-SDR is free software: you can redistribute it and/or modify +% * it under the terms of the GNU General Public License as published by +% * the Free Software Foundation, either version 3 of the License, or +% * at your option) any later version. +% * +% * GNSS-SDR is distributed in the hope that it will be useful, +% * but WITHOUT ANY WARRANTY; without even the implied warranty of +% * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% * GNU General Public License for more details. +% * +% * You should have received a copy of the GNU General Public License +% * along with GNSS-SDR. If not, see . +% * +% * ------------------------------------------------------------------------- +% */ +function [GNSS_tracking] = glonass_ca_dll_pll_read_tracking_dump (filename, count) + + %% usage: gps_l1_ca_dll_pll_read_tracking_dump_64bits (filename, [count]) + %% + %% open GNSS-SDR tracking binary log file .dat and return the contents + %% + + narginchk (1,2); + num_float_vars=5; + num_unsigned_long_int_vars=1; + num_double_vars=11; + num_unsigned_int_vars=1; + double_size_bytes=8; + unsigned_long_int_size_bytes=8; + float_size_bytes=4; + long_int_size_bytes=4; + + skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars+long_int_size_bytes*num_unsigned_int_vars; + bytes_shift=0; + + if (nargin < 2) + %count = Inf; + file_stats = dir(filename); + %round num bytes to read to integer number of samples (to protect the script from binary + %dump end file transitory) + count = (file_stats.bytes - mod(file_stats.bytes,skip_bytes_each_read))/skip_bytes_each_read; + end + %loops_counter = fread (f, count, 'uint32',4*12); + f = fopen (filename, 'rb'); + if (f < 0) + else + v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved unsigned_long_int + v6 = fread (f, count, 'uint64',skip_bytes_each_read-unsigned_long_int_size_bytes); + bytes_shift=bytes_shift+unsigned_long_int_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v7 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v8 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v9 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v10 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v11 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v12 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v13 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v14 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v15 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v16 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v17 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v18 = fread (f, count, 'uint32',skip_bytes_each_read-double_size_bytes); + fclose (f); + + %%%%%%%% output vars %%%%%%%% + +% // EPR +% d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); +% // PROMPT I and Q (to analyze navigation symbols) +% d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); +% // PRN start sample stamp +% //tmp_float=(float)d_sample_counter; +% d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); +% // accumulated carrier phase +% d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); +% +% // carrier and code frequency +% d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); +% +% //PLL commands +% d_dump_file.write(reinterpret_cast(&carr_phase_error_secs_Ti), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); +% +% //DLL commands +% d_dump_file.write(reinterpret_cast(&code_error_chips_Ti), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); +% +% // CN0 and carrier lock test +% d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); +% +% // AUX vars (for debug purposes) +% tmp_double = d_rem_code_phase_samples; +% d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); +% tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); +% d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); +% // PRN +% unsigned int prn_ = d_acquisition_gnss_synchro->PRN; +% d_dump_file.write(reinterpret_cast(&prn_), sizeof(unsigned int)); + E=v1; + P=v2; + L=v3; + prompt_I=v4; + prompt_Q=v5; + PRN_start_sample=v6; + acc_carrier_phase_rad=v7; + carrier_freq_hz=v8; + code_freq_hz=v9; + carr_error=v10; + carr_nco=v11; + code_error=v12; + code_nco=v13; + CN0_SNV_dB_Hz=v14; + carrier_lock_test=v15; + var1=v16; + var2=v17; + PRN=v18; + + GNSS_tracking.E=E; + GNSS_tracking.P=P; + GNSS_tracking.L=L; + GNSS_tracking.prompt_I=prompt_I; + GNSS_tracking.prompt_Q=prompt_Q; + GNSS_tracking.PRN_start_sample=PRN_start_sample; + GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; + GNSS_tracking.carrier_freq_hz=carrier_freq_hz; + GNSS_tracking.code_freq_hz=code_freq_hz; + GNSS_tracking.carr_error=carr_error; + GNSS_tracking.carr_nco=carr_nco; + GNSS_tracking.code_error=code_error; + GNSS_tracking.code_nco=code_nco; + GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; + GNSS_tracking.carrier_lock_test=carrier_lock_test; + GNSS_tracking.d_rem_code_phase_samples=var1; + GNSS_tracking.var2=var2; + GNSS_tracking.PRN=PRN; + end + diff --git a/src/utils/matlab/libs/glonass_l1_ca_dll_pll_read_tracking_dump.m b/src/utils/matlab/libs/glonass_l1_ca_dll_pll_read_tracking_dump.m new file mode 100644 index 000000000..8b1e54243 --- /dev/null +++ b/src/utils/matlab/libs/glonass_l1_ca_dll_pll_read_tracking_dump.m @@ -0,0 +1,193 @@ +% /*! +% * \file glonass_l1_ca_dll_pll_read_tracking_dump.m +% * \brief Read GNSS-SDR Tracking dump binary file into MATLAB. +% * \author Damian Miralles, 2017. dmiralles2009(at)gmail.com +% * ------------------------------------------------------------------------- +% * +% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors) +% * +% * GNSS-SDR is a software defined Global Navigation +% * Satellite Systems receiver +% * +% * This file is part of GNSS-SDR. +% * +% * GNSS-SDR is free software: you can redistribute it and/or modify +% * it under the terms of the GNU General Public License as published by +% * the Free Software Foundation, either version 3 of the License, or +% * at your option) any later version. +% * +% * GNSS-SDR is distributed in the hope that it will be useful, +% * but WITHOUT ANY WARRANTY; without even the implied warranty of +% * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% * GNU General Public License for more details. +% * +% * You should have received a copy of the GNU General Public License +% * along with GNSS-SDR. If not, see . +% * +% * ------------------------------------------------------------------------- +% */ +function [GNSS_tracking] = glonass_l1_ca_dll_pll_read_tracking_dump (filename, count) + + %% usage: glonass_l1_ca_dll_pll_read_tracking_dump_64bits (filename, [count]) + %% + %% open GNSS-SDR tracking binary log file .dat and return the contents + %% + + m = nargchk (1,2,nargin); + num_float_vars=5; + num_unsigned_long_int_vars=1; + num_double_vars=11; + num_unsigned_int_vars=1; + double_size_bytes=8; + unsigned_long_int_size_bytes=8; + float_size_bytes=4; + long_int_size_bytes=4; + + skip_bytes_each_read=float_size_bytes*num_float_vars+unsigned_long_int_size_bytes*num_unsigned_long_int_vars+double_size_bytes*num_double_vars+long_int_size_bytes*num_unsigned_int_vars; + bytes_shift=0; + if (m) + usage (m); + end + + if (nargin < 2) + %count = Inf; + file_stats = dir(filename); + %round num bytes to read to integer number of samples (to protect the script from binary + %dump end file transitory) + count = (file_stats.bytes - mod(file_stats.bytes,skip_bytes_each_read))/skip_bytes_each_read; + end + %loops_counter = fread (f, count, 'uint32',4*12); + f = fopen (filename, 'rb'); + if (f < 0) + else + v1 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v2 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v3 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v4 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved float + v5 = fread (f, count, 'float',skip_bytes_each_read-float_size_bytes); + bytes_shift=bytes_shift+float_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved unsigned_long_int + v6 = fread (f, count, 'uint64',skip_bytes_each_read-unsigned_long_int_size_bytes); + bytes_shift=bytes_shift+unsigned_long_int_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v7 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v8 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v9 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v10 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v11 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v12 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v13 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v14 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v15 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v16 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v17 = fread (f, count, 'float64',skip_bytes_each_read-double_size_bytes); + bytes_shift=bytes_shift+double_size_bytes; + fseek(f,bytes_shift,'bof'); % move to next interleaved double + v18 = fread (f, count, 'uint32',skip_bytes_each_read-double_size_bytes); + fclose (f); + + %%%%%%%% output vars %%%%%%%% + +% // EPR +% d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); +% // PROMPT I and Q (to analyze navigation symbols) +% d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); +% d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); +% // PRN start sample stamp +% //tmp_float=(float)d_sample_counter; +% d_dump_file.write(reinterpret_cast(&d_sample_counter), sizeof(unsigned long int)); +% // accumulated carrier phase +% d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); +% +% // carrier and code frequency +% d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); +% +% //PLL commands +% d_dump_file.write(reinterpret_cast(&carr_phase_error_secs_Ti), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); +% +% //DLL commands +% d_dump_file.write(reinterpret_cast(&code_error_chips_Ti), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); +% +% // CN0 and carrier lock test +% d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); +% d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); +% +% // AUX vars (for debug purposes) +% tmp_double = d_rem_code_phase_samples; +% d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); +% tmp_double = static_cast(d_sample_counter + d_current_prn_length_samples); +% d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); +% // PRN +% unsigned int prn_ = d_acquisition_gnss_synchro->PRN; +% d_dump_file.write(reinterpret_cast(&prn_), sizeof(unsigned int)); + E=v1; + P=v2; + L=v3; + prompt_I=v4; + prompt_Q=v5; + PRN_start_sample=v6; + acc_carrier_phase_rad=v7; + carrier_doppler_hz=v8; + code_freq_hz=v9; + carr_error=v10; + carr_nco=v11; + code_error=v12; + code_nco=v13; + CN0_SNV_dB_Hz=v14; + carrier_lock_test=v15; + var1=v16; + var2=v17; + PRN=v18; + + GNSS_tracking.E=E; + GNSS_tracking.P=P; + GNSS_tracking.L=L; + GNSS_tracking.prompt_I=prompt_I; + GNSS_tracking.prompt_Q=prompt_Q; + GNSS_tracking.PRN_start_sample=PRN_start_sample; + GNSS_tracking.acc_carrier_phase_rad=acc_carrier_phase_rad; + GNSS_tracking.carrier_doppler_hz=carrier_doppler_hz; + GNSS_tracking.code_freq_hz=code_freq_hz; + GNSS_tracking.carr_error=carr_error; + GNSS_tracking.carr_nco=carr_nco; + GNSS_tracking.code_error=code_error + GNSS_tracking.code_nco=code_nco; + GNSS_tracking.CN0_SNV_dB_Hz=CN0_SNV_dB_Hz; + GNSS_tracking.carrier_lock_test=carrier_lock_test; + GNSS_tracking.d_rem_code_phase_samples=var1; + GNSS_tracking.var2=var2; + GNSS_tracking.PRN=PRN; + end diff --git a/src/utils/matlab/libs/plotTracking.m b/src/utils/matlab/libs/plotTracking.m index d2e31f537..ec0c418d3 100644 --- a/src/utils/matlab/libs/plotTracking.m +++ b/src/utils/matlab/libs/plotTracking.m @@ -54,15 +54,20 @@ for channelNr = channelList %% Draw axes ============================================================== % Row 1 - handles(1, 1) = subplot(3, 3, 1); - handles(1, 2) = subplot(3, 3, [2 3]); + handles(1, 1) = subplot(4, 3, 1); + handles(1, 2) = subplot(4, 3, [2 3]); % Row 2 - handles(2, 1) = subplot(3, 3, 4); - handles(2, 2) = subplot(3, 3, [5 6]); + handles(2, 1) = subplot(4, 3, 4); + handles(2, 2) = subplot(4, 3, [5 6]); % Row 3 - handles(3, 1) = subplot(3, 3, 7); - handles(3, 2) = subplot(3, 3, 8); - handles(3, 3) = subplot(3, 3, 9); + handles(3, 1) = subplot(4, 3, 7); + handles(3, 2) = subplot(4, 3, 8); + handles(3, 3) = subplot(4, 3, 9); + % Row 4 + handles(4, 1) = subplot(4, 3, 10); + handles(4, 2) = subplot(4, 3, 11); + handles(4, 3) = subplot(4, 3, 12); + %% Plot all figures ======================================================= @@ -149,5 +154,35 @@ for channelNr = channelList xlabel(handles(3, 3), 'Time (s)'); ylabel(handles(3, 3), 'Amplitude'); title (handles(3, 3), 'Filtered DLL discriminator'); + + %----- CNo for signal---------------------------------- + plot (handles(4, 1), timeAxisInSeconds, ... + trackResults(channelNr).CNo(1:settings.msToProcess), 'b'); + + grid (handles(4, 1)); + axis (handles(4, 1), 'tight'); + xlabel(handles(4, 1), 'Time (s)'); + ylabel(handles(4, 1), 'CNo (dB-Hz)'); + title (handles(4, 1), 'Carrier to Noise Ratio'); + + %----- Carrier Frequency -------------------------------- + plot (handles(4, 2), timeAxisInSeconds, ... + trackResults(channelNr).carrFreq(1:settings.msToProcess), 'Color',[0.42 0.25 0.39]); + + grid (handles(4, 2)); + axis (handles(4, 2), 'tight'); + xlabel(handles(4, 2), 'Time (s)'); + ylabel(handles(4, 2), 'Freq (hz)'); + title (handles(4, 2), 'Carrier Freq'); + + %----- Code Frequency---------------------------------- + plot (handles(4, 3), timeAxisInSeconds, ... + trackResults(channelNr).codeFreq(1:settings.msToProcess), 'Color',[0.2 0.3 0.49]); + + grid (handles(4, 3)); + axis (handles(4, 3), 'tight'); + xlabel(handles(4, 3), 'Time (s)'); + ylabel(handles(4, 3), 'Freq (Hz)'); + title (handles(4, 3), 'Code Freq'); end % for channelNr = channelList