Changeset 11057 in ntrip for trunk/BNC/src/rinex


Ignore:
Timestamp:
Sep 30, 2026, 11:30:26 AM (10 days ago)
Author:
stuerze
Message:

bug fixes resulting from overall tests

Location:
trunk/BNC/src/rinex
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/src/rinex/reqcanalyze.cpp

    r11023 r11057  
    131131  // ----------------
    132132  t_reqcEdit::readEphemerides(_navFileNames, _ephs, _logStream, _checkEph);
     133  t_reqcEdit::indexEphemerides(_ephs, _ephsByPrn);
    133134
    134135  // Loop over all RINEX Files
    … …  
    207208          continue;
    208209        }
     210        // observations of unhealthy satellites are excluded, as those
     211        // below the elevation mask (see also setExpectedObs)
     212        if (_navFileNames.size() && unhealthyAt(rnxSat.prn, _currEpo->tt)) {
     213          continue;
     214        }
    209215        t_satObs satObs;
    210216        t_rnxObsFile::setObsFromRnx(obsFile, _currEpo, rnxSat, satObs);
    … …  
    266272    }
    267273
    268     t_eph* eph = 0;
    269     for (int ie = 0; ie < _ephs.size(); ie++) {
    270       if (_ephs[ie]->prn() == prn) {
    271         eph = _ephs[ie];
    272         break;
    273       }
    274     }
     274    if (unhealthyAt(prn, _currEpo->tt)) {
     275      continue;
     276    }
     277    t_eph* eph = ephForTime(prn, _currEpo->tt);
    275278    if (eph) {
    276279      ColumnVector xSat(6);
    … …  
    328331                             t_qcSat& qcSat) {
    329332
    330   t_eph* eph = 0;
    331   for (int ie = 0; ie < _ephs.size(); ie++) {
    332     if (_ephs[ie]->prn() == satObs._prn) {
    333       eph = _ephs[ie];
    334       break;
    335     }
    336   }
     333  t_eph* eph = ephForTime(satObs._prn, epoTime);
    337334  if (eph) {
    338335    ColumnVector xc(6);
    … …  
    976973                                   double interval, const ColumnVector& xyzSta) {
    977974  for(QMap<t_prn, int>::iterator it = _numExpObs.begin(); it != _numExpObs.end(); it++) {
    978     t_eph* eph = 0;
     975    bool navAvail = false;
    979976    for (int ie = 0; ie < _ephs.size(); ie++) {
    980977      if (_ephs[ie]->prn() == it.key()) {
    981         eph = _ephs[ie];
     978        navAvail = true;
    982979        break;
    983980      }
    984981    }
    985     if (eph) {
     982    if (navAvail) {
    986983      int numExpObs = 0;
    987984      bncTime epoTime;
    988985      for (epoTime = startTime - interval; epoTime < endTime; epoTime = epoTime + interval) {
     986        // an observation is only expected if a valid ephemeris exists,
     987        // the satellite is healthy (unhealthy satellite-epochs are also
     988        // excluded from the observations, see analyzeFile) and above
     989        // the elevation mask
     990        if (unhealthyAt(it.key(), epoTime)) {
     991          continue;
     992        }
     993        t_eph* eph = ephForTime(it.key(), epoTime, true);
     994        if (!eph) {
     995          continue;
     996        }
    989997        ColumnVector xc(6);
    990998        ColumnVector vv(3);
    … …  
    10071015  }
    10081016}
     1017
     1018// A satellite is considered unhealthy at epoch tt if the valid navigation
     1019// data set closest to tt is flagged unhealthy. Its orbit is not used then
     1020// (the geometry may be erroneous) and its observations are excluded.
     1021////////////////////////////////////////////////////////////////////////////
     1022bool t_reqcAnalyze::unhealthyAt(const t_prn& prn, const bncTime& tt) const {
     1023  t_eph* eph = ephForTime(prn, tt, true, true);
     1024  return eph && eph->checkState() == t_eph::unhealthy;
     1025}
     1026
     1027// Ephemeris of the given satellite for epoch tt, see t_reqcEdit::ephForTime
     1028////////////////////////////////////////////////////////////////////////////
     1029t_eph* t_reqcAnalyze::ephForTime(const t_prn& prn, const bncTime& tt,
     1030                                 bool validOnly, bool allowUnhealthy) const {
     1031  return t_reqcEdit::ephForTime(_ephsByPrn.value(prn), prn, tt, validOnly, allowUnhealthy);
     1032}
  • trunk/BNC/src/rinex/reqcanalyze.h

    r11023 r11057  
    194194  void   setExpectedObs(const bncTime& startTime, const bncTime& endTime,
    195195                        double interval, const ColumnVector& xyzSta);
     196
     197  t_eph* ephForTime(const t_prn& prn, const bncTime& tt, bool validOnly = false,
     198                    bool allowUnhealthy = false) const;
     199
     200  bool   unhealthyAt(const t_prn& prn, const bncTime& tt) const;
    196201
    197202  void   analyzeMultipath();
    … …  
    219224  QStringList                _defaultSignalTypes;
    220225  QVector<t_eph*>            _ephs;
     226  QMap<t_prn, QVector<t_eph*> > _ephsByPrn;
    221227  t_rnxObsFile::t_rnxEpo*    _currEpo;
    222228  t_qcFile                   _qcFile;
  • trunk/BNC/src/rinex/reqcedit.cpp

    r11023 r11057  
    230230  if (_minEle > 0.0 && _ephs.isEmpty()) {
    231231    t_reqcEdit::readEphemerides(_navFileNames, _ephs, _logStream, _checkEph);
     232    t_reqcEdit::indexEphemerides(_ephs, _ephsByPrn);
    232233  }
    233234
    … …  
    546547    const t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
    547548
    548     t_eph* eph = 0;
    549     for (int ie = 0; ie < _ephs.size(); ie++) {
    550       if (_ephs[ie]->prn() == rnxSat.prn) {
    551         eph = _ephs[ie];
    552         break;
    553       }
    554     }
     549    t_eph* eph = ephForTime(_ephsByPrn.value(rnxSat.prn), rnxSat.prn, epo->tt);
    555550    if (eph) {
    556551      ColumnVector xc(6);
    … …  
    567562  }
    568563  epo->rnxSat = keptSats;
     564}
     565
     566// Ephemeris of the given satellite for epoch tt: the one with TOC closest
     567// to tt among those valid at tt (see outDatedBcep). If none is valid,
     568// return 0 when validOnly is set, otherwise the one with TOC closest to tt.
     569// Only ephemerides accepted by t_eph::getCrd are considered (not bad or
     570// outdated; unhealthy ones only if allowUnhealthy is set, to be used with
     571// getCrd(..., ignoreHealth = true)).
     572// Using the first ephemeris of the day for all epochs gives wrong
     573// geometry late in the day and, for GLONASS, integrations over many
     574// hours (t_ephGlo::position integrates from TOC on every call).
     575////////////////////////////////////////////////////////////////////////////
     576t_eph* t_reqcEdit::ephForTime(const QVector<t_eph*>& ephs, const t_prn& prn,
     577                              const bncTime& tt, bool validOnly,
     578                              bool allowUnhealthy) {
     579  t_eph* bestValid   = 0;
     580  t_eph* bestAny     = 0;
     581  double bestValidDt = 0.0;
     582  double bestAnyDt   = 0.0;
     583  for (int ie = 0; ie < ephs.size(); ie++) {
     584    t_eph* eph = ephs[ie];
     585    if (eph->prn() != prn) {
     586      continue;
     587    }
     588    if (eph->checkState() == t_eph::bad      ||
     589        eph->checkState() == t_eph::outdated ||
     590        (eph->checkState() == t_eph::unhealthy && !allowUnhealthy)) {
     591      continue;
     592    }
     593    double dt = fabs(tt - eph->TOC());
     594    if (bestAny == 0 || dt < bestAnyDt) {
     595      bestAny   = eph;
     596      bestAnyDt = dt;
     597    }
     598    if (!outDatedBcep(eph, tt) && (bestValid == 0 || dt < bestValidDt)) {
     599      bestValid   = eph;
     600      bestValidDt = dt;
     601    }
     602  }
     603  if (bestValid || validOnly) {
     604    return bestValid;
     605  }
     606  return bestAny;
     607}
     608
     609// Group ephemerides by satellite (speeds up ephForTime)
     610////////////////////////////////////////////////////////////////////////////
     611void t_reqcEdit::indexEphemerides(const QVector<t_eph*>& ephs,
     612                                  QMap<t_prn, QVector<t_eph*> >& ephsByPrn) {
     613  ephsByPrn.clear();
     614  for (int ie = 0; ie < ephs.size(); ie++) {
     615    ephsByPrn[ephs[ie]->prn()].append(ephs[ie]);
     616  }
    569617}
    570618
  • trunk/BNC/src/rinex/reqcedit.h

    r11023 r11057  
    5656                                QVector<t_eph*>& ephs,
    5757                                QTextStream* log, bool checkEph);
     58  static void indexEphemerides(const QVector<t_eph*>& ephs,
     59                               QMap<t_prn, QVector<t_eph*> >& ephsByPrn);
     60  static t_eph* ephForTime(const QVector<t_eph*>& ephs, const t_prn& prn,
     61                           const bncTime& tt, bool validOnly = false,
     62                           bool allowUnhealthy = false);
    5863
    5964 private:
    … …  
    8287  QMap<QString, QMap<int, int> > _lli;
    8388  QVector<t_eph*>        _ephs;
     89  QMap<t_prn, QVector<t_eph*> > _ephsByPrn;
    8490};
    8591
  • trunk/BNC/src/rinex/rnxobsfile.cpp

    r11023 r11057  
    349349  }
    350350  else {
    351     _obsTypes['G'] << "C1C" << "L1C"  << "S1C"
    352                    << "C1W" << "L1W"  << "S1W"
    353                    << "C2X" << "L2X"  << "S2X"
    354                    << "C2W" << "L2W"  << "S2W"
    355                    << "C5X" << "L5X"  << "S5X";
    356 
    357     _obsTypes['J'] << "C1C" << "L1C"  << "S1C"
    358                    << "C1Z" << "L1Z"  << "S1Z"
    359                    << "C1X" << "L1X"  << "S1X"
    360                    << "C2L" << "L2L"  << "S2L"
    361                    << "C2X" << "L2X"  << "S2X"
    362                    << "C5Q" << "L5Q"  << "S5Q"
    363                    << "C5X" << "L5X"  << "S5X"
    364                    << "C6L" << "L6L"  << "S6L";
    365 
    366     _obsTypes['R'] << "C1C" << "L1C" << "S1C"
    367                    << "C1P" << "L1P" << "S1P"
    368                    << "C2C" << "L2C" << "S2C"
    369                    << "C2P" << "L2P" << "S2P"
    370                    << "C3I" << "L3I" << "S3I"
    371                    << "C4X" << "L4X" << "S4X"
    372                    << "C6X" << "L6X" << "S6X";
    373 
    374     _obsTypes['E'] << "C1C" << "L1C" << "S1C"
    375                    << "C1X" << "L1X" << "S1X"
    376                    << "C5Q" << "L5Q" << "S5Q"
    377                    << "C5X" << "L5X" << "S5X"
    378                    << "C6C" << "L6C" << "S6C"
    379                    << "C6X" << "L6X" << "S6X"
    380                    << "C7Q" << "L7Q" << "S7Q"
    381                    << "C7X" << "L7X" << "S7X"
    382                    << "C8Q" << "L8Q" << "S8Q"
    383                    << "C8X" << "L8X" << "S8X";
    384 
    385     _obsTypes['S'] << "C1C" << "L1C" << "S1C"
    386                    << "C5I" << "L5I" << "S5I"
    387                    << "C5Q" << "L5Q" << "S5Q"
    388                    << "C5X" << "L5X" << "S5X";
    389 
    390     _obsTypes['C'] << "C2I" << "L2I" << "S2I"
    391                    << "C2Q" << "L2Q" << "S2Q"
    392                    << "C2X" << "L2X" << "S2X"
    393                    << "C6I" << "L6I" << "S6I"
    394                    << "C6Q" << "L6Q" << "S6Q"
    395                    << "C6X" << "L6X" << "S6X"
    396                    << "C7I" << "L7I" << "S7I"
    397                    << "C7Q" << "L7Q" << "S7Q"
    398                    << "C7X" << "L7X" << "S7X";
    399 
    400     _obsTypes['I'] << "C5A" << "L5A" << "S5A"
    401                    << "C9A" << "L9A" << "S9A";
     351    // All signals the RTCM3 MSM decoder can deliver (see RTCM3Decoder.cpp),
     352    // each with code, phase, Doppler and SNR. Empty observations are blank
     353    // padded up to the last non-empty one of a record, so the order keeps
     354    // records short: per system first the signals most receivers track
     355    // (Q/C/L/P tracking modes), then the combined 'X' modes, then rarely
     356    // used ones.
     357    QMap<char, QStringList> sigCodes;
     358    sigCodes['G'] << "1C" << "1W" << "2W" << "2L" << "2S" << "5Q" << "1L"
     359                  << "2X" << "5X" << "1X"
     360                  << "5I" << "1S" << "1P" << "2C" << "2P";
     361    sigCodes['R'] << "1C" << "1P" << "2C" << "2P" << "3Q"
     362                  << "3X" << "4X" << "6X"
     363                  << "3I" << "4A" << "4B" << "6A" << "6B";
     364    sigCodes['E'] << "1C" << "5Q" << "7Q" << "8Q" << "6C"
     365                  << "1X" << "5X" << "7X" << "8X" << "6X"
     366                  << "1B" << "5I" << "7I" << "8I" << "6B" << "1A" << "1Z" << "6A" << "6Z";
     367    sigCodes['J'] << "1C" << "2L" << "5Q" << "1L"
     368                  << "2X" << "5X" << "1X"
     369                  << "2S" << "5I" << "1S" << "1E" << "1Z" << "6L" << "6S" << "6X";
     370    sigCodes['C'] << "2I" << "7I" << "6I" << "5P" << "1P" << "7D"
     371                  << "2X" << "7X" << "6X" << "5X" << "1X"
     372                  << "2Q" << "7Q" << "6Q" << "5D" << "1D";
     373    sigCodes['S'] << "1C" << "5I" << "5Q" << "5X";
     374    sigCodes['I'] << "5A" << "9A";
     375
     376    QMapIterator<char, QStringList> it(sigCodes);
     377    while (it.hasNext()) {
     378      it.next();
     379      for (int ii = 0; ii < it.value().size(); ii++) {
     380        const QString& sig = it.value()[ii];
     381        _obsTypes[it.key()] << "C" + sig << "L" + sig << "D" + sig << "S" + sig;
     382      }
     383    }
    402384  }
    403385}
    … …  
    15281510    char sys = rnxSat.prn.system();
    15291511
     1512    // If all observation types are given as v3 types, a direct lookup is
     1513    // equivalent to the (slow) matching loops below
     1514    // --------------------------------------------------------------------
     1515    bool allTypesV3 = true;
     1516    QMapIterator<QString, t_rnxObs> itChk(rnxSat.obs);
     1517    while (itChk.hasNext() && allTypesV3) {
     1518      itChk.next();
     1519      if (itChk.key().length() != 3 || type2to3(sys, itChk.key()) != itChk.key()) {
     1520        allTypesV3 = false;
     1521      }
     1522    }
     1523
    15301524    std::vector <const t_rnxObs*> hlp(header.nTypes(sys));
    15311525    for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
    15321526      hlp[iTypeV3] = 0;
    15331527      QString typeV3 = header.obsType(sys, iTypeV3);
     1528      if (allTypesV3) {
     1529        QMap<QString, t_rnxObs>::const_iterator itV3 = rnxSat.obs.constFind(typeV3);
     1530        if (itV3 != rnxSat.obs.constEnd() && itV3.value().value != 0.0) {
     1531          hlp[iTypeV3] = &itV3.value();
     1532        }
     1533        continue;
     1534      }
    15341535      QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
    15351536
    … …  
    15591560
    15601561    if (header.nTypes(sys)) {
    1561       *stream << rnxSat.prn.toString().c_str();
     1562      QString record = rnxSat.prn.toString().c_str();
    15621563      for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
    15631564        const t_rnxObs* rnxObs = hlp[iTypeV3];
    15641565        if (rnxObs == 0) {
    1565           *stream << QString().leftJustified(16);
     1566          record += QString().leftJustified(16);
    15661567        }
    15671568        else {
    1568           *stream << QString("%1").arg(rnxObs->value, 14, 'f', 3);
     1569          record += QString("%1").arg(rnxObs->value, 14, 'f', 3);
    15691570          if (rnxObs->lli != 0.0) {
    1570             *stream << QString("%1").arg(rnxObs->lli, 1);
     1571            record += QString("%1").arg(rnxObs->lli, 1);
    15711572          }
    15721573          else {
    1573             *stream << ' ';
     1574            record += ' ';
    15741575          }
    15751576          if (rnxObs->snr != 0.0) {
    1576             *stream << QString("%1").arg(rnxObs->snr, 1);
     1577            record += QString("%1").arg(rnxObs->snr, 1);
    15771578          }
    15781579          else {
    1579             *stream << ' ';
     1580            record += ' ';
    15801581          }
    15811582        }
    15821583      }
    1583       *stream << Qt::endl;
     1584      // Trailing blanks can be removed from the records (RINEX 4.02, 4.)
     1585      int len = record.length();
     1586      while (len > 3 && record[len-1] == ' ') {
     1587        len--;
     1588      }
     1589      record.truncate(len);
     1590      *stream << record << Qt::endl;
    15841591    }
    15851592  }
Note: See TracChangeset for help on using the changeset viewer.