Generic ephemeris validator

Implement generic ephemeris validator:
Keep previous and last valid ephemeris.
Compare received ephemeris to previous and last valid.
Count successful comparisions.
Update last valid ephemeris if count reaches threshold.

Add telemetry decoder configuration parameters:

int32_t TelemetryDecoder_B1.ecc_reject - reject ephemeris if the ECC error
counter reaches this value

int32_t TelemetryDecoder_B1.ecc_resync - resync telemetry decoder if the ECC
error counter reaches this value

int32_t TelemetryDecoder_B1.validator_thr - number of equal ephemeris
received, after that the ephemeris would be passed to observable. Set to
1 to disable validation

bool TelemetryDecoder_B1.validator_accept_first - an option to always pass
the first received ephemeris, bypassing the validator for one time. This
may speed up first PVT solution at cost of higher probability of getting
incorrect PVT in case, the first epehemeris would be corrupt.

Signed-off-by: Vladislav P <vladisslav2011@gmail.com>
This commit is contained in:
Vladislav P 2022-08-26 02:39:58 +03:00
parent f09da3ded6
commit 0282e61ac0
No known key found for this signature in database
GPG Key ID: 631C5FD38EE8D868
7 changed files with 204 additions and 6 deletions

View File

@ -34,4 +34,10 @@ void Tlm_Conf::SetFromConfiguration(const ConfigurationInterface *configuration,
{
there_are_e6_channels = true;
}
ecc_errors_reject = configuration->property(role + ".ecc_reject", 1);
ecc_errors_reject = (ecc_errors_reject < 1) ? 1 : ecc_errors_reject;
ecc_errors_resync = configuration->property(role + ".ecc_resync", 6);
ecc_errors_resync = (ecc_errors_resync < 1) ? 1 : ecc_errors_resync;
validator_thr = configuration->property(role + ".validator_thr", 2);
validator_accept_first = configuration->property(role + ".validator_accept_first", true);
}

View File

@ -43,6 +43,10 @@ public:
bool dump_crc_stats{false}; // telemetry CRC statistics
bool enable_navdata_monitor{false};
bool there_are_e6_channels{false};
int32_t ecc_errors_reject{1};
int32_t ecc_errors_resync{6};
uint32_t validator_thr{2};
bool validator_accept_first{true};
};

View File

@ -6,6 +6,7 @@
set(SYSTEM_PARAMETERS_SOURCES
common_ephemeris.cc
gnss_almanac.cc
gnss_ephemeris.cc
gnss_satellite.cc
@ -31,6 +32,7 @@ set(SYSTEM_PARAMETERS_SOURCES
)
set(SYSTEM_PARAMETERS_HEADERS
common_ephemeris.h
gnss_almanac.h
gnss_ephemeris.h
gnss_satellite.h

View File

@ -0,0 +1,83 @@
/*!
* \file common_ephemeris.cc
* \brief Base class for GNSS Ephemeris
* \author Vladislav P, 2022. vladisslav2011(at)gmail.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "common_ephemeris.h"
#include <cmath>
#include <numeric>
bool Common_Ephemeris::validate(history_set &hist, const std::shared_ptr<Common_Ephemeris> &eph, const int thr, const bool first_pass)
{
double dev_last = -1.0;
double dev_val = -1.0;
const int prn = eph->PRN - 1;
bool ret = false;
if (thr == 0)
{
return true;
}
if (hist[prn].last_eph.get())
{
dev_last = hist[prn].last_eph->max_deviation(*eph.get());
#ifdef EPHEMERIS_VALIDATOR_DEBUG
if (hist[prn].last_eph.get() == eph.get())
{
std::cout << "\nhist[prn].last_eph.get() == eph.get()\n\n";
}
#endif
}
if (hist[prn].valid_eph.get())
{
dev_val = hist[prn].valid_eph->max_deviation(*eph.get());
#ifdef EPHEMERIS_VALIDATOR_DEBUG
if (hist[prn].valid_eph.get() == eph.get())
{
std::cout << "\nhist[prn].last_eph.get() == eph.get()\n\n";
}
#endif
if (dev_last < dev_val)
{
if (dev_last < DEVIATION_THRESHOLD)
{
hist[prn].valid_eph = eph;
hist[prn].valid_eph_count = 2;
ret = hist[prn].valid_eph_count >= hist[prn].valid_eph_thr;
hist[prn].valid_eph_thr = (thr > 2) ? thr : 2;
}
}
else
{
if (dev_val < DEVIATION_THRESHOLD)
{
hist[prn].valid_eph_count++;
hist[prn].valid_eph_thr = (thr > 2) ? thr : 2;
ret = hist[prn].valid_eph_count >= hist[prn].valid_eph_thr;
}
}
}
else
{
hist[prn].valid_eph = eph;
hist[prn].valid_eph_count = 1;
hist[prn].valid_eph_thr = thr;
ret = first_pass || hist[prn].valid_eph_count >= hist[prn].valid_eph_thr;
}
hist[prn].last_eph = eph;
#ifdef EPHEMERIS_VALIDATOR_DEBUG
std::cout << "PRN " << eph->PRN << " dev_last = " << dev_last << " dev_val = " << dev_val << " count = " << hist[prn].valid_eph_count << "\n";
#endif
return ret;
}

View File

@ -0,0 +1,71 @@
/*!
* \file common_ephemeris.h
* \brief Base class for GNSS Ephemeris
* \author Vladislav P, 2022. vladisslav2011(at)gmail.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_COMMON_EPHEMERIS_H
#define GNSS_SDR_COMMON_EPHEMERIS_H
#include <cstdint>
#include <memory>
#include <vector>
#ifdef EPHEMERIS_VALIDATOR_DEBUG
#include <iostream>
#define update_eph_deviation(NN) \
{ \
if (std::fabs((NN)-tmp.NN) > dev) \
{ \
dev = std::fabs((NN)-tmp.NN); \
std::cout << "Gnss_Ephemeris::max_deviation " #NN << ": " << (NN) << "-" << tmp.NN << "=" << std::fabs((NN)-tmp.NN) << "\n"; \
} \
}
#else
#define update_eph_deviation(NN) \
{ \
if (std::fabs((NN)-tmp.NN) > dev) \
{ \
dev = std::fabs((NN)-tmp.NN); \
} \
}
#endif
class Common_Ephemeris
{
private:
using last_valid = struct
{
std::shared_ptr<Common_Ephemeris> last_eph;
std::shared_ptr<Common_Ephemeris> valid_eph;
int valid_eph_count;
int valid_eph_thr;
};
protected:
static constexpr double DEVIATION_THRESHOLD = 0.00001;
public:
using history_set = std::vector<last_valid>;
Common_Ephemeris() = default;
virtual ~Common_Ephemeris() = default;
virtual double max_deviation(Common_Ephemeris &from) = 0; //!< Compare a set of ephemeris to another one
static bool validate(history_set &hist, const std::shared_ptr<Common_Ephemeris> &eph, const int thr, const bool first_pass);
uint32_t PRN{}; //!< SV ID
};
#endif // GNSS_SDR_COMMON_EPHEMERIS_H

View File

@ -21,10 +21,10 @@
#include <algorithm>
#include <cmath>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
double Gnss_Ephemeris::sv_clock_drift(double transmitTime)
{
const double dt = check_t(transmitTime - this->toc);
@ -165,8 +165,37 @@ void Gnss_Ephemeris::satellitePosition(double transmitTime)
this->dtr = pos_vel_dtr[6];
}
double Gnss_Ephemeris::max_deviation(Common_Ephemeris &from)
{
const Gnss_Ephemeris &tmp = dynamic_cast<Gnss_Ephemeris &>(from);
double dev = 0.0;
update_eph_deviation(PRN);
update_eph_deviation(M_0);
update_eph_deviation(delta_n);
update_eph_deviation(ecc);
update_eph_deviation(sqrtA);
update_eph_deviation(OMEGA_0);
update_eph_deviation(i_0);
update_eph_deviation(omega);
update_eph_deviation(OMEGAdot);
update_eph_deviation(idot);
update_eph_deviation(Cuc);
update_eph_deviation(Cus);
update_eph_deviation(Crc);
update_eph_deviation(Crs);
update_eph_deviation(Cic);
update_eph_deviation(Cis);
// update_eph_deviation(toe);
// update_eph_deviation(toc);
update_eph_deviation(af0);
update_eph_deviation(af1);
update_eph_deviation(af2);
update_eph_deviation(satClkDrift);
update_eph_deviation(dtr);
return dev;
}
void Gnss_Ephemeris::satellitePosVelComputation(double transmitTime, std::array<double, 7>& pos_vel_dtr) const
void Gnss_Ephemeris::satellitePosVelComputation(double transmitTime, std::array<double, 7> &pos_vel_dtr) const
{
// Restore semi-major axis
const double a = this->sqrtA * this->sqrtA;

View File

@ -19,13 +19,16 @@
#ifndef GNSS_SDR_GNSS_EPHEMERIS_H
#define GNSS_SDR_GNSS_EPHEMERIS_H
#include "common_ephemeris.h"
#include <array>
#include <cstdint>
#include <memory>
#include <vector>
/*!
* \brief Base class for GNSS ephemeris storage
*/
class Gnss_Ephemeris
class Gnss_Ephemeris : public Common_Ephemeris
{
public:
Gnss_Ephemeris() = default;
@ -65,9 +68,9 @@ public:
*/
double predicted_doppler(double rx_time_s, double lat, double lon, double h, double ve, double vn, double vu, int band) const;
void satellitePosition(double transmitTime); //!< Computes the ECEF SV coordinates and ECEF velocity
void satellitePosition(double transmitTime); //!< Computes the ECEF SV coordinates and ECEF velocity
double max_deviation(Common_Ephemeris &from) override; //!< Compare a set of ephemeris to another one
uint32_t PRN{}; //!< SV ID
double M_0{}; //!< Mean anomaly at reference time [rad]
double delta_n{}; //!< Mean motion difference from computed value [rad/sec]
double ecc{}; //!< Eccentricity
@ -112,7 +115,7 @@ protected:
char System{}; //!< Character ID of the GNSS system. 'G': GPS. 'E': Galileo. 'B': BeiDou
private:
void satellitePosVelComputation(double transmitTime, std::array<double, 7>& pos_vel_dtr) const;
void satellitePosVelComputation(double transmitTime, std::array<double, 7> &pos_vel_dtr) const;
double check_t(double time) const;
double sv_clock_relativistic_term(double transmitTime) const;
};