diff --git a/src/algorithms/libs/glonass_l1_signal_replica.cc b/src/algorithms/libs/glonass_l1_signal_replica.cc index b0cab18cd..f40dc5318 100644 --- a/src/algorithms/libs/glonass_l1_signal_replica.cc +++ b/src/algorithms/libs/glonass_l1_signal_replica.cc @@ -75,6 +75,60 @@ void glonass_l1_ca_code_gen_complex(own::span> dest, uint32_ } } +void glonass_l1_ca_code_gen_float(own::span dest, uint32_t chip_shift) +{ + const uint32_t code_length = 511; + std::bitset G1{}; + auto G1_register = std::bitset<9>{}.set(); // All true + uint32_t lcv; + uint32_t lcv2; + bool feedback1; + bool aux; + + /* Generate G1 Register */ + for (lcv = 0; lcv < code_length; lcv++) + { + G1[lcv] = G1_register[2]; + + feedback1 = G1_register[4] ^ G1_register[0]; + + for (lcv2 = 0; lcv2 < 8; lcv2++) + { + G1_register[lcv2] = G1_register[lcv2 + 1]; + } + + G1_register[8] = feedback1; + } + + /* Generate PRN from G1 Register */ + for (lcv = 0; lcv < code_length; lcv++) + { + aux = G1[lcv]; + if (aux == true) + { + dest[lcv] = 1; + } + else + { + dest[lcv] = -1; + } + } + + /* Generate PRN from G1 and G2 Registers */ + for (lcv = 0; lcv < code_length; lcv++) + { + aux = G1[(lcv + chip_shift) % code_length]; + if (aux == true) + { + dest[lcv] = 1; + } + else + { + dest[lcv] = -1; + } + } +} + /* * Generates complex GLONASS L1 C/A code for the desired SV ID and sampled to specific sampling frequency diff --git a/src/algorithms/libs/glonass_l1_signal_replica.h b/src/algorithms/libs/glonass_l1_signal_replica.h index dbf7f78f4..a774fda83 100644 --- a/src/algorithms/libs/glonass_l1_signal_replica.h +++ b/src/algorithms/libs/glonass_l1_signal_replica.h @@ -38,6 +38,9 @@ namespace own = gsl_lite; //! Generates complex GLONASS L1 C/A code for the desired SV ID and code shift void glonass_l1_ca_code_gen_complex(own::span> dest, uint32_t chip_shift); +//! Generates float GLONASS L1 C/A code for the desired SV ID and code shift +void glonass_l1_ca_code_gen_float(own::span dest, uint32_t chip_shift); + //! Generates complex GLONASS L1 C/A code for the desired SV ID and code shift, and sampled to specific sampling frequency void glonass_l1_ca_code_gen_complex_sampled(own::span> dest, int32_t sampling_freq, uint32_t chip_shift); 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 80cf17291..5185fecf7 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 @@ -22,11 +22,16 @@ * ----------------------------------------------------------------------------- */ + + #include "glonass_l1_ca_dll_pll_tracking.h" #include "GLONASS_L1_L2_CA.h" #include "configuration_interface.h" -#include "gnss_sdr_flags.h" -#include +#include "display.h" +#include +#include +#include +#include #if USE_GLOG_AND_GFLAGS #include @@ -34,138 +39,81 @@ #include #endif - GlonassL1CaDllPllTracking::GlonassL1CaDllPllTracking( const ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams) - : role_(role), - item_size_(sizeof(gr_complex)), - channel_(0), - in_streams_(in_streams), - out_streams_(out_streams) + : BaseDllPllTracking(configuration, role, in_streams, out_streams) { - // ################# CONFIGURATION PARAMETERS ######################## - const std::string default_item_type("gr_complex"); - std::string item_type = configuration->property(role_ + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); - bool dump = configuration->property(role_ + ".dump", false); - float pll_bw_hz = configuration->property(role_ + ".pll_bw_hz", static_cast(50.0)); + configure_tracking_parameters(configuration); + create_tracking_block(); +} -#if USE_GLOG_AND_GFLAGS - if (FLAGS_pll_bw_hz != 0.0) - { - pll_bw_hz = static_cast(FLAGS_pll_bw_hz); - } -#else - if (absl::GetFlag(FLAGS_pll_bw_hz) != 0.0) - { - pll_bw_hz = static_cast(absl::GetFlag(FLAGS_pll_bw_hz)); - } -#endif - float dll_bw_hz = configuration->property(role_ + ".dll_bw_hz", static_cast(2.0)); -#if USE_GLOG_AND_GFLAGS - if (FLAGS_dll_bw_hz != 0.0) - { - dll_bw_hz = static_cast(FLAGS_dll_bw_hz); - } -#else - if (absl::GetFlag(FLAGS_dll_bw_hz) != 0.0) - { - dll_bw_hz = static_cast(absl::GetFlag(FLAGS_dll_bw_hz)); - } -#endif - float early_late_space_chips = configuration->property(role_ + ".early_late_space_chips", static_cast(0.5)); - const std::string default_dump_filename("./track_ch"); - std::string dump_filename = configuration->property(role_ + ".dump_filename", default_dump_filename); - const auto vector_length = static_cast(std::round(fs_in / (GLONASS_L1_CA_CODE_RATE_CPS / GLONASS_L1_CA_CODE_LENGTH_CHIPS))); - // ################# MAKE TRACKING GNURadio object ################### - DLOG(INFO) << "role " << role_; - if (item_type == "gr_complex") +void GlonassL1CaDllPllTracking::configure_tracking_parameters( + const ConfigurationInterface* configuration __attribute__((unused))) +{ + // Set basic signal identifiers + config_params().system = 'R'; + const std::array sig{'1', 'G', '\0'}; + std::copy_n(sig.data(), 3, config_params().signal); + + const auto vector_length = static_cast(std::round(config_params().fs_in / (GLONASS_L1_CA_CODE_RATE_CPS / GLONASS_L1_CA_CODE_LENGTH_CHIPS))); + config_params().vector_length = vector_length; + + // Sanity checks and warnings + if (config_params().extend_correlation_symbols < 1) { - tracking_sptr_ = glonass_l1_ca_dll_pll_make_tracking_cc( - fs_in, - vector_length, - dump, - dump_filename, - pll_bw_hz, - dll_bw_hz, - early_late_space_chips); - DLOG(INFO) << "tracking(" << tracking_sptr_->unique_id() << ")"; + config_params().extend_correlation_symbols = 1; + std::cout << TEXT_RED + << "WARNING: Glonass L1: extend_correlation_symbols must be > 0. " + << "Coherent integration set to 1 ms." + << TEXT_RESET << std::endl; + } + else if (config_params().extend_correlation_symbols > 10) + { + config_params().extend_correlation_symbols = 10; + std::cout << TEXT_RED + << "WARNING: Glonass L1: extend_correlation_symbols limited to 10 (10 ms)." + << TEXT_RESET << std::endl; + } + + // GPS L1 C/A does not have a pilot component + config_params().track_pilot = configuration->property(this->role() + ".track_pilot", false); + if (config_params().track_pilot) + { + config_params().track_pilot = false; + std::cout << TEXT_RED + << "WARNING: Glonass L1 does not have pilot signal. " + << "Data tracking enabled instead." + << TEXT_RESET << std::endl; + } + + // Ensure bandwidth sanity when narrow-band is enabled + if ((config_params().extend_correlation_symbols > 1) && + (config_params().pll_bw_narrow_hz > config_params().pll_bw_hz || + config_params().dll_bw_narrow_hz > config_params().dll_bw_hz)) + { + std::cout << TEXT_RED + << "WARNING: Glonass L1: Narrow tracking bandwidth is higher than wide bandwidth." + << TEXT_RESET << std::endl; + } +} + + +void GlonassL1CaDllPllTracking::create_tracking_block() +{ + // Create GNU Radio block + if (config_params().item_type == "gr_complex") + { + tracking_sptr_ = dll_pll_veml_make_tracking(config_params()); + DLOG(INFO) << "Tracking block (" << tracking_sptr_->unique_id() << ")"; } else { - item_size_ = 0; + set_item_size(0); tracking_sptr_ = nullptr; - LOG(WARNING) << item_type << " unknown tracking item type."; - } - - if (in_streams_ > 1) - { - LOG(ERROR) << "This implementation only supports one input stream"; - } - if (out_streams_ > 1) - { - LOG(ERROR) << "This implementation only supports one output stream"; + LOG(WARNING) << config_params().item_type << " unknown tracking item type."; } } - - -void GlonassL1CaDllPllTracking::stop_tracking() -{ -} - - -void GlonassL1CaDllPllTracking::start_tracking() -{ - tracking_sptr_->start_tracking(); -} - - -/* - * Set tracking channel unique ID - */ -void GlonassL1CaDllPllTracking::set_channel(unsigned int channel) -{ - channel_ = channel; - tracking_sptr_->set_channel(channel); -} - - -void GlonassL1CaDllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) -{ - tracking_sptr_->set_gnss_synchro(p_gnss_synchro); -} - - -void GlonassL1CaDllPllTracking::connect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - // nothing to connect, now the tracking uses gr_sync_decimator -} - - -void GlonassL1CaDllPllTracking::disconnect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - // nothing to disconnect, now the tracking uses gr_sync_decimator -} - - -gr::basic_block_sptr GlonassL1CaDllPllTracking::get_left_block() -{ - return tracking_sptr_; -} - - -gr::basic_block_sptr GlonassL1CaDllPllTracking::get_right_block() -{ - return tracking_sptr_; -} diff --git a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h index ba3f6f7fb..f56edb4bb 100644 --- a/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h +++ b/src/algorithms/tracking/adapters/glonass_l1_ca_dll_pll_tracking.h @@ -25,81 +25,40 @@ #ifndef GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H #define GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H -#include "glonass_ca_dll_pll_tracking_cc.h" -#include "tracking_interface.h" -#include +#include "base_dll_pll_tracking.h" /** \addtogroup Tracking + * Classes for GNSS signal tracking. * \{ */ -/** \addtogroup Tracking_adapters +/** \addtogroup Tracking_adapters tracking_adapters + * Wrap GNU Radio blocks for GNSS signal tracking with a TrackingInterface * \{ */ -class ConfigurationInterface; - /*! * \brief This class implements a code DLL + carrier PLL tracking loop + * block adapter for GLONASS L1 signals */ -class GlonassL1CaDllPllTracking : public TrackingInterface +class GlonassL1CaDllPllTracking : public BaseDllPllTracking { public: - GlonassL1CaDllPllTracking( - const ConfigurationInterface* configuration, + //! Constructor + GlonassL1CaDllPllTracking(const ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams); - ~GlonassL1CaDllPllTracking() = default; - - inline std::string role() override - { - return role_; - } - //! Returns "GLONASS_L1_CA_DLL_PLL_Tracking" inline std::string implementation() override { return "GLONASS_L1_CA_DLL_PLL_Tracking"; } - inline size_t item_size() override - { - return item_size_; - } - - void connect(gr::top_block_sptr top_block) override; - void disconnect(gr::top_block_sptr top_block) override; - gr::basic_block_sptr get_left_block() override; - gr::basic_block_sptr get_right_block() override; - - /*! - * \brief Set tracking channel unique ID - */ - void set_channel(unsigned int channel) override; - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to efficiently exchange synchronization data between acquisition and tracking blocks - */ - void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; - - void start_tracking() override; - - /*! - * \brief Stop running tracking - */ - void stop_tracking() override; - private: - glonass_l1_ca_dll_pll_tracking_cc_sptr tracking_sptr_; - std::string role_; - size_t item_size_; - unsigned int channel_; - unsigned int in_streams_; - unsigned int out_streams_; + void configure_tracking_parameters(const ConfigurationInterface* configuration) override; + void create_tracking_block() override; }; - /** \} */ /** \} */ -#endif // GNSS_SDR_GLONASS_L1_CA_DLL_PLL_TRACKING_H +#endif // GNSS_SDR_GLONASS_L1_DLL_PLL_TRACKING_H \ No newline at end of file diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc index 44caf32a6..b94b23e1c 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc @@ -30,12 +30,14 @@ #include "Galileo_E5a.h" #include "Galileo_E5b.h" #include "Galileo_E6.h" +#include "GLONASS_L1_L2_CA.h" #include "MATH_CONSTANTS.h" #include "beidou_b1i_signal_replica.h" #include "beidou_b3i_signal_replica.h" #include "galileo_e1_signal_replica.h" #include "galileo_e5_signal_replica.h" #include "galileo_e6_signal_replica.h" +#include "glonass_l1_signal_replica.h" #include "gnss_satellite.h" #include "gnss_sdr_create_directory.h" #include "gnss_sdr_filesystem.h" @@ -94,6 +96,7 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) d_acq_code_phase_samples(0.0), d_acq_carrier_doppler_hz(0.0), d_current_correlation_time_s(0.0), + d_cfo_frequency_hz(0.0), d_carrier_doppler_hz(0.0), d_acc_carrier_phase_rad(0.0), d_rem_code_phase_chips(0.0), @@ -450,6 +453,41 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) d_symbols_per_bit = 0; } } + else if (d_trk_parameters.system == 'R') + { + d_systemName = "Glonass"; + if (d_signal_type == "1G") + { + d_signal_carrier_freq = GLONASS_L1_CA_FREQ_HZ; + d_code_period = GLONASS_L1_CA_CODE_PERIOD_S; + d_code_chip_rate = GLONASS_L1_CA_CODE_RATE_CPS; + d_code_length_chips = static_cast(GLONASS_L1_CA_CODE_LENGTH_CHIPS); + d_signal_carrier_freq = BEIDOU_B1I_FREQ_HZ; + d_symbols_per_bit = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; + d_correlation_length_ms = 1; + d_code_samples_per_chip = 1; + d_secondary = false; + d_trk_parameters.track_pilot = false; + d_trk_parameters.slope = 1.0; + d_trk_parameters.spc = d_trk_parameters.early_late_space_chips; + d_trk_parameters.y_intercept = 1.0; + d_secondary_code_length = static_cast(GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS); + d_secondary_code_string = GLONASS_GNAV_PREAMBLE_STR; + d_symbols_per_bit = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; + } + else { + LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks"; + std::cout << "Invalid Signal argument when instantiating tracking blocks\n"; + d_correlation_length_ms = 1; + d_secondary = false; + d_signal_carrier_freq = 0.0; + d_code_period = 0.0; + d_code_length_chips = 0; + d_code_samples_per_chip = 0U; + d_symbols_per_bit = 0; + } + + } else { LOG(WARNING) << "Invalid System argument when instantiating tracking blocks"; @@ -846,7 +884,27 @@ void dll_pll_veml_tracking::start_tracking() d_Prompt_circular_buffer.set_capacity(d_secondary_code_length); } } + else if (d_systemName == "Glonass" and d_signal_type == "1G") + { + glonass_l1_ca_code_gen_float(d_tracking_code, 0); + d_cfo_frequency_hz = (DFRQ1_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(d_trk_parameters.fs_in); + d_symbols_per_bit = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; // todo: enable after fixing beidou symbol synchronization + d_correlation_length_ms = 1; + d_code_samples_per_chip = 1; + d_secondary = false; + d_trk_parameters.track_pilot = false; + // set the preamble in the secondary code acquisition + d_secondary_code_length = static_cast(GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS); + d_secondary_code_string = GLONASS_GNAV_PREAMBLE_STR; + d_data_secondary_code_length = 0; + d_Prompt_circular_buffer.set_capacity(d_secondary_code_length); + if (d_extend_correlation_symbols > GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT) + { + d_extend_correlation_symbols = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT; + } + } d_multicorrelator_cpu.set_local_code_and_taps(d_code_samples_per_chip * d_code_length_chips, d_tracking_code.data(), d_local_code_shift_chips.data()); std::fill_n(d_correlator_outs.begin(), d_n_correlator_taps, gr_complex(0.0, 0.0)); @@ -1216,7 +1274,7 @@ void dll_pll_veml_tracking::update_tracking_vars() // ################### PLL COMMANDS ################################################# // carrier phase step (NCO phase increment per sample) [rads/sample] - d_carrier_phase_step_rad = TWO_PI * d_carrier_doppler_hz / d_trk_parameters.fs_in; + d_carrier_phase_step_rad = TWO_PI * (d_carrier_doppler_hz+d_cfo_frequency_hz) / d_trk_parameters.fs_in; // carrier phase rate step (NCO phase increment rate per sample) [rads/sample^2] if (d_trk_parameters.high_dyn) { @@ -1974,7 +2032,7 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused) run_dll_pll(); update_tracking_vars(); check_carrier_phase_coherent_initialization(); - if (d_current_data_symbol == 0) + if ((d_current_data_symbol == 0) || (d_signal_type == "1G")) // Glonass telemetry decoder require symbols instead of bits { // enable write dump file this cycle (valid DLL/PLL cycle) log_data(); @@ -2013,7 +2071,7 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused) } } } - + current_synchro_data.TOW_at_current_symbol_ms = d_tow_from_telemetry_ms; // time tags std::vector tags_vec; diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h index 8f42fd626..ccc8a6f61 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.h @@ -128,6 +128,7 @@ private: double d_code_error_chips; double d_code_error_filt_chips; double d_code_freq_chips; + double d_cfo_frequency_hz; double d_carrier_doppler_hz; double d_acc_carrier_phase_rad; double d_rem_code_phase_chips; diff --git a/src/core/system_parameters/GLONASS_L1_L2_CA.h b/src/core/system_parameters/GLONASS_L1_L2_CA.h index 5106fe27d..29a4fc34c 100644 --- a/src/core/system_parameters/GLONASS_L1_L2_CA.h +++ b/src/core/system_parameters/GLONASS_L1_L2_CA.h @@ -92,6 +92,8 @@ constexpr int32_t GLONASS_L1_CA_HISTORY_DEEP = 100; #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} + +constexpr char GLONASS_GNAV_PREAMBLE_STR[301] = "111111111111111111111111111111111111111111111111110000000000000000000000000000001111111111111111111100000000001111111111111111111111111111110000000000111111111100000000001111111111000000000000000000000000000000000000000011111111110000000000000000000011111111110000000000111111111111111111110000000000"; constexpr double GLONASS_GNAV_PREAMBLE_DURATION_S = 0.300; constexpr int32_t GLONASS_GNAV_PREAMBLE_LENGTH_BITS = 30; constexpr int32_t GLONASS_GNAV_PREAMBLE_LENGTH_SYMBOLS = 300;