mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-10-18 13:32:37 +00:00
This commit is contained in:
@@ -63,6 +63,7 @@
|
||||
#include <iterator> // for insert_iterator, inserter
|
||||
#include <map> // for std::map
|
||||
#include <memory> // for std::shared_ptr
|
||||
#include <optional> // for std::optional
|
||||
#include <set> // for set
|
||||
#include <sstream> // for std::stringstream
|
||||
#include <stdexcept> // for invalid_argument
|
||||
@@ -1832,8 +1833,33 @@ void GNSSFlowgraph::acquisition_manager(unsigned int who)
|
||||
}
|
||||
else
|
||||
{
|
||||
// set Doppler center to 0 Hz and search the full Doppler range
|
||||
channels_[current_channel]->assist_acquisition_doppler(0, 0);
|
||||
// No dual-frequency assist: fall back to a geometric Doppler
|
||||
// prediction from ephemeris/almanac (SatelliteVisibility), if
|
||||
// this is the primary signal of a satellite already classified
|
||||
// visible and a live PVT fix currently exists. No-op (stays
|
||||
// nullopt) unless visibility-aware search is enabled --
|
||||
// PredictedDopplerHz() itself requires a live fix for now; the
|
||||
// AGNSS-reference (no-fix) case is a follow-up.
|
||||
std::optional<double> predicted_doppler_hz;
|
||||
if (is_primary_freq && satellite_visibility_ && satellite_visibility_->enabled())
|
||||
{
|
||||
const auto pvt_ptr = get_pvt();
|
||||
const Gnss_Satellite& sat = channels_[current_channel]->get_signal().get_satellite();
|
||||
if (pvt_ptr && satellite_visibility_->IsVisible(sat))
|
||||
{
|
||||
const Monitor_Pvt fix_status = channels_status_->get_current_status_pvt();
|
||||
predicted_doppler_hz = satellite_visibility_->PredictedDopplerHz(pvt_ptr, fix_status, sat, channels_[current_channel]->get_signal().get_signal_str());
|
||||
}
|
||||
}
|
||||
if (predicted_doppler_hz.has_value())
|
||||
{
|
||||
channels_[current_channel]->assist_acquisition_doppler(*predicted_doppler_hz, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set Doppler center to 0 Hz and search the full Doppler range
|
||||
channels_[current_channel]->assist_acquisition_doppler(0, 0);
|
||||
}
|
||||
}
|
||||
#if ENABLE_FPGA
|
||||
if (enable_fpga_offloading_)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "agnss_ref_time.h" // for parse_agnss_ref_utc_time
|
||||
#include "configuration_interface.h"
|
||||
#include "geofunctions.h"
|
||||
#include "gnss_frequencies.h" // for SIGNAL_FREQ_MAP
|
||||
#include "monitor_pvt.h"
|
||||
#include "pvt_interface.h"
|
||||
#include "qzss.h"
|
||||
@@ -1056,3 +1057,114 @@ bool SatelliteVisibility::IsSearchExcluded(const Gnss_Satellite& sat) const
|
||||
{
|
||||
return GetSearchVisibility(sat) == SearchVisibility::Excluded;
|
||||
}
|
||||
|
||||
|
||||
std::optional<double> SatelliteVisibility::PredictedDopplerHz(const std::shared_ptr<PvtInterface>& pvt_ptr,
|
||||
const Monitor_Pvt& fix_status, const Gnss_Satellite& sat, const std::string& signal) const
|
||||
{
|
||||
if (!enabled_ || !pvt_ptr || fix_status.RX_time < 0.0)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Gnss_Ephemeris::predicted_doppler()/Gnss_Almanac::predicted_doppler()'s
|
||||
// own band codes, keyed by signal the same way SIGNAL_FREQ_MAP is.
|
||||
static const std::map<std::string, int> kBandForSignal = {
|
||||
{"1C", 1}, {"1B", 1}, {"1D", 1}, {"J1", 1}, {"B1", 1},
|
||||
{"2S", 2}, {"B2", 2},
|
||||
{"L5", 5}, {"5X", 5}, {"J5", 5},
|
||||
{"E6", 6},
|
||||
{"7X", 7},
|
||||
{"B3", 3}};
|
||||
const auto band_it = kBandForSignal.find(signal);
|
||||
const auto freq_it = SIGNAL_FREQ_MAP.find(signal);
|
||||
if (band_it == kBandForSignal.cend() || freq_it == SIGNAL_FREQ_MAP.cend())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
const int band = band_it->second;
|
||||
const double carrier_freq_hz = freq_it->second;
|
||||
|
||||
const double lat_deg = fix_status.latitude;
|
||||
const double lon_deg = fix_status.longitude;
|
||||
const double h_m = fix_status.height;
|
||||
const double ve_mps = fix_status.vel_e;
|
||||
const double vn_mps = fix_status.vel_n;
|
||||
const double vu_mps = fix_status.vel_u;
|
||||
const gtime_t gps_gtime = gpst2time(static_cast<int>(fix_status.week), fix_status.RX_time);
|
||||
const double rx_time_s = time2gpst(gps_gtime, nullptr);
|
||||
int ref_gps_week = 0;
|
||||
time2gpst(gps_gtime, &ref_gps_week);
|
||||
const std::string system = sat.get_system();
|
||||
const auto prn = static_cast<int>(sat.get_PRN());
|
||||
|
||||
std::optional<double> geometric_doppler_hz;
|
||||
if (system == "GPS")
|
||||
{
|
||||
const auto eph_map = pvt_ptr->get_gps_ephemeris();
|
||||
const auto eph_it = eph_map.find(prn);
|
||||
if (eph_it != eph_map.cend() && std::abs(timediff(gps_gtime, eph_to_rtklib(eph_it->second, ref_gps_week).toe)) <= MAXDTOE)
|
||||
{
|
||||
geometric_doppler_hz = eph_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto alm_map = pvt_ptr->get_gps_almanac();
|
||||
const auto alm_it = alm_map.find(prn);
|
||||
if (alm_it != alm_map.cend() && std::abs(timediff(gps_gtime, alm_to_rtklib(alm_it->second, ref_gps_week).toa)) <= almanac_max_age_s_)
|
||||
{
|
||||
geometric_doppler_hz = alm_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (system == "Galileo")
|
||||
{
|
||||
const auto eph_map = pvt_ptr->get_galileo_ephemeris();
|
||||
const auto eph_it = eph_map.find(prn);
|
||||
if (eph_it != eph_map.cend() && std::abs(timediff(gps_gtime, eph_to_rtklib(eph_it->second).toe)) <= MAXDTOE_GAL)
|
||||
{
|
||||
geometric_doppler_hz = eph_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto alm_map = pvt_ptr->get_galileo_almanac();
|
||||
const auto alm_it = alm_map.find(prn);
|
||||
if (alm_it != alm_map.cend() && std::abs(timediff(gps_gtime, alm_to_rtklib(alm_it->second, ref_gps_week).toa)) <= almanac_max_age_s_)
|
||||
{
|
||||
geometric_doppler_hz = alm_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (system == "Beidou")
|
||||
{
|
||||
const auto eph_map = pvt_ptr->get_beidou_dnav_ephemeris();
|
||||
const auto eph_it = eph_map.find(prn);
|
||||
if (eph_it != eph_map.cend() && std::abs(timediff(gps_gtime, eph_to_rtklib(eph_it->second).toe)) <= MAXDTOE_BDS)
|
||||
{
|
||||
geometric_doppler_hz = eph_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto alm_map = pvt_ptr->get_beidou_dnav_almanac();
|
||||
const auto alm_it = alm_map.find(prn);
|
||||
if (alm_it != alm_map.cend() && std::abs(timediff(gps_gtime, alm_to_rtklib(alm_it->second).toa)) <= almanac_max_age_s_)
|
||||
{
|
||||
geometric_doppler_hz = alm_it->second.predicted_doppler(rx_time_s, lat_deg, lon_deg, h_m, ve_mps, vn_mps, vu_mps, band);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!geometric_doppler_hz.has_value())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Live PVT-solved clock drift, shared by every satellite's observed
|
||||
// Doppler, on top of the per-satellite geometric term above.
|
||||
// SUBTRACTED, not added -- empirically verified against
|
||||
// project_doppler()'s dual-frequency projection (gnss_flowgraph.cc):
|
||||
// geometric - clock_offset matched to within noise, geometric +
|
||||
// clock_offset was off by 2x it.
|
||||
const double clock_offset_hz = fix_status.user_clk_drift_ppm * 1.0e-6 * carrier_freq_hz;
|
||||
return *geometric_doppler_hz - clock_offset_hz;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -161,6 +162,22 @@ public:
|
||||
bool IsSearchVisible(const Gnss_Satellite& sat) const;
|
||||
bool IsSearchExcluded(const Gnss_Satellite& sat) const;
|
||||
|
||||
// Predicted Doppler (Hz) for sat on the given signal (e.g. "1B", "5X",
|
||||
// "L5", "7X"), for use as an acquisition search center. Geometric term
|
||||
// from whichever of sat's ephemeris/almanac is usable (same freshness
|
||||
// rules as compute_visible_satellites()), plus the receiver's live
|
||||
// solved clock drift (fix_status.user_clk_drift_ppm) scaled to this
|
||||
// signal's carrier. Only meaningful with a live PVT fix -- std::nullopt
|
||||
// when disabled, no fix is currently valid, the signal isn't a
|
||||
// recognized carrier, or neither ephemeris nor almanac is currently
|
||||
// usable for sat. No AGNSS-reference fallback yet: that's deferred to a
|
||||
// follow-up (needs the pre-fix clock/velocity uncertainty this signal's
|
||||
// Doppler tolerance can't absorb from a single search bin -- see
|
||||
// GNSS-SDR.clock_frequency_max_error_ppm / receiver_max_velocity_m_s in
|
||||
// the follow-up PR).
|
||||
std::optional<double> PredictedDopplerHz(const std::shared_ptr<PvtInterface>& pvt_ptr,
|
||||
const Monitor_Pvt& fix_status, const Gnss_Satellite& sat, const std::string& signal) const;
|
||||
|
||||
private:
|
||||
enum class SearchVisibility
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user