Changeset 11047 in ntrip
- Timestamp:
- Sep 28, 2026, 11:17:34 AM (3 hours ago)
- Location:
- trunk/BNC/src
- Files:
-
- 19 edited
-
PPP/pppEphPool.cpp (modified) (3 diffs)
-
PPP/pppEphPool.h (modified) (1 diff)
-
PPP/pppObsPool.cpp (modified) (3 diffs)
-
PPP/pppSatObs.cpp (modified) (7 diffs)
-
RTCM3/RTCM3Decoder.cpp (modified) (11 diffs)
-
RTCM3/RTCM3Decoder.h (modified) (1 diff)
-
RTCM3/RTCM3coDecoder.cpp (modified) (13 diffs)
-
RTCM3/RTCM3coDecoder.h (modified) (3 diffs)
-
bncantex.cpp (modified) (3 diffs)
-
bncantex.h (modified) (2 diffs)
-
bncephuser.cpp (modified) (2 diffs)
-
bncephuser.h (modified) (1 diff)
-
bncrinex.cpp (modified) (2 diffs)
-
combination/bnccomb.cpp (modified) (2 diffs)
-
pppRun.cpp (modified) (1 diff)
-
satObs.cpp (modified) (12 diffs)
-
satObs.h (modified) (6 diffs)
-
t_prn.cpp (modified) (1 diff)
-
t_prn.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/src/PPP/pppEphPool.cpp
r10953 r11047 20 20 #include "pppInclude.h" 21 21 #include "pppClient.h" 22 #include "bncephuser.h" 22 23 23 24 using namespace BNC_PPP; … … 26 27 // 27 28 ///////////////////////////////////////////////////////////////////////////// 29 // Bad, outdated and unhealthy ephemerides are never used. Ephemerides from 30 // RINEX navigation files (post-processing) never pass bncEphUser's checks and 31 // stay "unchecked", so the health flag and the plausibility of the satellite 32 // distance are checked here directly as well. 33 ///////////////////////////////////////////////////////////////////////////// 28 34 void t_pppEphPool::putEphemeris(t_eph* eph) { 29 if (eph && (eph->checkState() != t_eph::bad || 30 eph->checkState() != t_eph::unhealthy || 31 eph->checkState() != t_eph::outdated)) { 32 _satEphPool[eph->prn().toInt()].putEphemeris(_maxQueueSize, eph); 35 if (!eph) { 36 return; 37 } 38 int iPrn = eph->prn().toInt(); 39 if (iPrn == 0) { // satellite number out of range 40 delete eph; 41 } 42 else if (eph->checkState() == t_eph::unhealthy || eph->isUnhealthy()) { 43 _satEphPool[iPrn].setUnhealthy(eph); 44 } 45 else if (eph->checkState() == t_eph::unchecked && !bncEphUser::radialDistanceOk(eph)) { 46 LOG << "bad ephemeris " << eph->prn().toString() << ' ' << string(eph->TOC()) 47 << " - implausible satellite distance, ignored" << endl; 48 delete eph; 49 } 50 else if (eph->checkState() != t_eph::bad && 51 eph->checkState() != t_eph::outdated) { 52 _satEphPool[iPrn].putEphemeris(_maxQueueSize, eph); 33 53 } 34 54 else { … … 87 107 delete eph; 88 108 } 109 } 110 111 // A newer ephemeris declaring the satellite unhealthy: rejecting it alone 112 // would leave the older, healthy ephemerides in the pool, and the satellite 113 // would still be used with them - so they are all discarded, and the 114 // satellite stays unused until a newer healthy ephemeris arrives. 115 ///////////////////////////////////////////////////////////////////////////// 116 void t_pppEphPool::t_satEphPool::setUnhealthy(t_eph* eph) { 117 if (_ephs.empty() || eph->isNewerThan(_ephs.front())) { 118 if (!_ephs.empty()) { 119 LOG << "unhealthy ephemeris " << eph->prn().toString() << ' ' << string(eph->TOC()) 120 << " - older ephemerides of this satellite discarded" << endl; 121 } 122 for (unsigned ii = 0; ii < _ephs.size(); ii++) { 123 delete _ephs[ii]; 124 } 125 _ephs.clear(); 126 } 127 delete eph; 89 128 } 90 129 -
trunk/BNC/src/PPP/pppEphPool.h
r8401 r11047 41 41 } 42 42 void putEphemeris(unsigned maxQueueSize, t_eph* eph); 43 void setUnhealthy(t_eph* eph); 43 44 void putOrbCorrection(t_orbCorr* corr); 44 45 void putClkCorrection(t_clkCorr* corr); -
trunk/BNC/src/PPP/pppObsPool.cpp
r11041 r11047 82 82 void t_pppObsPool::putCodeBias(t_satCodeBias* satCodeBias) { 83 83 int iPrn = satCodeBias->_prn.toInt(); 84 if (iPrn == 0) { // satellite number out of range 85 delete satCodeBias; 86 return; 87 } 84 88 delete _satCodeBiases[iPrn]; 85 89 _satCodeBiases[iPrn] = satCodeBias; … … 97 101 void t_pppObsPool::putPhaseBias(t_satPhaseBias* satPhaseBias) { 98 102 int iPrn = satPhaseBias->_prn.toInt(); 103 if (iPrn == 0) { // satellite number out of range 104 delete satPhaseBias; 105 return; 106 } 99 107 delete _satPhaseBiases[iPrn]; 100 108 _satPhaseBiases[iPrn] = satPhaseBias; … … 122 130 void t_pppObsPool::putSatAntenna(t_satAntenna* satAntenna) { 123 131 int iPrn = satAntenna->_prn.toInt(); 132 if (iPrn == 0) { // satellite number out of range 133 delete satAntenna; 134 return; 135 } 124 136 delete _satAntennas[iPrn]; 125 137 _satAntennas[iPrn] = satAntenna; -
trunk/BNC/src/PPP/pppSatObs.cpp
r11042 r11047 400 400 401 401 402 // A system's Satellite Antenna message is only trustworthy once the 403 // provider has confirmed it via Metadata: SatelliteAntennaIOD (DF+010) must 404 // be non-zero, and must match the Data IOD (DF+069) of a Metadata entry for 405 // model-correction type 1 (satellite antenna PCV) or type 2 (GDV) - either 406 // entry matching is sufficient. Metadata carries this IOD once globally, not 407 // per system (DF+010 is GNSS-specific, DF+069 is not), so the same Metadata 408 // entries are reused as the trust anchor for every system's check - the 409 // provider is relied on to keep DF+010 synchronized with DF+069 across all 410 // systems for this to work. 402 // Satellite Antenna IOD referenced by the SSR Metadata: the Data IOD (DF+069) 403 // of the model-correction entry of type 1 (satellite antenna PCV) or type 2 404 // (GDV). refIOD = 0 if Metadata references no antenna information (no 405 // Metadata, no such entry, no Data IOD, or a zero Data IOD). A provider's 406 // solution is relative to one Satellite Antenna information only, so two 407 // different non-zero IODs are inconsistent: returns false in that case. 408 // 409 // A non-zero reference means the provider's biases, and orbits/clocks, are 410 // relative to exactly that Satellite Antenna information, so the client 411 // must apply it and nothing else (see t_pppSatObs::cmpModel()). 412 //////////////////////////////////////////////////////////////////////////// 413 static bool ssrSatAntennaRefIOD(const t_metaData* metaData, unsigned int& refIOD) { 414 refIOD = 0; 415 if (!metaData) { 416 return true; 417 } 418 for (unsigned ii = 0; ii < metaData->_entries.size(); ii++) { 419 const t_metaDataEntry& entry = metaData->_entries[ii]; 420 if ((entry._typeIndicator == 1 || entry._typeIndicator == 2) && // PCV or GDV 421 entry._dataIODIndicator && entry._dataIOD != 0) { 422 if (refIOD != 0 && refIOD != entry._dataIOD) { 423 return false; 424 } 425 refIOD = entry._dataIOD; 426 } 427 } 428 return true; 429 } 430 431 // Whether cached Satellite Antenna data is the information referenced by 432 // Metadata (refIOD, from ssrSatAntennaRefIOD()). SatelliteAntennaIOD (DF+010) 433 // must be non-zero and equal refIOD. Metadata carries this IOD once globally, 434 // not per system (DF+010 is GNSS-specific, DF+069 is not), so the same 435 // Metadata entries are reused for every system's check - the provider is 436 // relied on to keep DF+010 synchronized with DF+069 across all systems. 437 // 438 // The IOD is also unique only per SSR Provider ID (DF414), so the Metadata 439 // must come from the same provider as the Antenna message - antenna data may 440 // be taken from the bias mountpoint while Metadata comes from the 441 // corrections mountpoint (see pppRun.cpp). 411 442 // 412 443 // Separately, providers only guarantee SatelliteAntennaIOD uniqueness within … … 414 445 // has been without a fresh Antenna message for that system for 64 days or 415 446 // more must treat any cached data as unverifiable and stop using it, even 416 // if the IOD/Metadata check above would otherwise pass - the same IOD value 417 // could by then legitimately mean something else. epoTime is the current 418 // processing epoch, compared against t_satAntenna::_time (when this data 419 // was actually decoded, not a wire epoch - the message carries none). 420 //////////////////////////////////////////////////////////////////////////// 421 static bool ssrSatAntennaTrusted(const t_satAntenna* satAntenna, const bncTime& epoTime) { 447 // if the IOD check above would otherwise pass - the same IOD value could by 448 // then legitimately mean something else. epoTime is the current processing 449 // epoch, compared against t_satAntenna::_time (when this data was last 450 // received, to within the decoder's re-emit interval - not a wire epoch, 451 // the message carries none; see RTCM3coDecoder::sendResults()). 452 //////////////////////////////////////////////////////////////////////////// 453 static bool ssrSatAntennaTrusted(const t_satAntenna* satAntenna, const t_metaData* metaData, 454 unsigned int refIOD, const bncTime& epoTime) { 422 455 const double MAX_AGE_SEC = 64.0 * 86400.0; 423 if (!satAntenna || satAntenna->_satelliteAntennaIOD == 0) { 456 if (!satAntenna || !metaData || refIOD == 0 || 457 satAntenna->_satelliteAntennaIOD != refIOD || 458 satAntenna->_ssrProviderID != metaData->_providerID) { 424 459 return false; 425 460 } … … 428 463 return false; 429 464 } 430 const t_metaData* metaData = PPP_CLIENT->obsPool()->metaData(); 431 if (!metaData) { 432 return false; 433 } 434 for (unsigned ii = 0; ii < metaData->_entries.size(); ii++) { 435 const t_metaDataEntry& entry = metaData->_entries[ii]; 436 if ((entry._typeIndicator == 1 || entry._typeIndicator == 2) && // PCV or GDV 437 entry._dataIODIndicator && 438 entry._dataIOD == satAntenna->_satelliteAntennaIOD) { 439 return true; 440 } 441 } 442 return false; 465 return true; 443 466 } 444 467 445 468 // Satellite antenna correction (offset + nadir-angle-dependent PCV) from a 446 469 // live SSR Satellite Antenna message, in the same additive sense as 447 // bncAntex::satCorr(). Returns false (corr untouched) if no trusted SSR data 448 // is available for this PRN/frequency (see ssrSatAntennaTrusted), so the 449 // caller falls back to the static ANTEX file. 470 // bncAntex::satCorr(). Returns false (corr untouched) if the data contains 471 // no entry for this frequency. 450 472 //////////////////////////////////////////////////////////////////////////// 451 473 static bool ssrSatAntennaCorr(const t_satAntenna* satAntenna, const string& frqStr, … … 472 494 else if (idx >= (int)frq._nadirAngleCorrection.size()) { 473 495 idx = (int)frq._nadirAngleCorrection.size() - 1; 496 } 497 if (std::isnan(frq._nadirAngleCorrection[idx])) { 498 return false; // invalid value (DF+021 = -2^(n-1)) at this nadir angle 474 499 } 475 500 corr += frq._nadirAngleCorrection[idx]; … … 555 580 // Antenna Phase Center Offsets and Variations 556 581 // ------------------------------------------- 582 // If SSR Metadata references Satellite Antenna information (non-zero IOD), 583 // the provider's biases are relative to exactly that information, so it 584 // is the only satellite antenna model applied - never mixed with ANTEX: 585 // phaseranges get the SSR correction if the Phase Center indicator 586 // (DF+011) is set, otherwise zero; pseudoranges likewise with the Group 587 // Delay indicator (DF+012). Zero values are part of that information 588 // (explicitly encoded, or DF+019/DF+013 not set); omitting a satellite or 589 // frequency within a constellation is not a valid way to signal zero. So 590 // if the referenced information is not (yet) available for this satellite, 591 // or lacks a frequency the PPP linear combinations need, the satellite is 592 // excluded rather than corrected with ANTEX. Without such a reference, 593 // the static ANTEX file is used for both observables. 557 594 if (PPP_CLIENT->antex()) { 595 const t_metaData* metaData = PPP_CLIENT->obsPool()->metaData(); 558 596 const t_satAntenna* satAntenna = PPP_CLIENT->obsPool()->satAntenna(_prn); 559 if (!ssrSatAntennaTrusted(satAntenna, _time)) { 560 satAntenna = 0; // untrusted (IOD zero, or not confirmed via Metadata) - fall back to ANTEX 561 } 597 unsigned int refIOD; 598 if (!ssrSatAntennaRefIOD(metaData, refIOD)) { 599 LOG << "SSR Metadata references different Satellite Antenna IODs (PCV/GDV) - " 600 << _prn.toString() << " excluded" << endl; 601 return failure; 602 } 603 bool useSsr = (refIOD != 0); 604 if (useSsr && !ssrSatAntennaTrusted(satAntenna, metaData, refIOD, _time)) { 605 LOG << "SSR Satellite Antenna IOD " << refIOD << " referenced by Metadata not available for " 606 << _prn.toString() << " - satellite excluded" << endl; 607 return failure; 608 } 609 610 bool phaseMissing[t_frequency::max] = {}; 611 bool codeMissing[t_frequency::max] = {}; 612 562 613 for (unsigned ii = 0; ii < t_frequency::max; ii++) { 563 614 t_frequency::type frqType = static_cast<t_frequency::type>(ii); … … 568 619 _model._antPCO[ii] = PPP_CLIENT->antex()->rcvCorr(station->antName(), frqType, _model._eleSat, _model._azSat, found); 569 620 570 // Prefer a live, trusted SSR Satellite Antenna correction over the 571 // static ANTEX file when available for this satellite/frequency, 572 // mirroring how SSR orbit/clock corrections already take precedence 573 // over broadcast ephemerides elsewhere in this codebase. Unlike 574 // ANTEX's satCorr() (a single geometric PCO/PCV value shared by code 575 // and phase alike), the SSR message's DF+011/DF+012 indicators say 576 // explicitly which observable(s) the correction applies to, so it is 577 // routed into the dedicated phase-only/code-only fields instead of 578 // the shared _antPCO - both may fire for the same ssrCorr value if 579 // both indicators are set. 580 double ssrCorr; 581 if (ssrSatAntennaCorr(satAntenna, frqStr, _model._elTx, ssrCorr)) { 582 if (satAntenna->_phaseCenterInfoInd) { 583 _model._antPCV[ii] += ssrCorr; 584 } 585 if (satAntenna->_groupDelayInfoInd) { 586 _model._antGDV[ii] += ssrCorr; 621 if (useSsr) { 622 // Unlike ANTEX's satCorr() (a single geometric PCO/PCV value shared 623 // by code and phase alike), DF+011/DF+012 say explicitly which 624 // observable(s) the correction applies to, so it is routed into the 625 // dedicated phase-only/code-only fields instead of the shared _antPCO. 626 // BDS 1207.14 MHz: B2 (BDS-2, "C7") or B2b (BDS-3, "C7b") - a 627 // satellite transmits only one of them. The entry of the satellite's 628 // own generation is preferred, taken from the ANTEX block type valid 629 // at this epoch (PRNs have been reassigned from BDS-2 to BDS-3). 630 // Since antenna corrections depend on the carrier, not the signal, 631 // the other entry is used as fallback if the own one is missing; if 632 // the generation is unknown, an entry is used only if unambiguous 633 // (just one present, or both equal). 634 // PRELIMINARY - pending clarification by RTCM SC-104 whether B2 and 635 // B2b entries of one satellite are meant to be identical; to revert 636 // to the strict selection, drop the fallback branches below. 637 double ssrCorr = 0.0; 638 bool ssrOK = false; 639 if (frqStr == "C7") { 640 double corrB2 = 0.0, corrB2b = 0.0; 641 bool hasB2 = ssrSatAntennaCorr(satAntenna, "C7", _model._elTx, corrB2); 642 bool hasB2b = ssrSatAntennaCorr(satAntenna, "C7b", _model._elTx, corrB2b); 643 QString blockType = PPP_CLIENT->antex()->satBlockType(prn, _time); 644 if (blockType.startsWith("3")) { // BDS-3: B2b, fallback B2 645 ssrOK = hasB2b || hasB2; 646 ssrCorr = hasB2b ? corrB2b : corrB2; 647 } 648 else if (blockType.startsWith("2")) { // BDS-2: B2, fallback B2b 649 ssrOK = hasB2 || hasB2b; 650 ssrCorr = hasB2 ? corrB2 : corrB2b; 651 } 652 else if (hasB2 != hasB2b || (hasB2 && corrB2 == corrB2b)) { // generation unknown 653 ssrOK = true; 654 ssrCorr = hasB2 ? corrB2 : corrB2b; 655 } 656 } 657 else { 658 ssrOK = ssrSatAntennaCorr(satAntenna, frqStr, _model._elTx, ssrCorr); 659 } 660 if (ssrOK) { 661 if (satAntenna->_phaseCenterInfoInd) { 662 _model._antPCV[ii] += ssrCorr; 663 } 664 if (satAntenna->_groupDelayInfoInd) { 665 _model._antGDV[ii] += ssrCorr; 666 } 667 } 668 else { 669 phaseMissing[ii] = satAntenna->_phaseCenterInfoInd; 670 codeMissing[ii] = satAntenna->_groupDelayInfoInd; 587 671 } 588 672 } … … 604 688 _model._antPCO[ii] -= PPP_CLIENT->antex()->satCorr(prn, t_frequency::C2, _model._elTx, _model._azTx, found); 605 689 } 690 } 691 } 692 } 693 694 // If the SSR antenna information applies to both observables (both 695 // DF+011 and DF+012 set), the code and phase biases must come from the 696 // same SSR solution (same SSR IOD and Provider ID), otherwise they are 697 // not consistent with each other with respect to it. Only checked if 698 // phase biases are used and both IODs are known. 699 if (useSsr && satAntenna->_phaseCenterInfoInd && satAntenna->_groupDelayInfoInd && 700 OPT->arSystem(_prn.system())) { 701 const t_satCodeBias* satCodeBias = PPP_CLIENT->obsPool()->satCodeBias(_prn); 702 const t_satPhaseBias* satPhaseBias = PPP_CLIENT->obsPool()->satPhaseBias(_prn); 703 if (satCodeBias && satPhaseBias && 704 satCodeBias->_ssrIOD >= 0 && satPhaseBias->_ssrIOD >= 0 && 705 (satCodeBias->_ssrIOD != satPhaseBias->_ssrIOD || 706 satCodeBias->_ssrProviderID != satPhaseBias->_ssrProviderID)) { 707 LOG << "SSR code bias (IOD " << satCodeBias->_ssrIOD << ", provider " << satCodeBias->_ssrProviderID 708 << ") and phase bias (IOD " << satPhaseBias->_ssrIOD << ", provider " << satPhaseBias->_ssrProviderID 709 << ") inconsistent for " << _prn.toString() << " with shared SSR Satellite Antenna information" 710 << " - satellite excluded" << endl; 711 return failure; 712 } 713 } 714 715 // Exclude the satellite if the referenced antenna information omits a 716 // frequency actually used by the linear combinations of this system 717 const vector<t_lc>& LCs = OPT->LCs(_prn.system()); 718 for (unsigned iLC = 0; iLC < LCs.size(); iLC++) { 719 map<t_frequency::type, double> codeCoeff; 720 map<t_frequency::type, double> phaseCoeff; 721 map<t_frequency::type, double> ionoCoeff; 722 lcCoeff(LCs[iLC], codeCoeff, phaseCoeff, ionoCoeff); 723 map<t_frequency::type, double>::const_iterator it; 724 for (it = phaseCoeff.begin(); it != phaseCoeff.end(); it++) { 725 if (phaseMissing[it->first]) { 726 LOG << "SSR Satellite Antenna IOD " << refIOD << " has no valid entry for " 727 << _prn.toString() << ' ' << t_frequency::toString(it->first) << " (phase) - satellite excluded" << endl; 728 return failure; 729 } 730 } 731 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) { 732 if (codeMissing[it->first]) { 733 LOG << "SSR Satellite Antenna IOD " << refIOD << " has no valid entry for " 734 << _prn.toString() << ' ' << t_frequency::toString(it->first) << " (code) - satellite excluded" << endl; 735 return failure; 606 736 } 607 737 } -
trunk/BNC/src/RTCM3/RTCM3Decoder.cpp
r11043 r11047 141 141 flag = t_corrSSR::getSsrNavTypeFlag(sys, num); 142 142 CurrentObs._prn.set(sys, num, flag); 143 checkPrnRange(CurrentObs._prn); 143 144 144 145 t_frqObs *frqObs = new t_frqObs; … … 723 724 else 724 725 CurrentObs._prn.set(sys, RTCM3_MSM_NUMSAT - i); 726 checkPrnRange(CurrentObs._prn); 725 727 j = RTCM3_MSM_NUMSIG; 726 728 while (!(sigmask & (1 << --j))) … … 954 956 int flag = t_corrSSR::getSsrNavTypeFlag(sys, sv); 955 957 CurrentObs._prn.set(sys, sv, flag); 958 checkPrnRange(CurrentObs._prn); 956 959 GETBITS(code, 1) 957 960 GETBITS(freq, 5) 958 GLOFreq[sv - 1] = 100 + freq - 7; /* store frequency for other users (MSM) */ 961 if (sv >= 1) { /* 6-bit slot 1..63 fits GLOFreq[64]; 0 is invalid */ 962 GLOFreq[sv - 1] = 100 + freq - 7; /* store frequency for other users (MSM) */ 963 } 959 964 960 965 t_frqObs *frqObs = new t_frqObs; … … 1066 1071 } 1067 1072 eph._prn.set('G', i); 1073 checkPrnRange(eph._prn); 1068 1074 GETBITS(week, 10) 1069 1075 if (week < 0 || week > 1023) { … … 1185 1191 } 1186 1192 eph._prn.set('R', sv); 1193 checkPrnRange(eph._prn); 1187 1194 1188 1195 GETBITS(i, 5) … … 1373 1380 } 1374 1381 eph._prn.set('J', i); 1382 checkPrnRange(eph._prn); 1375 1383 1376 1384 GETBITS(i, 16) … … 1493 1501 } 1494 1502 eph._prn.set('I', i); 1503 checkPrnRange(eph._prn); 1495 1504 GETBITS(week, 10) 1496 1505 if (week < 0 || week > 1023) { … … 1627 1636 } 1628 1637 eph._prn.set('S', 20 + i); 1638 checkPrnRange(eph._prn); 1629 1639 GETBITS(eph._IODN, 8) 1630 1640 GETBITS(i, 13) … … 1716 1726 } 1717 1727 eph._prn.set('E', i, eph._inav ? t_eph::INAV : t_eph::FNAV); 1728 checkPrnRange(eph._prn); 1718 1729 1719 1730 GETBITS(week, 12) //FIXME: roll-over after week 4095!! … … 1863 1874 } 1864 1875 eph._prn.set('C', i); 1876 checkPrnRange(eph._prn); 1865 1877 1866 1878 GETBITS(week, 13) … … 2439 2451 } 2440 2452 2441 2442 2443 2453 // Satellite numbers on the wire can exceed BNC's supported range (e.g. 6-bit 2454 // IDs up to 63, while t_prn supports G01-G32). They are passed on unchanged, 2455 // but t_prn::toInt() maps them to the unused index 0, so they are not usable 2456 // for per-satellite processing - report that once per satellite. 2457 //////////////////////////////////////////////////////////////////////////// 2458 void RTCM3Decoder::checkPrnRange(const t_prn& prn) { 2459 if (prn.toInt() != 0) { 2460 return; 2461 } 2462 QString prnStr = QString::fromStdString(prn.toString()); 2463 if (!_prnOutOfRangeLogged.contains(prnStr)) { 2464 _prnOutOfRangeLogged.insert(prnStr); 2465 emit newMessage(QString("%1: satellite %2 outside the range supported by BNC - not usable for processing") 2466 .arg(_staID).arg(prnStr).toLatin1(), true); 2467 } 2468 } -
trunk/BNC/src/RTCM3/RTCM3Decoder.h
r11024 r11047 60 60 61 61 private: 62 // Log (once per satellite) a satellite number outside BNC's supported 63 // range (t_prn::MAXPRN_*); such satellites map to the unused index 0. 64 void checkPrnRange(const t_prn& prn); 65 QSet<QString> _prnOutOfRangeLogged; 62 66 /** 63 67 * Extract a RTCM3 message. Data is passed in the follow fields:<br> -
trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp
r11041 r11047 105 105 106 106 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 107 _antennaSentIOD[s] = UINT_MAX; // "never sent" 107 _antennaReceived[s] = false; 108 _antennaIODKnown[s] = false; 109 _antennaIODProvider[s] = 0; 110 _antennaIODCur[s] = 0; 111 _antennaIODPrev[s] = 0; 112 } 113 for (unsigned i = 0; i < CLOCKORBIT_COUNTSAT; i++) { 114 _antennaSentProviderID[i] = 0; 115 _antennaSentIOD[i] = 0; // meaningless while _antennaSentTime[i] is invalid ("never sent") 108 116 } 109 117 … … 203 211 memcpy(&_stateSnapshot->antenna, &_antenna, sizeof(_antenna)); 204 212 213 // _antenna persists across messages, so its content alone can't tell 214 // whether a Satellite Antenna message arrived in this frame (an unchanged 215 // retransmission looks identical). Clear messageType[] as a marker: the 216 // COBOFS_SATANT decoder sets it (always non-zero) for each system it 217 // decodes. Restored with the snapshot if the frame turns out incomplete. 218 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 219 _antenna.messageType[s] = 0; 220 } 221 205 222 int bytesused = 0; 206 223 … … 240 257 241 258 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) { 259 // Latch the reception until sendResults() consumes it - it may not 260 // run for this frame if _lastTime is still invalid. 261 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) { 262 if (_antenna.messageType[s] != 0) { 263 _antennaReceived[s] = true; 264 checkAntennaIOD(s); 265 } 266 } 242 267 setEpochTime(); // sets _lastTime 243 268 … … 342 367 t_orbCorr orbCorr; 343 368 orbCorr._prn.set(sys, num, flag); 369 checkPrnRange(orbCorr._prn); 344 370 orbCorr._staID = _staID.toStdString(); 345 371 orbCorr._iod = _clkOrb.Sat[ii].IOD; … … 378 404 t_clkCorr clkCorr; 379 405 clkCorr._prn.set(sys, _clkOrb.Sat[ii].ID, flag); 406 checkPrnRange(clkCorr._prn); 380 407 clkCorr._staID = _staID.toStdString(); 381 408 clkCorr._time = _lastTime; … … 470 497 t_satCodeBias satCodeBias; 471 498 satCodeBias._prn.set(sys, num, flag); 499 checkPrnRange(satCodeBias._prn); 472 500 satCodeBias._staID = _staID.toStdString(); 473 501 satCodeBias._time = _lastTime; 474 502 satCodeBias._updateInt = _codeBias.UpdateInterval; 503 satCodeBias._ssrIOD = _codeBias.SSRIOD; 504 satCodeBias._ssrProviderID = _codeBias.SSRProviderID; 475 505 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) { 476 506 const SsrCorr::CodeBias::BiasSat::CodeBiasEntry& biasEntry = _codeBias.Sat[ii].Biases[jj]; … … 560 590 t_satPhaseBias satPhaseBias; 561 591 satPhaseBias._prn.set(sys, num, flag); 592 checkPrnRange(satPhaseBias._prn); 562 593 satPhaseBias._staID = _staID.toStdString(); 563 594 satPhaseBias._time = _lastTime; 564 595 satPhaseBias._updateInt = _phaseBias.UpdateInterval; 596 satPhaseBias._ssrIOD = _phaseBias.SSRIOD; 597 satPhaseBias._ssrProviderID = _phaseBias.SSRProviderID; 565 598 satPhaseBias._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld : 566 599 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown; … … 649 682 // _antenna, like _metaData, carries no epoch field of its own and is never 650 683 // wiped by reset(), so each system's data persists across unrelated 651 // messages. _antennaSentIOD tracks the last SatelliteAntennaIOD actually 652 // emitted per system, so unrelated messages (and unchanged retransmissions 653 // of the same antenna data) don't cause duplicate output - the same 654 // freshness problem _phaseBiasSentEpoch solves for phase biases. 684 // messages. Only a system for which an Antenna message was actually 685 // received (_antennaReceived, latched in Decode()) is considered, so 686 // persisted data is never re-stamped with a newer time. 687 // 688 // The SatelliteAntennaIOD is unique only per SSR Provider ID (DF414) and 689 // only within 64 days, and a client that has not received the stream for 690 // 64 days must discard cached antenna data (enforced downstream against 691 // t_satAntenna::_time, see ssrSatAntennaTrusted() in pppSatObs.cpp). So an 692 // unchanged (provider ID, IOD) retransmission is suppressed only if it was 693 // last emitted less than ANT_REFRESH_SEC ago. Re-emitting it after that 694 // keeps _time close to the last reception - not the first - so continuously 695 // received data never ages out. It also means a reception after a long 696 // gap is always emitted, even when the provider has legitimately reused 697 // the IOD for different content, and each .ssr file contains the antenna 698 // data at least once per refresh interval. 699 // 700 // This is tracked per satellite, not per system: providers may split a 701 // system's satellites across several messages with rotating satellite 702 // masks (DF394), all carrying the same IOD - a per-system check would 703 // emit only whichever subset happened to arrive first. 655 704 { 705 const double ANT_REFRESH_SEC = 3600.0; 656 706 struct SysInfo { unsigned sysIdx; char sysChar; unsigned numSat; unsigned offset; }; 657 707 const SysInfo sysInfos[] = { … … 664 714 for (const SysInfo& si : sysInfos) { 665 715 unsigned s = si.sysIdx; 666 if (_antenna.SatelliteAntennaIOD[s] == _antennaSentIOD[s]) { 667 continue; // nothing new for this system since the last emit 668 } 716 if (!_antennaReceived[s]) { 717 continue; // no Antenna message received for this system since the last check 718 } 719 _antennaReceived[s] = false; 669 720 if (_antenna.SatelliteMask[s] == 0) { 670 continue; // this system's antenna data was never decoded721 continue; // no satellites in this system's antenna data 671 722 } 672 723 for (unsigned k = 0; k < si.numSat; k++) { … … 674 725 continue; 675 726 } 727 unsigned i = si.offset + k; 728 if (_antennaSentTime[i].valid() && 729 _antenna.SSRProviderID[s] == _antennaSentProviderID[i] && 730 _antenna.SatelliteAntennaIOD[s] == _antennaSentIOD[i] && 731 _lastTime - _antennaSentTime[i] < ANT_REFRESH_SEC) { 732 continue; // unchanged retransmission, emitted recently 733 } 734 _antennaSentProviderID[i] = _antenna.SSRProviderID[s]; 735 _antennaSentIOD[i] = _antenna.SatelliteAntennaIOD[s]; 736 _antennaSentTime[i] = _lastTime; 676 737 int num = k + 1; // PRN within this system, DF394 MSB-first convention 677 738 int flag = 0; … … 696 757 satAntenna._nadirAngleRangeExtension = _antenna.NadirAngleDependentCorrectionRangeExtension[s]; 697 758 698 const SsrCorr::Antenna::SatellitePart& satPart = _antenna.Sat[ si.offset + k];759 const SsrCorr::Antenna::SatellitePart& satPart = _antenna.Sat[i]; 699 760 for (unsigned f = 0; f < ANT_MAXFREQUENCIES; f++) { 700 761 if (!((satPart.GnssFrequencyMask >> (ANT_MAXFREQUENCIES - 1 - f)) & 1U)) { … … 718 779 _satAntennas[_lastTime].append(satAntenna); 719 780 } 720 _antennaSentIOD[s] = _antenna.SatelliteAntennaIOD[s];721 781 } 722 782 } … … 1109 1169 } 1110 1170 } 1171 1172 // Satellite numbers on the wire can exceed BNC's supported range (e.g. 6-bit 1173 // IDs up to 63, while t_prn supports G01-G32). They are passed on unchanged, 1174 // but t_prn::toInt() maps them to the unused index 0, so they are not usable 1175 // for per-satellite processing - report that once per satellite. 1176 //////////////////////////////////////////////////////////////////////////// 1177 void RTCM3coDecoder::checkPrnRange(const t_prn& prn) { 1178 if (prn.toInt() != 0) { 1179 return; 1180 } 1181 QString prnStr = QString::fromStdString(prn.toString()); 1182 if (!_prnOutOfRangeLogged.contains(prnStr)) { 1183 _prnOutOfRangeLogged.insert(prnStr); 1184 emit newMessage(QString("%1: satellite %2 outside the range supported by BNC - not usable for processing") 1185 .arg(_staID).arg(prnStr).toLatin1(), true); 1186 } 1187 } 1188 1189 // All Satellite Antenna messages of one GNSS must use the same Satellite 1190 // Antenna IOD (a satellite set may be split over several messages). During 1191 // a legitimate IOD change old and new IOD are both seen for a while, until 1192 // every message has been sent with the new one - but the IOD never returns 1193 // to a replaced value within 64 days (uniqueness per SSR Provider ID), so a 1194 // switch back to the replaced IOD within that period reveals messages of the 1195 // same GNSS using different IODs. Reported once per GNSS and IOD pair; the 1196 // data itself is not changed (PPP checks each satellite's IOD individually). 1197 //////////////////////////////////////////////////////////////////////////// 1198 void RTCM3coDecoder::checkAntennaIOD(unsigned s) { 1199 const double MAX_AGE_SEC = 64.0 * 86400.0; 1200 unsigned int iod = _antenna.SatelliteAntennaIOD[s]; 1201 unsigned int provider = _antenna.SSRProviderID[s]; 1202 1203 int currentWeek = 0; 1204 double currentSec = 0.0; 1205 currentGPSWeeks(currentWeek, currentSec); 1206 bncTime currentTime(currentWeek, currentSec); 1207 1208 if (!_antennaIODKnown[s] || provider != _antennaIODProvider[s]) { 1209 _antennaIODKnown[s] = true; 1210 _antennaIODProvider[s] = provider; 1211 _antennaIODCur[s] = iod; 1212 _antennaIODPrevTime[s].reset(); // no replaced IOD yet 1213 return; 1214 } 1215 if (iod == _antennaIODCur[s]) { 1216 return; 1217 } 1218 if (_antennaIODPrevTime[s].valid() && iod == _antennaIODPrev[s] && 1219 currentTime - _antennaIODPrevTime[s] < MAX_AGE_SEC) { 1220 const char sysChars[CLOCKORBIT_SATNUM] = {'G', 'R', 'E', 'J', 'S', 'C'}; 1221 char sys = (s < CLOCKORBIT_SATNUM) ? sysChars[s] : '?'; 1222 QString key = QString("%1_%2_%3").arg(sys).arg(_antennaIODCur[s]).arg(iod); 1223 if (!_antennaIODLogged.contains(key)) { 1224 _antennaIODLogged.insert(key); 1225 emit newMessage(QString("%1: GNSS %2 Satellite Antenna IOD switches back %3 -> %4" 1226 " - messages of one GNSS must use the same IOD") 1227 .arg(_staID).arg(sys).arg(_antennaIODCur[s]).arg(iod).toLatin1(), true); 1228 } 1229 } 1230 _antennaIODPrev[s] = _antennaIODCur[s]; 1231 _antennaIODPrevTime[s] = currentTime; 1232 _antennaIODCur[s] = iod; 1233 } -
trunk/BNC/src/RTCM3/RTCM3coDecoder.h
r11038 r11047 30 30 #include <QList> 31 31 #include <QMap> 32 #include <QSet> 32 33 #include "GPSDecoder.h" 33 34 #include "../RTCM3/clock_and_orbit/clock_orbit_igs.h" … … 75 76 void checkProviderID(); 76 77 bool corrIsOutOfRange(const SsrCorr::ClockOrbit::SatData& coSat); 78 // Log (once per satellite) a satellite number outside BNC's supported 79 // range (t_prn::MAXPRN_*); such satellites map to the unused index 0. 80 void checkPrnRange(const t_prn& prn); 81 QSet<QString> _prnOutOfRangeLogged; 82 77 83 78 84 struct t_stateSnapshot { … … 111 117 QMap<bncTime, QList<t_satAntenna> > _satAntennas; 112 118 unsigned int _phaseBiasSentEpoch[CLOCKORBIT_SATNUM]; 113 unsigned int _antennaSentIOD[CLOCKORBIT_SATNUM]; 119 bool _antennaReceived[CLOCKORBIT_SATNUM]; 120 unsigned int _antennaSentProviderID[CLOCKORBIT_COUNTSAT]; 121 unsigned int _antennaSentIOD[CLOCKORBIT_COUNTSAT]; 122 bncTime _antennaSentTime[CLOCKORBIT_COUNTSAT]; 123 // per GNSS: Satellite Antenna IOD currently in use and the one it replaced, 124 // to detect messages of one GNSS using different IODs (see checkAntennaIOD()) 125 void checkAntennaIOD(unsigned s); 126 bool _antennaIODKnown[CLOCKORBIT_SATNUM]; 127 unsigned int _antennaIODProvider[CLOCKORBIT_SATNUM]; 128 unsigned int _antennaIODCur[CLOCKORBIT_SATNUM]; 129 unsigned int _antennaIODPrev[CLOCKORBIT_SATNUM]; 130 bncTime _antennaIODPrevTime[CLOCKORBIT_SATNUM]; // when _antennaIODPrev was last seen 131 QSet<QString> _antennaIODLogged; 114 132 }; 115 133 -
trunk/BNC/src/bncantex.cpp
r11021 r11047 169 169 else if (line.indexOf("END OF ANTENNA") == 60) { 170 170 if (newAntMap) { 171 if (!newAntMap->blockType.isEmpty()) { // satellite antenna 172 t_satBlock satBlock; 173 satBlock.validFrom = newAntMap->validFrom; 174 satBlock.validTo = newAntMap->validTo; 175 satBlock.blockType = newAntMap->blockType; 176 _satBlocks[newAntMap->antName].append(satBlock); 177 } 171 178 if (_maps.contains(newAntMap->antName)) { 172 179 delete _maps[newAntMap->antName]; … … 213 220 else { 214 221 newAntMap->antName = line.mid(0,20); 222 } 223 } 224 else if (line.indexOf("VALID FROM") == 60 || line.indexOf("VALID UNTIL") == 60) { 225 QTextStream inLine(&line, QIODevice::ReadOnly); 226 int year, month, day, hour, min; 227 double sec; 228 inLine >> year >> month >> day >> hour >> min >> sec; 229 bncTime tt; 230 tt.set(year, month, day, hour, min, sec); 231 if (line.indexOf("VALID FROM") == 60) { 232 newAntMap->validFrom = tt; 233 } 234 else { 235 newAntMap->validTo = tt; 215 236 } 216 237 } … … 942 963 943 964 } 965 966 // Satellite block type valid at the given epoch 967 //////////////////////////////////////////////////////////////////////////// 968 QString bncAntex::satBlockType(const QString& prn, const bncTime& epoch) const { 969 QMap<QString, QVector<t_satBlock> >::const_iterator it = _satBlocks.find(prn.mid(0,3)); 970 if (it == _satBlocks.end() || it.value().isEmpty()) { 971 return QString(); 972 } 973 const QVector<t_satBlock>& blocks = it.value(); 974 if (!epoch.valid()) { 975 return blocks.last().blockType; 976 } 977 for (int ii = 0; ii < blocks.size(); ii++) { 978 const t_satBlock& bb = blocks[ii]; 979 if ((!bb.validFrom.valid() || !(epoch < bb.validFrom)) && 980 (!bb.validTo.valid() || epoch < bb.validTo)) { 981 return bb.blockType; 982 } 983 } 984 return QString(); 985 } -
trunk/BNC/src/bncantex.h
r11021 r11047 46 46 double rcvCorr(const std::string& antName, t_frequency::type frqType, 47 47 double eleSat, double azSat, bool& found) const; 48 // Satellite block type (e.g. "IIF", "2I", "3M-CAST") valid for the PRN at 49 // the given epoch, taking PRN reassignments into account (VALID FROM/UNTIL); 50 // empty if unknown 51 QString satBlockType(const QString& prn, const bncTime& epoch) const; 48 52 49 53 // Attitude model selection for satCoMcorrection(). … … 194 198 195 199 QMap<QString, t_antMap*> _maps; 200 201 // Block type history per satellite PRN. _maps keeps only the last ANTEX 202 // entry per PRN, which is wrong for epochs before a PRN was reassigned. 203 struct t_satBlock { 204 bncTime validFrom; 205 bncTime validTo; // invalid: still valid 206 QString blockType; 207 }; 208 QMap<QString, QVector<t_satBlock> > _satBlocks; 196 209 }; 197 210 -
trunk/BNC/src/bncephuser.cpp
r11021 r11047 185 185 // 186 186 //////////////////////////////////////////////////////////////////////////// 187 bool bncEphUser::radialDistanceOk(const t_eph* eph) { 188 ColumnVector xc(6); 189 ColumnVector vv(3); 190 if (eph->getCrd(eph->TOC(), xc, vv, false) != success) { 191 return false; 192 } 193 double rr = xc.Rows(1,3).NormFrobenius(); 194 195 const double MINDIST = 2.e7; 196 const double MAXDIST = 6.e7; 197 if (rr < MINDIST || rr > MAXDIST || std::isnan(rr)) { 198 return false; 199 } 200 return true; 201 } 202 203 // 204 //////////////////////////////////////////////////////////////////////////// 187 205 void bncEphUser::checkEphemeris(t_eph* eph, bool realTime) { 188 206 … … 211 229 // Simple Check - check satellite radial distance 212 230 // ---------------------------------------------- 231 if (!radialDistanceOk(eph)) { 232 eph->setCheckState(t_eph::bad); 233 return; 234 } 213 235 ColumnVector xc(6); 214 236 ColumnVector vv(3); 215 if (eph->getCrd(eph->TOC(), xc, vv, false) != success) { 216 eph->setCheckState(t_eph::bad); 217 return; 218 } 219 double rr = xc.Rows(1,3).NormFrobenius(); 220 221 const double MINDIST = 2.e7; 222 const double MAXDIST = 6.e7; 223 if (rr < MINDIST || rr > MAXDIST || std::isnan(rr)) { 224 eph->setCheckState(t_eph::bad); 225 return; 226 } 237 eph->getCrd(eph->TOC(), xc, vv, false); 227 238 228 239 // Check consistency with older ephemeris -
trunk/BNC/src/bncephuser.h
r11021 r11047 51 51 t_irc putNewEph(t_eph* newEph, bool check); 52 52 53 // Plausibility check: satellite position computable at TOC and its 54 // distance from the geocenter within 20000-60000 km 55 static bool radialDistanceOk(const t_eph* eph); 56 53 57 t_eph* ephLast(const QString& prn) { 54 58 if (_eph.contains(prn)) { -
trunk/BNC/src/bncrinex.cpp
r11021 r11047 390 390 QString monNum = "0"; 391 391 QString recNum = "0"; 392 if (statIDlength == 9) { 392 if (statIDlength == 9 && 393 isdigit((unsigned char) _statID[4]) && 394 isdigit((unsigned char) _statID[5])) { 393 395 monNum = QChar(_statID[4]); 394 396 recNum = QChar(_statID[5]); … … 410 412 "_S_" + // stream 411 413 QString("%1").arg(datTim.date().year()) + 412 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 414 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 413 415 hlpStr + // HMS_period 414 416 QString("%1").arg(_samplingRateStr) + // sampling rate -
trunk/BNC/src/combination/bnccomb.cpp
r10962 r11047 1296 1296 t_satCodeBias satCodeBias(corr->_satCodeBias); 1297 1297 satCodeBias._staID = "INTERNAL"; 1298 satCodeBias._ssrIOD = -1; // combined, not any single provider's solution 1299 satCodeBias._ssrProviderID = -1; 1298 1300 satCodeBiasList.push_back(satCodeBias); 1299 1301 hlp = QString().asprintf(" CodeBias %2lu", satCodeBias._bias.size()); … … 1592 1594 im.remove(); 1593 1595 } 1596 // a newer ephemeris may have arrived (or an older one been re-classified) 1597 // since the correction was accepted - never switch to an unusable one 1598 else if (ephLast->checkState() == t_eph::bad || 1599 ephLast->checkState() == t_eph::outdated || 1600 ephLast->checkState() == t_eph::unhealthy) { 1601 out << "checkOrbit: last eph not ok (" << ephLast->checkStateToString() << ") " << corr->_prn.mid(0,3) << "\n"; 1602 delete corr; 1603 im.remove(); 1604 } 1594 1605 else { 1595 1606 if ( corr->_eph == ephLast || -
trunk/BNC/src/pppRun.cpp
r11041 r11047 575 575 } 576 576 577 // Taken from the same mountpoint as the Metadata (see slotNewMetaData()), 578 // since only Metadata of the same provider can reference this antenna 579 // information (IOD unique per SSR Provider ID only). 577 580 if (_opt->_realTime) { 578 if (_opt->_corrMount.empty() &&_opt->_biasMount.empty()) {581 if (_opt->_corrMount.empty() || _opt->_corrMount != satAntennas[0]._staID) { 579 582 return; 580 }581 if (!_opt->_biasMount.empty()) {582 if (_opt->_biasMount != satAntennas[0]._staID) {583 return;584 }585 }586 else if (!_opt->_corrMount.empty()) {587 if (_opt->_corrMount != satAntennas[0]._staID) {588 return;589 }590 583 } 591 584 } -
trunk/BNC/src/satObs.cpp
r11041 r11047 2 2 #include <iomanip> 3 3 #include <sstream> 4 #include <cstdlib> 4 5 #include <newmatio.h> 5 6 … … 132 133 133 134 e_ssrFormat ssrFormat = ssrUnknown; 135 136 // TEMPORARY BACKWARD COMPATIBILITY - remove later on: 137 // .ssr files written before the SSR format line (a single integer) was 138 // added after the "> ORBIT" epoch line don't have it - their first line 139 // is already the first satellite. Such a line is kept (firstLine) and 140 // processed as the first correction below, with ssrFormat unknown. 141 // To revert: read the format line unconditionally again, i.e. drop the 142 // "only one integer on the line" test and the firstLine handling in the 143 // loop below. 144 string firstLine; 145 getline(inStream, firstLine); 134 146 { 135 string line; 136 getline(inStream, line); 137 istringstream in(line.c_str()); 138 int ssrFormatInt = 0; 139 if (in >> ssrFormatInt) { 147 istringstream in(firstLine.c_str()); 148 int ssrFormatInt = 0; 149 string rest; 150 if ((in >> ssrFormatInt) && !(in >> rest)) { // format line 140 151 ssrFormat = static_cast<e_ssrFormat>(ssrFormatInt); 152 firstLine.clear(); 141 153 } 142 154 } … … 150 162 151 163 string line; 152 getline(inStream, line); 164 if (ii == 0 && !firstLine.empty()) { // TEMPORARY BACKWARD COMPATIBILITY, see above 165 line = firstLine; 166 } 167 else { 168 getline(inStream, line); 169 } 153 170 istringstream in(line.c_str()); 154 171 … … 245 262 *out << "> CODE_BIAS " << epoTime.datestr(' ') << ' ' << epoTime.timestr(1, ' ') << " " 246 263 << satCodeBias._updateInt << " " 247 << biasList.size() << ' ' << satCodeBias._staID << endl; 264 << biasList.size() << ' ' << satCodeBias._staID << ' ' 265 << satCodeBias._ssrIOD << ' ' << satCodeBias._ssrProviderID << endl; 248 266 } 249 267 *out << satCodeBias._prn.toString() << " " << setw(2) << satCodeBias._bias.size(); … … 268 286 return; 269 287 } 288 int ssrIOD, ssrProviderID; 289 t_corrSSR::readSsrIOD(epoLine, ssrIOD, ssrProviderID); 270 290 for (int ii = 0; ii < numSat; ii++) { 271 291 t_satCodeBias satCodeBias; … … 273 293 satCodeBias._updateInt = updateInt; 274 294 satCodeBias._staID = staID; 295 satCodeBias._ssrIOD = ssrIOD; 296 satCodeBias._ssrProviderID = ssrProviderID; 275 297 276 298 string line; … … 313 335 *out << "> PHASE_BIAS " << epoTime.datestr(' ') << ' ' << epoTime.timestr(1, ' ') << " " 314 336 << satPhaseBias._updateInt << " " 315 << biasList.size() << ' ' << satPhaseBias._staID << endl; 337 << biasList.size() << ' ' << satPhaseBias._staID << ' ' 338 << satPhaseBias._ssrIOD << ' ' << satPhaseBias._ssrProviderID << endl; 316 339 317 340 if (satPhaseBias._ssrFormat == e_ssrFormat::ssrRtcmNew) { … … 373 396 return; 374 397 } 398 int ssrIOD, ssrProviderID; 399 t_corrSSR::readSsrIOD(epoLine, ssrIOD, ssrProviderID); 375 400 for (int ii = 0; ii <= numSat; ii++) { 376 401 t_satPhaseBias satPhaseBias; … … 378 403 satPhaseBias._updateInt = updateInt; 379 404 satPhaseBias._staID = staID; 405 satPhaseBias._ssrIOD = ssrIOD; 406 satPhaseBias._ssrProviderID = ssrProviderID; 380 407 381 408 string line; … … 392 419 switch (ssrFormat) { 393 420 case e_ssrFormat::ssrRtcmNew: 394 satPhaseBias._ dispBiasConsistInd = metadata1;395 satPhaseBias._ MelbWuebConsistInd = metadata2;421 satPhaseBias._satYawInfoInd = metadata1; 422 satPhaseBias._extPBPhaseInd = metadata2; 396 423 break; 397 424 case e_ssrFormat::ssrRtcmOld: 398 425 case e_ssrFormat::ssrUnknown: 399 satPhaseBias._ satYawInfoInd = metadata1;400 satPhaseBias._ extPBPhaseInd = metadata2;426 satPhaseBias._dispBiasConsistInd = metadata1; 427 satPhaseBias._MelbWuebConsistInd = metadata2; 401 428 break; 402 429 } … … 575 602 in >> frqAntenna._frqType >> frqAntenna._nadirCorrectionIndicator >> frqAntenna._nadirCorrection; 576 603 for (unsigned kk = 0; kk < numAngles; kk++) { 577 double val;578 in >> val; 579 frqAntenna._nadirAngleCorrection.push_back( val);604 string valStr; // may be "nan" (invalid value), which operator>> can't parse 605 in >> valStr; 606 frqAntenna._nadirAngleCorrection.push_back(strtod(valStr.c_str(), 0)); 580 607 } 581 608 satAntenna._freq.push_back(frqAntenna); … … 684 711 685 712 return unknown; 713 } 714 715 // Optional SSR IOD and Provider ID trailing the staID in CODE_BIAS and 716 // PHASE_BIAS epoch lines (older files don't have them: -1 = unknown) 717 //////////////////////////////////////////////////////////////////////////// 718 void t_corrSSR::readSsrIOD(const string& line, int& ssrIOD, int& ssrProviderID) { 719 istringstream inLine(line.c_str()); 720 string hlp; 721 for (int ii = 0; ii < 11; ii++) { // '>', type, 6 x date/time, updateInt, numEntries, staID 722 inLine >> hlp; 723 } 724 if (!(inLine >> ssrIOD >> ssrProviderID)) { 725 ssrIOD = -1; 726 ssrProviderID = -1; 727 } 686 728 } 687 729 -
trunk/BNC/src/satObs.h
r11041 r11047 166 166 public: 167 167 t_satCodeBias() { 168 _updateInt = 0; 168 _updateInt = 0; 169 _ssrIOD = -1; 170 _ssrProviderID = -1; 169 171 } 170 172 static void writeEpoch(std::ostream* out, const QList<t_satCodeBias>& biasList); … … 174 176 bncTime _time; 175 177 unsigned int _updateInt; 178 int _ssrIOD; // SSR IOD (DF413), -1 if unknown; not satellite specific 179 int _ssrProviderID; // SSR Provider ID (DF414), -1 if unknown; not satellite specific 176 180 std::vector<t_frqCodeBias> _bias; 177 181 }; … … 196 200 t_satPhaseBias() { 197 201 _updateInt = 0; 202 _ssrIOD = -1; 203 _ssrProviderID = -1; 198 204 _ssrFormat = ssrUnknown; 199 205 _dispBiasConsistInd = 0; … … 210 216 bncTime _time; 211 217 unsigned int _updateInt; // not satellite specific 218 int _ssrIOD; // SSR IOD (DF413), -1 if unknown; not satellite specific 219 int _ssrProviderID; // SSR Provider ID (DF414), -1 if unknown; not satellite specific 212 220 e_ssrFormat _ssrFormat; // not satellite specific 213 221 // IGS-SSR … … 307 315 std::string _staID; 308 316 t_prn _prn; 309 bncTime _time; // time this message was decoded (no epoch field on the wire)317 bncTime _time; // time this message was last received (no epoch field on the wire) 310 318 unsigned int _ssrProviderID; // not satellite specific 311 319 unsigned int _satelliteAntennaIOD; // not satellite specific; unique per provider within a 64-day window … … 323 331 static e_type readEpoLine(const std::string& line, bncTime& epoTime, 324 332 unsigned int& updateInt, int& numEntries, std::string& staID); 333 static void readSsrIOD(const std::string& line, int& ssrIOD, int& ssrProviderID); 325 334 static t_eph::e_type getSsrNavTypeFlag(char sys, int num); 326 335 }; -
trunk/BNC/src/t_prn.cpp
r10791 r11047 53 53 ////////////////////////////////////////////////////////////////////////////// 54 54 int t_prn::toInt() const { 55 // Every per-satellite array (size MAXPRN+1) and every map keyed by t_prn 56 // (compared via operator unsigned) relies on this index. A number beyond 57 // its system's range - e.g. a 6-bit SSR satellite ID up to 63 - would 58 // otherwise silently map onto a satellite of the next system (G33 = R01) 59 // or beyond the arrays, so it is mapped to the unused index 0 instead. 60 unsigned maxNum = 0; 61 switch (_system) { 62 case 'G': maxNum = MAXPRN_GPS; break; 63 case 'R': maxNum = MAXPRN_GLONASS; break; 64 case 'E': maxNum = MAXPRN_GALILEO; break; 65 case 'J': maxNum = MAXPRN_QZSS; break; 66 case 'S': maxNum = MAXPRN_SBAS; break; 67 case 'C': maxNum = MAXPRN_BDS; break; 68 case 'I': maxNum = MAXPRN_NavIC; break; 69 } 70 if (_number < 1 || unsigned(_number) > maxNum) { 71 return 0; 72 } 55 73 if (_system == 'G') { 56 74 return _number; -
trunk/BNC/src/t_prn.h
r11036 r11047 10 10 static const unsigned MAXPRN_GALILEO = 36; 11 11 static const unsigned MAXPRN_QZSS = 10; 12 static const unsigned MAXPRN_SBAS = 38;12 static const unsigned MAXPRN_SBAS = 58; // numbered S20-S58 (PRN 120-158), S01-S19 unused 13 13 static const unsigned MAXPRN_BDS = 65; 14 14 static const unsigned MAXPRN_NavIC = 20; … … 54 54 return _flag; 55 55 } 56 int toInt() const; 56 int toInt() const; // 0 (unused index) if the number is out of range for its system 57 57 std::string toString() const; 58 58 std::string toInternalString() const;
Note:
See TracChangeset
for help on using the changeset viewer.
