Changeset 11137 in ntrip for trunk/BNC/src/ssrQc.cpp
- Timestamp:
- Oct 28, 2026, 9:48:01 PM (2 days ago)
- File:
-
- 1 edited
-
trunk/BNC/src/ssrQc.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/src/ssrQc.cpp
r11129 r11137 56 56 const double MAX_CLK_JUMP = 0.5; // [m] clock change beyond its rate between consecutive epochs 57 57 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 58 61 const double CMP_SAMPL = 30.0; // [s] sampling of the stream comparison 59 62 const double CMP_DELAY = 60.0; // [s] epochs compared when data this much newer arrived … … 119 122 //////////////////////////////////////////////////////////////////////////// 120 123 t_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) { 122 125 _dirName = dirName; 123 126 _reference = reference.isEmpty() ? QString("CONSENSUS") : reference; … … 359 362 // Broadcast ephemeris the correction refers to 360 363 //////////////////////////////////////////////////////////////////////////// 361 void t_ssrQc::checkEph(t_satStat& stat, const QString& prnInt, unsigned iod, constbncTime& time,362 const string& staID) { 364 void t_ssrQc::checkEph(t_satStat& stat, const QString& satKey, const QString& prnInt, 365 unsigned iod, const bncTime& time, const string& staID) { 363 366 // not before all broadcast ephemerides may have been received 364 367 if (time - _staStart[QString::fromStdString(staID)] < EPH_WARMUP) { 365 368 return; 366 369 } 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)) { 373 371 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; 377 389 } 378 390 else if (eph->checkState() == t_eph::unhealthy || eph->checkState() == t_eph::bad) { 379 391 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 //////////////////////////////////////////////////////////////////////////// 405 void 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); 380 429 } 381 430 } … … 395 444 t_satStat& stat = _satStat[QString::fromStdString(corr._staID) + ' ' + prn]; 396 445 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); 398 448 double radial = fabs(corr._xr[0]); 399 449 double alongCross = max(fabs(corr._xr[1]), fabs(corr._xr[2])); … … 417 467 t_satStat& stat = _satStat[QString::fromStdString(corr._staID) + ' ' + prn]; 418 468 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); 420 471 421 472 // jump: change between consecutive epochs (same IOD) beyond the clock rate … … 837 888 } 838 889 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 } 844 894 if (!eph || clk._iod != orb._iod) { 845 895 continue; … … 1363 1413 bncTime endTime = final ? _lastTime : _intervalStart + _interval; 1364 1414 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 1365 1421 // Healthy and current broadcast ephemerides per system 1366 1422 QMap<char, QSet<QString> > ephSats; … … 1475 1531 continue; 1476 1532 } 1533 QMap<QString, unsigned> iodEarly, outdated; 1534 double maxEarly = 0.0; 1477 1535 QMap<QString, unsigned> missOrb, missClk, missCB, missPB, iodUnknown, unhealthy, noEph, 1478 1536 jumps, missRef, noYaw, yawPartly; … … 1507 1565 const t_satStat& stat = itSat.value(); 1508 1566 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; 1509 1572 if (stat.ephUnhealthy) unhealthy[prn] = stat.ephUnhealthy; 1510 1573 if (stat.noEph) noEph[prn] = stat.noEph; … … 1568 1631 addSats("phase biases missing (healthy broadcast ephemeris available)", missPB); 1569 1632 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); 1570 1638 addSats("corrections for unhealthy broadcast ephemeris", unhealthy); 1571 1639 addSats("corrections for satellites without broadcast ephemeris", noEph);
Note:
See TracChangeset
for help on using the changeset viewer.
