Fix Glonass carrier phase and time annotations in RINEX files

This commit is contained in:
Carles Fernandez
2026-06-11 07:22:02 +02:00
parent 6584ed5d17
commit 7bd6622e2c
13 changed files with 201 additions and 121 deletions
+56 -14
View File
@@ -1422,7 +1422,8 @@ std::string get_beidou_time_corr_line(const Beidou_Dnav_Utc_Model& utc_model)
std::string get_glonass_time_corr_line(const Glonass_Gnav_Utc_Model& utc_model)
{
return get_time_corr_line("GLUT", utc_model.d_tau_c, 0.0, nullptr, nullptr);
// The GLUT correction is defined as -TauC (see RINEX specification, Table A5)
return get_time_corr_line("GLUT", -utc_model.d_tau_c, 0.0, nullptr, nullptr);
}
@@ -1452,7 +1453,7 @@ std::string get_glonass_time_corr_line_v2(const Glonass_Gnav_Utc_Model& utc_mode
line += rightJustify(month, 6);
line += rightJustify(day, 6);
line += std::string(3, ' ');
line += rightJustify(doub2for(utc_model.d_tau_c, 19, 2), 19);
line += rightJustify(doub2for(-utc_model.d_tau_c, 19, 2), 19);
line += std::string(20, ' ');
line += leftJustify("CORR TO SYSTEM TIME", 20);
lengthCheck(line);
@@ -1953,15 +1954,42 @@ void add_obs_sys_obs_type_v2(std::fstream& out,
void add_obs_glonass_slot_freq(std::fstream& out)
{
// TODO Need to provide system with list of all satellites and update this accordingly
// List of slot / frequency channel pairs known to the receiver, taken from
// the GLONASS_PRN table (slot 0 is reserved for test purposes)
std::vector<std::pair<uint32_t, int32_t>> slots;
for (const auto& slot_freq : GLONASS_PRN)
{
if (slot_freq.first != 0)
{
slots.emplace_back(slot_freq);
}
}
std::string line;
line += rightJustify(std::to_string(0), 3); // Number of satellites in list
line += std::string(1, ' ');
line += satelliteSystem.at("GLONASS");
line += rightJustify(std::to_string(0), 2); // Slot Number
line += std::string(1, ' ');
line += rightJustify(std::to_string(0), 2); // Frequency Number
line += std::string(1, ' ');
line += rightJustify(std::to_string(slots.size()), 3); // Number of satellites in list
size_t sats_in_line = 0;
for (const auto& slot_freq : slots)
{
if (sats_in_line == 8)
{
// Continuation lines hold up to eight satellites each
line += std::string(60 - line.size(), ' ');
line += leftJustify("GLONASS SLOT / FRQ #", 20);
lengthCheck(line);
out << line << '\n';
line = std::string(3, ' ');
sats_in_line = 0;
}
line += std::string(1, ' ');
line += satelliteSystem.at("GLONASS");
if (slot_freq.first < 10)
{
line += std::string("0");
}
line += std::to_string(slot_freq.first); // Slot Number
line += rightJustify(std::to_string(slot_freq.second), 3); // Frequency Number
sats_in_line++;
}
line += std::string(60 - line.size(), ' ');
line += leftJustify("GLONASS SLOT / FRQ #", 20);
lengthCheck(line);
@@ -2813,7 +2841,7 @@ void Rinex_Printer::log_rinex_nav_glo_gnav(const std::map<int32_t, Glonass_Gnav_
line += std::string(1, ' ');
line += get_datetime_v2(p_utc_time);
line += std::string(1, ' ');
line += doub2for(-eph.d_tau_c, 18, 2);
line += doub2for(-eph.d_tau_n, 18, 2);
line += std::string(1, ' ');
line += doub2for(eph.d_gamma_n, 18, 2);
line += std::string(1, ' ');
@@ -2824,7 +2852,11 @@ void Rinex_Printer::log_rinex_nav_glo_gnav(const std::map<int32_t, Glonass_Gnav_
}
if (d_version == 3)
{
out << get_nav_sv_epoch_svclk_line(p_utc_time, sys_char, eph.PRN, -eph.d_tau_n, +eph.d_gamma_n, eph.d_t_k + p_utc_time.date().day_of_week() * 86400) << '\n';
// Message frame time in seconds of the UTC week (tk is given in
// seconds of the GLONASS day, which is offset 3 h from UTC)
const boost::posix_time::ptime p_frame_time_utc = eph.glot_to_utc(eph.d_t_k, 0.0);
const double message_frame_time = static_cast<double>(p_frame_time_utc.date().day_of_week() * 86400 + p_frame_time_utc.time_of_day().total_seconds());
out << get_nav_sv_epoch_svclk_line(p_utc_time, sys_char, eph.PRN, -eph.d_tau_n, +eph.d_gamma_n, message_frame_time) << '\n';
}
line.clear();
@@ -3281,10 +3313,20 @@ boost::posix_time::ptime Rinex_Printer::compute_UTC_time(const Glonass_Gnav_Ephe
// Get seconds of day in glonass time
tod = fmod(obs_time_glot, 86400);
// Form date and time duration types
// Form date and time duration types. The date is taken from the ephemeris,
// so it must be adjusted if the observation time has crossed a GLONASS day
// boundary after the ephemeris reference time
const boost::posix_time::time_duration t1(0, 0, tod);
const boost::gregorian::date d1(eph.d_yr - J + 1.0, 1, 1);
const boost::gregorian::days d2(eph.d_N_T - 1);
boost::gregorian::days d2(eph.d_N_T - 1);
if (tod - eph.d_t_b > 43200.0)
{
d2 = boost::gregorian::days(eph.d_N_T - 2);
}
else if (tod - eph.d_t_b < -43200.0)
{
d2 = boost::gregorian::days(eph.d_N_T);
}
const boost::posix_time::ptime glo_time(d1 + d2, t1);
// Convert to utc
@@ -210,7 +210,11 @@ obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs,
}
break;
case 'R':
rtklib_obs.sat = gnss_synchro.PRN + NSATGPS;
rtklib_obs.sat = satno(SYS_GLO, gnss_synchro.PRN);
if (sig_ == "2G")
{
rtklib_obs.code[band] = static_cast<unsigned char>(CODE_L2C);
}
break;
case 'C':
rtklib_obs.sat = gnss_synchro.PRN + NSATGPS + NSATGLO + NSATGAL + NSATQZS;
@@ -372,24 +376,24 @@ geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glona
int adj_week;
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};
rtklib_sat.sat = glonass_gnav_eph.i_satellite_slot_number + NSATGPS; /* satellite number */
rtklib_sat.iode = static_cast<int>(glonass_gnav_eph.d_t_b); /* 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 = static_cast<int>(glonass_gnav_eph.d_F_T); /* satellite accuracy*/
rtklib_sat.age = static_cast<int>(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.dtaun = static_cast<int>(glonass_gnav_eph.d_Delta_tau_n); /* delay between L1 and L2 (s) */
rtklib_sat.sat = satno(SYS_GLO, glonass_gnav_eph.i_satellite_slot_number); /* satellite number */
rtklib_sat.iode = static_cast<int>(glonass_gnav_eph.d_t_b / 900.0 + 0.5); /* IODE (tb interval index) */
rtklib_sat.frq = glonass_gnav_eph.i_satellite_freq_channel; /* satellite frequency number */
rtklib_sat.svh = ((static_cast<int32_t>(glonass_gnav_eph.d_B_n) & 4) != 0 || glonass_gnav_eph.d_l3rd_n) ? 1 : 0; /* satellite health from Bn MSB and ln flag */
rtklib_sat.sva = static_cast<int>(glonass_gnav_eph.d_F_T); /* satellite accuracy*/
rtklib_sat.age = static_cast<int>(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.dtaun = glonass_gnav_eph.d_Delta_tau_n; /* delay between L1 and L2 (s) */
// Time expressed in GPS Time but using RTKLib format
glonass_gnav_eph.glot_to_gpst(glonass_gnav_eph.d_t_b, gnav_clock_model.d_tau_c, gnav_clock_model.d_tau_gps, &week, &sec);
@@ -16,7 +16,6 @@
*/
#include "hybrid_observables_gs.h"
#include "GLONASS_L1_L2_CA.h"
#include "MATH_CONSTANTS.h" // for SPEED_OF_LIGHT_M_S, TWO_PI
#include "gnss_circular_deque.h"
#include "gnss_frequencies.h"
@@ -684,25 +683,7 @@ void hybrid_observables_gs::detect_cycle_slips(std::vector<Gnss_Synchro> &data,
const double previous_phase_cycles = prev_obs.Carrier_phase_rads / TWO_PI;
const double delta_phase_cycles = current_phase_cycles - previous_phase_cycles;
double doppler_hz = obs.Carrier_Doppler_hz;
if (obs.System == 'R')
{
const std::string signal(obs.Signal, 2);
const auto it_prn = GLONASS_PRN.find(obs.PRN);
if (it_prn != GLONASS_PRN.cend())
{
if (signal == "1G")
{
doppler_hz += DFRQ1_GLO * it_prn->second;
}
else if (signal == "2G")
{
doppler_hz += DFRQ2_GLO * it_prn->second;
}
}
}
const double residual = delta_phase_cycles + doppler_hz * d_T_rx_step_s;
const double residual = delta_phase_cycles + obs.Carrier_Doppler_hz * d_T_rx_step_s;
residuals.push_back(residual);
channels.push_back(n);
}
@@ -200,7 +200,6 @@ void glonass_l1_ca_telemetry_decoder_gs::decode_string(const double *frame_symbo
{
LOG(INFO) << "GLONASS GNAV Slot Number Identified in channel " << d_channel;
d_satellite.update_PRN(d_nav.get_ephemeris().d_n);
d_satellite.what_block(d_satellite.get_system(), d_nav.get_ephemeris().d_n);
d_nav.set_flag_update_slot_number(false);
}
}
@@ -201,7 +201,6 @@ void glonass_l2_ca_telemetry_decoder_gs::decode_string(const double *frame_symbo
{
LOG(INFO) << "GLONASS GNAV Slot Number Identified in channel " << d_channel;
d_satellite.update_PRN(d_nav.get_ephemeris().d_n);
d_satellite.what_block(d_satellite.get_system(), d_nav.get_ephemeris().d_n);
d_nav.set_flag_update_slot_number(false);
}
}
@@ -102,6 +102,7 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_)
d_acq_carrier_doppler_hz(0.0),
d_current_correlation_time_s(0.0),
d_cfo_frequency_hz(0.0),
d_cfo_phase_step_rad(0.0),
d_carrier_doppler_hz(0.0),
d_acc_carrier_phase_rad(0.0),
d_rem_code_phase_chips(0.0),
@@ -993,6 +994,7 @@ void dll_pll_veml_tracking::start_tracking()
d_cfo_frequency_hz = (DFRQ2_GLO * GLONASS_PRN.at(d_acquisition_gnss_synchro->PRN));
}
d_carrier_phase_step_rad = TWO_PI * (d_cfo_frequency_hz + d_carrier_doppler_hz) / static_cast<double>(d_trk_parameters.fs_in);
d_cfo_phase_step_rad = TWO_PI * d_cfo_frequency_hz / static_cast<double>(d_trk_parameters.fs_in);
d_symbols_per_bit = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT;
d_correlation_length_ms = 1;
d_code_samples_per_chip = 1;
@@ -1450,7 +1452,7 @@ void dll_pll_veml_tracking::update_tracking_vars()
// double a = d_carrier_phase_step_rad * static_cast<double>(d_current_prn_length_samples);
// double b = 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples);
// std::cout << fmod(b, TWO_PI) / fmod(a, TWO_PI) << '\n';
d_acc_carrier_phase_rad -= (d_carrier_phase_step_rad * static_cast<double>(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples));
d_acc_carrier_phase_rad -= ((d_carrier_phase_step_rad - d_cfo_phase_step_rad) * static_cast<double>(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples));
// ################### DLL COMMANDS #################################################
// code phase step (Code resampler phase increment per sample) [chips/sample]
@@ -1964,7 +1966,7 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused)
d_current_prn_length_samples = round(T_prn_mod_samples);
const int32_t samples_offset = round(d_acq_code_phase_samples);
d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast<double>(samples_offset);
d_acc_carrier_phase_rad -= (d_carrier_phase_step_rad - d_cfo_phase_step_rad) * static_cast<double>(samples_offset);
d_state = 2;
// d_sample_counter += samples_offset; // count for the processed samples
d_cn0_smoother.reset();
@@ -134,6 +134,7 @@ private:
double d_code_error_filt_chips;
double d_code_freq_chips;
double d_cfo_frequency_hz;
double d_cfo_phase_step_rad;
double d_carrier_doppler_hz;
double d_acc_carrier_phase_rad;
double d_rem_code_phase_chips;
@@ -188,6 +188,25 @@ int64_t Glonass_Gnav_Navigation_Message::read_navigation_signed(const std::bitse
}
void Glonass_Gnav_Navigation_Message::update_almanac_satellite_info()
{
Glonass_Gnav_Almanac& alm = gnav_almanac[i_alm_satellite_slot_number - 1];
// H_n_A values 25..31 represent carrier frequency channels -7..-1, values
// 0..13 map directly to channels 0..13, and values 14..24 are not used
// (GLONASS ICD Table 4.10)
if (alm.d_H_n_A > 24)
{
alm.i_satellite_freq_channel = static_cast<int32_t>(alm.d_H_n_A) - 32;
}
else if (alm.d_H_n_A <= 13)
{
alm.i_satellite_freq_channel = static_cast<int32_t>(alm.d_H_n_A);
}
alm.i_satellite_slot_number = static_cast<uint32_t>(alm.d_n_A);
alm.PRN = static_cast<uint32_t>(alm.d_n_A);
}
uint32_t Glonass_Gnav_Navigation_Message::get_frame_number(uint32_t satellite_slot_number)
{
uint32_t frame_ID = 0U;
@@ -225,7 +244,6 @@ uint32_t Glonass_Gnav_Navigation_Message::get_frame_number(uint32_t satellite_sl
int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame_string)
{
int32_t J = 0;
d_frame_ID = 0U;
uint64_t P_1_tmp = 0;
// Unpack bytes to bits
@@ -304,10 +322,18 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_ephemeris.d_n = static_cast<double>(read_navigation_unsigned(string_bits, N));
gnav_ephemeris.d_M = static_cast<double>(read_navigation_unsigned(string_bits, M));
// Fill in ephemeris deliverables in the code
flag_update_slot_number = true;
gnav_ephemeris.i_satellite_slot_number = static_cast<uint32_t>(gnav_ephemeris.d_n);
gnav_ephemeris.PRN = static_cast<uint32_t>(gnav_ephemeris.d_n);
// Fill in ephemeris deliverables in the code. Valid slot numbers
// are the ones in the GLONASS_PRN table (nominal constellation
// slots 1-24 plus the slots used by satellites under flight
// tests). n = 0 is broadcast by satellites under test or
// maintenance, and must not replace the configured satellite
// identity
if (static_cast<uint32_t>(gnav_ephemeris.d_n) >= 1 && GLONASS_PRN.find(static_cast<uint32_t>(gnav_ephemeris.d_n)) != GLONASS_PRN.cend())
{
flag_update_slot_number = true;
gnav_ephemeris.i_satellite_slot_number = static_cast<uint32_t>(gnav_ephemeris.d_n);
gnav_ephemeris.PRN = static_cast<uint32_t>(gnav_ephemeris.d_n);
}
flag_ephemeris_str_4 = true;
}
@@ -396,12 +422,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = read_navigation_bool(string_bits, ALM_L_N);
// Set satellite information for redundancy purposes
if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24)
{
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0;
}
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
gnav_almanac[i_alm_satellite_slot_number - 1].PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
update_almanac_satellite_info();
if (i_alm_satellite_slot_number == gnav_ephemeris.i_satellite_slot_number)
{
@@ -446,12 +467,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = read_navigation_bool(string_bits, ALM_L_N);
// Set satellite information for redundancy purposes
if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24)
{
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0;
}
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
gnav_almanac[i_alm_satellite_slot_number - 1].PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
update_almanac_satellite_info();
flag_almanac_str_9 = true;
}
@@ -491,12 +507,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = read_navigation_bool(string_bits, ALM_L_N);
// Set satellite information for redundancy purposes
if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24)
{
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0;
}
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
gnav_almanac[i_alm_satellite_slot_number - 1].PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
update_almanac_satellite_info();
flag_almanac_str_11 = true;
}
@@ -535,12 +546,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = read_navigation_bool(string_bits, ALM_L_N);
// Set satellite information for redundancy purposes
if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24)
{
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0;
}
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
gnav_almanac[i_alm_satellite_slot_number - 1].PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
update_almanac_satellite_info();
flag_almanac_str_13 = true;
}
@@ -548,17 +554,21 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
case 14:
// --- It is string 14 ---------------------------------------------
// The frame being received is only known from the almanac slot numbers
// decoded in strings 6-13, so d_frame_ID is 0 (unknown) until one of
// them has been decoded. In frame 5, string 14 carries the B1/B2 UTC
// parameters instead of almanac data
if (d_frame_ID == 5)
{
gnav_utc_model.d_B1 = static_cast<double>(read_navigation_unsigned(string_bits, B1));
gnav_utc_model.d_B2 = static_cast<double>(read_navigation_unsigned(string_bits, B2));
}
else
else if (d_frame_ID != 0)
{
i_alm_satellite_slot_number = static_cast<uint32_t>(read_navigation_unsigned(string_bits, N_A));
d_frame_ID = get_frame_number(i_alm_satellite_slot_number);
// Make sure a valid frame_ID or satellite slot number is returned
if (d_frame_ID == 0)
// In frames 1-4, string 14 carries the almanac of a satellite
// assigned to the frame being received
if (get_frame_number(i_alm_satellite_slot_number) != d_frame_ID)
{
return 0;
}
@@ -576,7 +586,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
case 15:
// --- It is string 15 ----------------------------------------------
if (d_frame_ID != 5 && flag_almanac_str_14 == true)
if (d_frame_ID >= 1 && d_frame_ID <= 4 && flag_almanac_str_14 == true)
{
gnav_almanac[i_alm_satellite_slot_number - 1].d_omega_n_A = static_cast<double>(read_navigation_signed(string_bits, OMEGA_N_A)) * TWO_N15 * GNSS_PI;
gnav_almanac[i_alm_satellite_slot_number - 1].d_t_lambda_n_A = static_cast<double>(read_navigation_unsigned(string_bits, T_LAMBDA_N_A)) * TWO_N5;
@@ -586,12 +596,7 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame
gnav_almanac[i_alm_satellite_slot_number - 1].d_l_n = read_navigation_bool(string_bits, ALM_L_N);
// Set satellite information for redundancy purposes
if (gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A > 24)
{
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_freq_channel = gnav_almanac[i_alm_satellite_slot_number - 1].d_H_n_A - 32.0;
}
gnav_almanac[i_alm_satellite_slot_number - 1].i_satellite_slot_number = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
gnav_almanac[i_alm_satellite_slot_number - 1].PRN = gnav_almanac[i_alm_satellite_slot_number - 1].d_n_A;
update_almanac_satellite_info();
flag_almanac_str_15 = true;
}
@@ -172,6 +172,7 @@ private:
uint64_t read_navigation_unsigned(const std::bitset<GLONASS_GNAV_STRING_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const;
int64_t read_navigation_signed(const std::bitset<GLONASS_GNAV_STRING_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const;
bool read_navigation_bool(const std::bitset<GLONASS_GNAV_STRING_BITS>& bits, const std::vector<std::pair<int32_t, int32_t>>& parameter) const;
void update_almanac_satellite_info();
Glonass_Gnav_Ephemeris gnav_ephemeris{}; // Ephemeris information decoded
Glonass_Gnav_Utc_Model gnav_utc_model{}; // UTC model information
+6 -15
View File
@@ -222,24 +222,15 @@ void Gnss_Satellite::update_PRN(uint32_t PRN_)
if (system != "Glonass")
{
DLOG(INFO) << "Trying to update PRN for not GLONASS system";
PRN = 0;
return;
}
else
if (PRN_ < 1 || GLONASS_PRN.find(PRN_) == GLONASS_PRN.cend())
{
if (PRN_ < 1 or PRN_ > 31)
{
DLOG(INFO) << "This GLONASS slot number is not defined";
PRN = 0;
}
else
{
if (GLONASS_PRN.find(PRN_) == GLONASS_PRN.cend())
{
DLOG(INFO) << "GLONASS frequency channel for slot " << PRN_ << " is not configured";
}
PRN = PRN_;
}
DLOG(INFO) << "This GLONASS slot number is not defined";
return;
}
PRN = PRN_;
set_block(system, PRN_);
}
+1 -1
View File
@@ -51,7 +51,7 @@ public:
friend bool operator==(const Gnss_Satellite& /*sat1*/, const Gnss_Satellite& /*sat2*/); //!< operator== for comparison
friend std::ostream& operator<<(std::ostream& /*out*/, const Gnss_Satellite& /*sat*/); //!< operator<< for pretty printing
void update_PRN(uint32_t PRN); //!< Updates the PRN Number when information is decoded, only applies to GLONASS GNAV messages
void update_PRN(uint32_t PRN); //!< Updates the PRN Number (and the corresponding block) when the slot number is decoded, only applies to GLONASS GNAV messages
uint32_t get_PRN() const; //!< Gets satellite's PRN
int32_t get_rf_link() const; //!< Gets the satellite's rf link
std::string get_system() const; //!< Gets the satellite system {"GPS", "Glonass", "SBAS", "Galileo", "Beidou", "QZSS"}
@@ -165,7 +165,10 @@ void find_obs_record_lines(const std::string& obsfile, const std::string& sat, s
{
line_epoch = line_str;
}
if (line_str.find(sat, 0) != std::string::npos)
// Observation records start with the satellite identifier; header
// lines may also contain it (e.g. GLONASS SLOT / FRQ #), so the
// match is anchored to the beginning of the line
if (line_str.compare(0, sat.size(), sat) == 0)
{
no_more_finds = true;
line_sat = line_str;
@@ -379,23 +382,25 @@ TEST_F(RinexPrinterTest, GlonassObsHeader)
fstr.seekg(0);
std::string line_aux;
std::string line_slot_frq;
std::string line_str;
bool no_more_finds = false;
while (!fstr.eof())
{
std::getline(fstr, line_str);
if (!no_more_finds)
if (line_aux.empty() && line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos)
{
if (line_str.find("SYS / # / OBS TYPES", 59) != std::string::npos)
{
no_more_finds = true;
line_aux = std::string(line_str);
}
line_aux = std::string(line_str);
}
if (line_slot_frq.empty() && line_str.find("GLONASS SLOT / FRQ #", 59) != std::string::npos)
{
line_slot_frq = std::string(line_str);
}
}
std::string expected_str("R 4 C1C L1C D1C S1C SYS / # / OBS TYPES ");
std::string expected_slot_frq(" 27 R01 1 R02 -4 R03 5 R04 6 R05 1 R06 -4 R07 5 R08 6 GLONASS SLOT / FRQ #");
EXPECT_EQ(0, expected_str.compare(line_aux));
EXPECT_EQ(0, expected_slot_frq.compare(line_slot_frq));
fstr.close();
fs::remove(obsfile);
fs::remove(navfile);
@@ -249,3 +249,53 @@ std::string str12("0110010101001100000011110110100110100100010100001000111110000
std::string str13("0110111011100100111110100001000110100010011101001011111110100100101010011010001101001");
std::string str14("0111010101010000000100011000011110100110111100001110110100001000001111001101010000101");
std::string str15("0111101110101010001110101010100111101100001101001011111111100010101010011001010011101");
/*!
* \brief Testing satellite identification fields filled in by the second
* almanac string of the pair (string 7 for satellite slot 6, whose H_n_A
* value of 28 represents carrier frequency channel -4)
*/
TEST(GlonassGnavNavigationMessageTest, String7SetsAlmanacSatelliteInfo)
{
Glonass_Gnav_Navigation_Message gnav_nav_message;
gnav_nav_message.string_decoder(str6);
gnav_nav_message.string_decoder(str7);
Glonass_Gnav_Almanac gnav_almanac = gnav_nav_message.get_almanac(6);
EXPECT_EQ(gnav_almanac.i_satellite_slot_number, 6U);
EXPECT_EQ(gnav_almanac.PRN, 6U);
EXPECT_EQ(gnav_almanac.i_satellite_freq_channel, -4);
}
/*!
* \brief In frames 1-4, string 14 carries almanac data (here for satellite
* slot 10, in frame 2). The frame is known from the almanac slot number
* decoded in a previous string of the same frame
*/
TEST(GlonassGnavNavigationMessageTest, String14AlmanacDecoder)
{
Glonass_Gnav_Navigation_Message gnav_nav_message;
gnav_nav_message.string_decoder(str6); // almanac slot 6 identifies frame 2
gnav_nav_message.string_decoder(str14); // almanac for slot 10, also in frame 2
EXPECT_DOUBLE_EQ(gnav_nav_message.get_almanac(10).d_n_A, 10.0);
}
/*!
* \brief Until the frame being received is identified, string 14 content is
* ambiguous (in frame 5 it carries the B1/B2 UTC parameters instead of
* almanac data), so it must not be decoded as almanac
*/
TEST(GlonassGnavNavigationMessageTest, String14RequiresKnownFrame)
{
Glonass_Gnav_Navigation_Message gnav_nav_message;
gnav_nav_message.string_decoder(str14);
EXPECT_DOUBLE_EQ(gnav_nav_message.get_almanac(10).d_n_A, 0.0);
}