Changeset 11137 in ntrip


Ignore:
Timestamp:
Oct 28, 2026, 9:48:01 PM (9 hours ago)
Author:
stuerze
Message:

eph handling improved

Location:
trunk/BNC
Files:
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/CHANGELOG.md

    r11136 r11137  
    2323- ADDED: Option 'File per stream' (key ephFilePerStation) in the RINEX Ephemeris panel: one RINEX navigation file per stream, named after the stream like the observation files, each with all ephemerides of its stream; by default still one file with each ephemeris once
    2424- ADDED: PPP option 'Ephemeris stream' (key PPP/ephMount): real-time PPP uses the Broadcast Ephemeris of the given stream(s) only, e.g. BCEP00BKG0, not those of the observation streams; empty: all streams as before
     25- FIXED: GPS and QZSS uploads within the curve fit interval (cutover; TOC some 16 s earlier than that of the data set replaced, e.g. 01:59:44 instead of 02:00:00) were ignored as not newer until the next regular data set, in RINEX navigation files, ephemeris upload (BCEP), PPP and combination; corrections of ACs referring to such an upload were not used for up to 2 hours. Data sets received before (e.g. from a slower stream) are ignored now explicitly
     26- ADDED: GPS/QZSS ephemeris check: data sets with IODE different from the 8 LSBs of IODC (assembled from subframes of two uploads) are rejected
     27- FIXED: Ephemeris upload: the periods of validity of the uploaded data sets were not applied (logical or instead of and), so a data set was uploaded as long as no newer one came, e.g. a Galileo data set 32 hours after its TOC
     28- CHANGED: SSR QC: the IOD of the corrections is looked up among the last 30 data sets of a satellite instead of the last two (false 'IOD of no received broadcast ephemeris' for Galileo and GLONASS); new report lines for IODs received from the ephemeris stream(s) only later (with the largest delay) and for corrections referring to a broadcast ephemeris outside its validity
    2529- ADDED: Regression test suite ('tests'): example configurations and short raw captures replayed through BNC and compared with reference outputs
    2630- ADDED: macOS packaging script
  • trunk/BNC/src/PPP/pppEphPool.cpp

    r11047 r11137  
    9797/////////////////////////////////////////////////////////////////////////////
    9898void t_pppEphPool::t_satEphPool::putEphemeris(unsigned maxQueueSize, t_eph* eph) {
     99  // data set received before (e.g. from another stream after a newer one)
     100  for (unsigned ii = 0; ii < _ephs.size(); ii++) {
     101    if (_ephs[ii]->sameDataSet(eph)) {
     102      delete eph;
     103      return;
     104    }
     105  }
    99106  if (_ephs.empty() || eph->isNewerThan(_ephs.front())) {
    100107    _ephs.push_front(eph);
  • trunk/BNC/src/bncephuser.cpp

    r11057 r11137  
    4848// Constructor
    4949////////////////////////////////////////////////////////////////////////////
    50 bncEphUser::bncEphUser(bool connectSlots) {
     50bncEphUser::bncEphUser(bool connectSlots, unsigned maxQueueSize) : _maxQueueSize(maxQueueSize) {
    5151  if (connectSlots) {
    5252    connect(BNC_CORE, SIGNAL(newGPSEph(t_ephGPS)),
    … …  
    148148
    149149  QString prn(newEph->prn().toInternalString().c_str());
     150
     151  // data set received before, e.g. from a slower stream after a newer one
     152  if (_eph.contains(prn)) {
     153    const deque<t_eph*>& qq = _eph[prn];
     154    for (unsigned ii = 0; ii < qq.size(); ii++) {
     155      if (qq[ii]->sameDataSet(eph)) {
     156        delete newEph;
     157        return failure;
     158      }
     159    }
     160  }
    150161
    151162  const t_eph* ephOld = ephLast(prn);
    … …  
    224235  if (eph->isUnhealthy()) {
    225236    eph->setCheckState(t_eph::unhealthy);
     237    return;
     238  }
     239
     240  // GPS/QZSS: IODE and IODC of the same upload
     241  // -------------------------------------------
     242  const t_ephGPS* ephGPS = dynamic_cast<const t_ephGPS*>(eph);
     243  if (ephGPS && !ephGPS->iodeIodcConsistent()) {
     244    eph->setCheckState(t_eph::bad);
    226245    return;
    227246  }
  • trunk/BNC/src/bncephuser.h

    r11047 r11137  
    4646
    4747 public:
    48   bncEphUser(bool connectSlots);
     48  bncEphUser(bool connectSlots, unsigned maxQueueSize = 6);
    4949  virtual ~bncEphUser();
    5050
    … …  
    7272  }
    7373
     74  // latest data set of the satellite with this IOD
     75  t_eph* ephWithIOD(const QString& prn, unsigned iod) {
     76    if (_eph.contains(prn)) {
     77      const std::deque<t_eph*>& qq = _eph[prn];
     78      for (int ii = int(qq.size()) - 1; ii >= 0; ii--) {
     79        if (qq[ii]->IOD() == iod) {
     80          return qq[ii];
     81        }
     82      }
     83    }
     84    return 0;
     85  }
     86
    7487  const QList<QString> prnList() {return _eph.keys();}
    7588
    … …  
    8093  void checkEphemeris(t_eph* eph, bool realTime);
    8194  QMutex                             _mutex;
    82   static const unsigned              _maxQueueSize = 6;
     95  unsigned                           _maxQueueSize;  // data sets kept per satellite
    8396  QMap<QString, std::deque<t_eph*> > _eph;
    8497};
  • trunk/BNC/src/bnchelp.html

    r11136 r11137  
    34533453    or 'OUTDATED EPHEMERIS' in the logfile.
    34543454  </p>
     3455  <p>
     3456    A data set is taken as new if its Time of Clock (TOC) is later than that of the latest data set of the
     3457    satellite. An upload of a GPS or QZSS satellite within the curve fit interval (cutover) gets a TOC slightly
     3458    earlier than that of the data set it replaces, off the regular grid (e.g. 01:59:44 instead of 02:00:00); such a
     3459    data set with a different IOD and a TOC up to 10 minutes earlier is taken as new as well, as the satellite
     3460    broadcasts it from then on and the corrections of the Analysis Centers refer to it. A data set received before,
     3461    e.g. from a slower stream after a newer one, is ignored. A GPS or QZSS data set whose IODE differs from the 8 least
     3462    significant bits of its IODC, i.e. assembled from subframes of two uploads, is ignored as wrong.
     3463  </p>
    34553464
    34563465  <p>
    … …  
    51565165    <li>satellites with a healthy, current broadcast ephemeris without orbit corrections, clock corrections, code
    51575166      biases or phase biases (the latter two only if the stream provides them for the system),</li>
    5158     <li>orbit and clock corrections referring to an IOD of no received broadcast ephemeris, to an unhealthy
    5159       broadcast ephemeris, or to a satellite without broadcast ephemeris (number of corrections in brackets; not
    5160       checked during the first 2 minutes, while the broadcast ephemerides are received),</li>
     5167    <li>orbit and clock corrections referring to an IOD of no received broadcast ephemeris, to an IOD received from
     5168      the ephemeris stream(s) only later (up to 5 minutes, with the largest delay; the Analysis Center switched to a
     5169      new data set before the ephemeris stream delivered it), to a broadcast ephemeris outside its validity (see section
     5170      2.16 'Upload Ephemeris' for the periods of validity), to an unhealthy broadcast ephemeris, or to a satellite
     5171      without broadcast ephemeris (number of corrections in brackets; not checked during the first 2 minutes, while
     5172      the broadcast ephemerides are received). The IOD is looked up among the last 30 data sets of the satellite,
     5173      as Galileo e.g. broadcasts a new data set every 10 minutes and Analysis Centers keep one for up to an
     5174      hour,</li>
    51615175    <li>the code bias signals provided, satellites without code biases of the reference signals (default GPS C1W/C2W,
    51625176      GLONASS C1P/C2P, Galileo C1C/C5Q, BDS C2I/C6I, QZSS C1C/C2L, SBAS C1C/C5Q; as in the combination, see option
    … …  
    97849798    <li>SBAS ephemeris will be interpreted as outdated and ignored when dt > 600.0 or dt < -600.0.</li>
    97859799    <li>QZSS ephemeris will be interpreted as outdated and ignored when dt > 7200.0 or dt < -3600.0.</li>
    9786     <li>NavIC ephemeris will be interpreted as outdated and ignored when fabs(dt > 86400.0).</li>
     9800    <li>NavIC ephemeris will be interpreted as outdated and ignored when fabs(dt) > 86400.0.</li>
    97879801  </ul>
    97889802  A note 'OUTDATED EPHEMERIS' will be given in the logfile and the data will be disregarded when necessary.
  • trunk/BNC/src/ephemeris.cpp

    r11057 r11137  
    2626  _clkCorr = 0;
    2727}
     28
     29// Is this data set newer than eph (the latest one received)?
     30// Usually its TOC is later. An upload of a GPS or QZSS satellite within the
     31// curve fit interval (cutover) gets a TOC slightly earlier than that of the
     32// data set it replaces (e.g. 01:59:44 instead of 02:00:00, i.e. off the regular
     33// grid), and a different IOD; the new upload is broadcast from then on and
     34// the corrections of the ACs refer to it.
     35////////////////////////////////////////////////////////////////////////////
     36bool t_eph::isNewerThan(const t_eph* eph) const {
     37  if (eph->_TOC < _TOC) {
     38    return true;
     39  }
     40  const double MAX_CUTOVER_SHIFT = 600.0;  // observed: 16 s, 32 s
     41  if ((system() == GPS || system() == QZSS) && system() == eph->system() &&
     42      IOD() != eph->IOD() && eph->_TOC - _TOC <= MAX_CUTOVER_SHIFT) {
     43    return true;
     44  }
     45  return false;
     46}
     47
    2848// Destructor
    2949////////////////////////////////////////////////////////////////////////////
  • trunk/BNC/src/ephemeris.h

    r10954 r11137  
    2929  virtual int slotNum() const {return 0;}
    3030  bncTime TOC() const {return _TOC;}
    31   bool    isNewerThan(const t_eph* eph) const {return earlierTime(eph, this);}
     31  bool    isNewerThan(const t_eph* eph) const;
     32  bool    sameDataSet(const t_eph* eph) const {return _TOC == eph->_TOC && IOD() == eph->IOD();}
    3233  void    setCheckState(e_checkState checkState) {_checkState = checkState;}
    3334  e_checkState checkState() const {return _checkState;}
    … …  
    146147  virtual QString toString(double version) const;
    147148  virtual unsigned int  IOD() const { return static_cast<unsigned int>(_IODE); }
     149  // GPS/QZSS: IODE equals the 8 LSBs of IODC, except for data sets assembled
     150  // from subframes of two uploads (cutover)
     151  bool iodeIodcConsistent() const {
     152    return (system() != t_eph::GPS && system() != t_eph::QZSS) ||
     153           (static_cast<int>(_IODE) == (static_cast<int>(_IODC) & 0xFF));
     154  }
    148155  //virtual unsigned int  isUnhealthy() const { return static_cast<unsigned int>(_health);}
    149156  virtual unsigned int isUnhealthy() const;
  • trunk/BNC/src/src.pro

    r11020 r11137  
    22TARGET = ../bnc
    33
    4 CONFIG -= debug
    5 CONFIG += release
     4CONFIG += debug
     5CONFIG -= release
    66
    77macx {
  • trunk/BNC/src/ssrQc.cpp

    r11129 r11137  
    5656  const double MAX_CLK_JUMP   = 0.5;  // [m] clock change beyond its rate between consecutive epochs
    5757  const double EPH_WARMUP     = 120.0; // [s] no ephemeris checks at the start
     58  const double EPH_EARLY_MAX  = 300.0; // [s] IOD received this much later still counted as early
     59  const double EPH_IOD_REUSE  = 21600.0; // [s] an outdated data set this far from the epoch: IOD reused
     60  const unsigned EPH_KEPT     = 30;    // data sets kept per satellite
    5861  const double CMP_SAMPL      = 30.0;  // [s] sampling of the stream comparison
    5962  const double CMP_DELAY      = 60.0;  // [s] epochs compared when data this much newer arrived
    … …  
    119122////////////////////////////////////////////////////////////////////////////
    120123t_ssrQc::t_ssrQc(const QString& dirName, double interval, const QStringList& streams,
    121                  const QString& reference) : _ephUser(true) {
     124                 const QString& reference) : _ephUser(true, EPH_KEPT) {
    122125  _dirName   = dirName;
    123126  _reference = reference.isEmpty() ? QString("CONSENSUS") : reference;
    … …  
    359362// Broadcast ephemeris the correction refers to
    360363////////////////////////////////////////////////////////////////////////////
    361 void t_ssrQc::checkEph(t_satStat& stat, const QString& prnInt, unsigned iod, const bncTime& time,
    362                        const string& staID) {
     364void t_ssrQc::checkEph(t_satStat& stat, const QString& satKey, const QString& prnInt,
     365                       unsigned iod, const bncTime& time, const string& staID) {
    363366  // not before all broadcast ephemerides may have been received
    364367  if (time - _staStart[QString::fromStdString(staID)] < EPH_WARMUP) {
    365368    return;
    366369  }
    367   t_eph* ephLast = _ephUser.ephLast(prnInt);
    368   t_eph* ephPrev = _ephUser.ephPrev(prnInt);
    369   t_eph* eph = 0;
    370   if      (ephLast && ephLast->IOD() == iod) eph = ephLast;
    371   else if (ephPrev && ephPrev->IOD() == iod) eph = ephPrev;
    372   if (!ephLast) {
     370  if (!_ephUser.ephLast(prnInt)) {
    373371    stat.noEph += 1;
    374   }
    375   else if (!eph) {
    376     stat.iodUnknown += 1;
     372    return;
     373  }
     374  // any data set kept, not only the last two: Galileo has a new IODnav every
     375  // 10 minutes, and ACs keep one for up to an hour
     376  t_eph* eph = _ephUser.ephWithIOD(prnInt, iod);
     377  // an IOD used again later (GLONASS tb every day, GPS IODE) is another data set
     378  if (eph && outDatedBcep(eph, time) && fabs(time - eph->TOC()) > EPH_IOD_REUSE) {
     379    eph = 0;
     380  }
     381  if (!eph) {
     382    // received later from the ephemeris stream(s)? decided in resolvePendingIod
     383    t_pendingIod& pending = _pendingIod[satKey][iod];
     384    if (pending.num == 0) {
     385      pending.prnInt = prnInt;
     386      pending.first  = currentTime();
     387    }
     388    pending.num += 1;
    377389  }
    378390  else if (eph->checkState() == t_eph::unhealthy || eph->checkState() == t_eph::bad) {
    379391    stat.ephUnhealthy += 1;
     392  }
     393  else if (outDatedBcep(eph, time)) {
     394    stat.ephOutdated += 1;
     395  }
     396  if (_pendingIod.contains(satKey)) {
     397    resolvePendingIod(satKey, false);
     398  }
     399}
     400
     401// Corrections referring to an IOD not received before: counted as early if
     402// the ephemeris stream(s) delivered the data set later, as unknown if not
     403// within EPH_EARLY_MAX (or at the end of the report interval, final)
     404////////////////////////////////////////////////////////////////////////////
     405void t_ssrQc::resolvePendingIod(const QString& satKey, bool final) {
     406  t_satStat& stat = _satStat[satKey];
     407  QMap<unsigned, t_pendingIod>& pend = _pendingIod[satKey];
     408  QMutableMapIterator<unsigned, t_pendingIod> it(pend);
     409  while (it.hasNext()) {
     410    it.next();
     411    const t_pendingIod& pending = it.value();
     412    t_eph* eph = _ephUser.ephWithIOD(pending.prnInt, it.key());
     413    if (eph && eph->receptDateTime().isValid()) {
     414      bncTime recept(eph->receptDateTime().toString(Qt::ISODate).toStdString());
     415      if (recept >= pending.first) {
     416        stat.iodEarly += pending.num;
     417        stat.maxEarly  = max(stat.maxEarly, recept - pending.first);
     418        it.remove();
     419        continue;
     420      }
     421    }
     422    if (final || currentTime() - pending.first > EPH_EARLY_MAX) {
     423      stat.iodUnknown += pending.num;
     424      it.remove();
     425    }
     426  }
     427  if (pend.isEmpty()) {
     428    _pendingIod.remove(satKey);
    380429  }
    381430}
    … …  
    395444    t_satStat& stat = _satStat[QString::fromStdString(corr._staID) + ' ' + prn];
    396445    stat.numOrb += 1;
    397     checkEph(stat, QString::fromStdString(corr._prn.toInternalString()), corr._iod, corr._time, corr._staID);
     446    checkEph(stat, QString::fromStdString(corr._staID) + ' ' + prn,
     447             QString::fromStdString(corr._prn.toInternalString()), corr._iod, corr._time, corr._staID);
    398448    double radial = fabs(corr._xr[0]);
    399449    double alongCross = max(fabs(corr._xr[1]), fabs(corr._xr[2]));
    … …  
    417467    t_satStat& stat = _satStat[QString::fromStdString(corr._staID) + ' ' + prn];
    418468    stat.numClk += 1;
    419     checkEph(stat, QString::fromStdString(corr._prn.toInternalString()), corr._iod, corr._time, corr._staID);
     469    checkEph(stat, QString::fromStdString(corr._staID) + ' ' + prn,
     470             QString::fromStdString(corr._prn.toInternalString()), corr._iod, corr._time, corr._staID);
    420471
    421472    // jump: change between consecutive epochs (same IOD) beyond the clock rate
    … …  
    837888      }
    838889      const t_orbCorr& orb = (--itO).value();
    839       t_eph* eph = 0;
    840       t_eph* ephLast = _ephUser.ephLast(prnInt);
    841       t_eph* ephPrev = _ephUser.ephPrev(prnInt);
    842       if      (ephLast && ephLast->IOD() == orb._iod) eph = ephLast;
    843       else if (ephPrev && ephPrev->IOD() == orb._iod) eph = ephPrev;
     890      t_eph* eph = _ephUser.ephWithIOD(prnInt, orb._iod);
     891      if (eph && outDatedBcep(eph, tt) && fabs(tt - eph->TOC()) > EPH_IOD_REUSE) {
     892        eph = 0;
     893      }
    844894      if (!eph || clk._iod != orb._iod) {
    845895        continue;
    … …  
    13631413  bncTime endTime = final ? _lastTime : _intervalStart + _interval;
    13641414
     1415  // IODs not received: early or unknown (pending ones younger than
     1416  // EPH_EARLY_MAX are decided in the next interval)
     1417  for (const QString& satKey : _pendingIod.keys()) {
     1418    resolvePendingIod(satKey, final);
     1419  }
     1420
    13651421  // Healthy and current broadcast ephemerides per system
    13661422  QMap<char, QSet<QString> > ephSats;
    … …  
    14751531        continue;
    14761532      }
     1533      QMap<QString, unsigned> iodEarly, outdated;
     1534      double maxEarly = 0.0;
    14771535      QMap<QString, unsigned> missOrb, missClk, missCB, missPB, iodUnknown, unhealthy, noEph,
    14781536                              jumps, missRef, noYaw, yawPartly;
    … …  
    15071565        const t_satStat& stat = itSat.value();
    15081566        if (stat.iodUnknown)   iodUnknown[prn] = stat.iodUnknown;
     1567        if (stat.iodEarly) {
     1568          iodEarly[prn] = stat.iodEarly;
     1569          maxEarly = max(maxEarly, stat.maxEarly);
     1570        }
     1571        if (stat.ephOutdated)  outdated[prn]   = stat.ephOutdated;
    15091572        if (stat.ephUnhealthy) unhealthy[prn]  = stat.ephUnhealthy;
    15101573        if (stat.noEph)        noEph[prn]      = stat.noEph;
    … …  
    15681631      addSats("phase biases missing (healthy broadcast ephemeris available)", missPB);
    15691632      addSats("corrections referring to an IOD of no received broadcast ephemeris", iodUnknown);
     1633      if (!iodEarly.isEmpty()) {
     1634        addSats(QString("corrections referring to an IOD received from the ephemeris stream(s) "
     1635                        "only later (up to %1 s)").arg(maxEarly, 0, 'f', 0), iodEarly);
     1636      }
     1637      addSats("corrections referring to a broadcast ephemeris outside its validity", outdated);
    15701638      addSats("corrections for unhealthy broadcast ephemeris", unhealthy);
    15711639      addSats("corrections for satellites without broadcast ephemeris", noEph);
  • trunk/BNC/src/ssrQc.h

    r11129 r11137  
    5959    unsigned      numClk;
    6060    unsigned      iodUnknown;    // IOD of no received broadcast ephemeris
     61    unsigned      iodEarly = 0;  // IOD received from the ephemeris stream(s) only later
     62    double        maxEarly = 0.0; // [s] largest delay of these
     63    unsigned      ephOutdated = 0; // broadcast ephemeris outside its validity
    6164    unsigned      ephUnhealthy;  // broadcast ephemeris unhealthy/bad
    6265    unsigned      noEph;         // no broadcast ephemeris at all
    … …  
    7780  void   newEpoch(const std::string& staID, char sys, e_type type, const bncTime& time,
    7881                  unsigned updateInt, const QString& prn);
    79   void   checkEph(t_satStat& stat, const QString& prnInt, unsigned iod, const bncTime& time,
    80                   const std::string& staID);
     82  void   checkEph(t_satStat& stat, const QString& satKey, const QString& prnInt, unsigned iod,
     83                  const bncTime& time, const std::string& staID);
    8184  void   checkInterval(const bncTime& time);
    8285  void   writeReport(bool final);
    … …  
    138141  QMap<QString, t_epoStat>  _epoStat;    // key "STA SYS TYPE"
    139142  QMap<QString, t_satStat>  _satStat;    // key "STA PRN"
     143  class t_pendingIod {       // IOD not (yet) received, key "STA PRN" and IOD
     144   public:
     145    QString  prnInt;         // internal PRN (with the Galileo F/NAV, I/NAV flag)
     146    bncTime  first;          // reception time of the first correction
     147    unsigned num = 0;        // corrections referring to it
     148  };
     149  QMap<QString, QMap<unsigned, t_pendingIod> > _pendingIod;
     150  void   resolvePendingIod(const QString& satKey, bool final);
    140151  QMap<QString, QSet<QString> > _codeSignals;  // key "STA SYS": signals with code biases
    141152  QMap<QString, QSet<QString> > _phaseSignals; // key "STA SYS": signals with phase biases
  • trunk/BNC/src/upload/bncephuploadcaster.cpp

    r10754 r11137  
    9292
    9393        if      (ephGPS && ephGPS->system() == t_eph::GPS  &&  (system == "ALL" || system.contains('G'))) {
    94           if (dt < 14400.0 || dt > -7200.0) {
     94          if (dt < 14400.0 && dt > -7200.0) {
    9595            size = t_ephEncoder::RTCM3(*ephGPS, Array);
    9696          }
    9797        }
    9898        else if (ephGPS && ephGPS->system() == t_eph::QZSS && (system == "ALL" || system.contains('J'))) {
    99           if (dt <  7200.0 || dt > -3600.0) {
     99          if (dt <  7200.0 && dt > -3600.0) {
    100100            size = t_ephEncoder::RTCM3(*ephGPS, Array);
    101101          }
    102102        }
    103103        else if (ephGlo && (system == "ALL" || system.contains('R'))) {
    104           if (dt <  3900.0 || dt > -2100.0) {
     104          if (dt <  3900.0 && dt > -2100.0) {
    105105            size = t_ephEncoder::RTCM3(*ephGlo, Array);
    106106          }
    107107        }
    108108        else if (ephGal && (system == "ALL" || system.contains('E'))) {
    109           if (dt < 14400.0 || dt >     0.0) {
     109          if (dt < 14400.0 && dt >     0.0) {
    110110            size = t_ephEncoder::RTCM3(*ephGal, Array);
    111111          }
    112112        }
    113113        else if (ephSBAS && (system == "ALL" || system.contains('S'))) {
    114           if (dt <   600.0 || dt >  -600.0) {
     114          if (dt <   600.0 && dt >  -600.0) {
    115115            size = t_ephEncoder::RTCM3(*ephSBAS, Array);
    116116          }
    117117        }
    118118        else if (ephBDS && (system == "ALL" || system.contains('C'))) {
    119           if (dt <  3900.0 || dt >     0.0) {
     119          if (dt <  3900.0 && dt >     0.0) {
    120120            size = t_ephEncoder::RTCM3(*ephBDS, Array);
    121121          }
    122122        }
    123123        else if (ephGPS && ephGPS->system() == t_eph::NavIC && (system == "ALL" || system.contains('I'))) {
    124           if (fabs(dt < 86400.0)) {
     124          if (fabs(dt) < 86400.0) {
    125125            size = t_ephEncoder::RTCM3(*ephGPS, Array);
    126126          }
  • trunk/BNC/tests/README.md

    r11136 r11137  
    5555  (ephemeris messages of BCEP00BKG0, SSRA00EUH0, FFMJ00DEU0, WTZR00DEU0 cut from the
    5656  merged capture): one RINEX 4 navigation file per stream.
     57* `replay_eph_cutover`: 02 on `data/eph_cutover_261023_20min.raw` (GPS ephemerides of
     58  BCEP00BKG0, BCEP01JPL0, BCEP00CAS0, 23 Oct 2026 01:05-01:25): the G17 upload within the
     59  fit interval (IOD 4, TOC 01:59:44, 16 s before IOD 148) is accepted, the data set mixed
     60  from both uploads (IODE 4, IODC 148) rejected.
    5761* `replay_save_sp3_has`: 14 with Galileo HAS (SSRA00EUH0) only; its epochs are
    5862  off the SP3/CLK sampling grid and are written at the preceding grid epoch.
    … …  
    97101  `data/combi_multi_261002_5min.raw`. `ssr_qc_bias` adds the CAS DCB file as
    98102  'QC Bias File' (code bias check against the other ACs and the file).
     103* `ssr_qc_iod`: IOD check of the SSR QC on `data/qc_iod_261015.raw` (made with
     104  `tools/mk_qc_iod.py` from the QC capture of 15 Oct 2026: BCEP00BKG0 with each message only
     105  at its first reception from 00:00, SSRA00WHU1/GMV1/CNE1 01:55-02:10): IODs received only
     106  later (WHU1), never received (GMV1 G16, upload not in BCEP00BKG0), ephemeris outside its
     107  validity (CNE1 GLONASS).
    99108
    100109* `decoder_limits`: crafted, CRC-valid frames from `tools/mkcrafted.py`
Note: See TracChangeset for help on using the changeset viewer.