Changeset 11091 in ntrip


Ignore:
Timestamp:
Oct 16, 2026, 11:22:26 AM (17 hours ago)
Author:
stuerze
Message:

ssrqs: consider if an AC has more than one solution

Location:
trunk/BNC/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/src/bnchelp.html

    r11087 r11091  
    51385138      signal (or to another common signal, if the stream lacks it), are compared with
    51395139      <ul>
    5140         <li>each other AC separately (one vote per AC, own AC left out, combinations not voting), with the RMS of
    5141           the differences and the number of DCBs with opposite sign (only DCBs of at least 0.3 m are used for the
    5142           sign). A stream is reported to use the opposite sign if it has the opposite sign for most DCBs to more than
    5143           half of at least two other ACs - with only two ACs, it cannot be decided which one is wrong. Satellites
    5144           with DCBs deviating from the median of at least 3 other ACs are listed,</li>
     5140        <li>each other solution separately (see 'CONSENSUS' below; also the other solutions of the own AC,
     5141          combinations not voting), with the RMS of the differences and the number of DCBs with opposite sign (only
     5142          DCBs of at least 0.3 m are used for the sign). A stream is reported to use the opposite sign if it has the
     5143          opposite sign for most DCBs to more than half of at least two solutions of other ACs - with only two ACs, it
     5144          cannot be decided which one is wrong. Satellites with DCBs deviating from the median of at least 3
     5145          solutions of other ACs are listed,</li>
    51455146        <li>the selected 'QC Reference' stream instead, if it is not 'CONSENSUS',</li>
    51465147        <li>the 'QC Bias File', if specified.</li>
    … …  
    51525153      gets errors of twice the biases, e.g.
    51535154      <pre>
    5154   G code biases compared with the other ACs (DCBs to C1W): BKG RMS 2.17 m, opposite sign 48/49; CNE RMS 2.44 m, opposite sign 98/101
    5155   G code biases with the opposite sign of 2 of 2 other ACs (BKG CNE) - SINEX sign convention instead of the SSR one?
     5155  G code biases compared with the other solutions (DCBs to C1W): BKG00 RMS 2.17 m, opposite sign 48/49; CNE00 RMS 2.44 m, opposite sign 98/101
     5156  G code biases with the opposite sign of 2 of 2 solutions of other ACs (BKG00 CNE00) - SINEX sign convention instead of the SSR one?
    51565157  G code biases compared with Bias SINEX file CAS1MGXRAP_01D_01D_DCB.BSX (DCBs to C1W, 32 satellites, 141 DCBs): RMS of the differences 2.401 m, opposite sign for 106 of 107 DCBs (|DCB| &gt;= 0.3 m)
    51575158</pre>
    … …  
    51915192  </p>
    51925193  <ul>
    5193     <li>'CONSENSUS' (default): per satellite the median of the other analysis centers (at least two). All decoded
    5194       streams contribute, also those not selected under 'QC Streams' (except the excluded ones). An AC with several
    5195       streams (IGS-SSR and RTCM-SSR format, APC and CoM) has one vote, the median of its streams; the AC is derived
    5196       from the stream name (e.g. 'CNE' from 'SSRA00CNE1'). A stream is compared without the streams of its own AC.
     5194    <li>'CONSENSUS' (default): per satellite the median of the solutions of the other analysis centers (at least
     5195      two). All decoded streams contribute, also those not selected under 'QC Streams' (except the excluded ones). A
     5196      solution is the AC and the two digits of the stream name, e.g. 'GFZ00' for SSRA00GFZ0, SSRA00GFZ1, SSRC00GFZ0
     5197      and SSRC00GFZ1, and 'GFZ01' for SSRA01GFZ0 (OSB streams like OSBC00WHU1 belong to the solution 'WHU00'). The
     5198      streams of a solution (IGS-SSR and RTCM-SSR format, APC and CoM) have one vote, the median of its streams;
     5199      different solutions of an AC vote separately. A stream is compared without all solutions of its own AC, as
     5200      these are not independent (same software and models).
    51975201      Combination products ('INTERNAL' and the IGS combinations '...IGS.') do not vote, as they are derived from the
    51985202      ACs, but are compared with the consensus. A single erroneous AC does not affect the consensus, and no
  • trunk/BNC/src/ssrQc.cpp

    r11087 r11091  
    172172
    173173// Analysis center of a stream: the 3 characters of the AC in mountpoints
    174 // like SSRA00CNE1, otherwise the stream name itself
     174// like SSRA00CNE1 or OSBC00WHU1, otherwise the stream name itself
    175175////////////////////////////////////////////////////////////////////////////
    176176QString t_ssrQc::acOf(const QString& staID) {
    177   static const QRegularExpression re("^SSR[AC][0-9]{2}([A-Z0-9]{3})[0-9]$");
     177  static const QRegularExpression re("^(?:SSR|OSB)[AC][0-9]{2}([A-Z0-9]{3})[0-9]$");
    178178  QRegularExpressionMatch mm = re.match(staID);
    179179  return mm.hasMatch() ? mm.captured(1) : staID;
     180}
     181
     182// Solution of an AC: AC and the two digits of the mountpoint, e.g. GFZ00 for
     183// SSRA00GFZ0/SSRC00GFZ1 and GFZ01 for SSRA01GFZ0; the streams of a solution
     184// (formats, APC/CoM) have one vote in the consensus
     185////////////////////////////////////////////////////////////////////////////
     186QString t_ssrQc::solOf(const QString& staID) {
     187  static const QRegularExpression re("^(?:SSR|OSB)[AC]([0-9]{2})([A-Z0-9]{3})[0-9]$");
     188  QRegularExpressionMatch mm = re.match(staID);
     189  return mm.hasMatch() ? mm.captured(2) + mm.captured(1) : staID;
     190}
     191
     192// AC of a solution (GFZ01 -> GFZ)
     193////////////////////////////////////////////////////////////////////////////
     194QString t_ssrQc::acOfSol(const QString& sol) {
     195  static const QRegularExpression re("^([A-Z0-9]{3})[0-9]{2}$");
     196  QRegularExpressionMatch mm = re.match(sol);
     197  return mm.hasMatch() ? mm.captured(1) : sol;
    180198}
    181199
    … …  
    505523    }
    506524    if (_reference == "CONSENSUS") {
    507       if (!votes(sta) || acOf(sta) == acOf(staID) || (!onlyAC.isEmpty() && acOf(sta) != onlyAC)) {
     525      if (!votes(sta)) {
     526        continue;
     527      }
     528      if (onlyAC.isEmpty() ? (acOf(sta) == acOf(staID))
     529                           : (solOf(sta) != onlyAC || solOf(sta) == solOf(staID))) {
    508530        continue;
    509531      }
    … …  
    521543    for (auto it = bb.constBegin(); it != bb.constEnd(); ++it) {
    522544      if (it.key() != base) {
    523         acDcbs[acOf(sta)][it.key()].append(bb[base] - it.value());
     545        acDcbs[solOf(sta)][it.key()].append(bb[base] - it.value());
    524546      }
    525547    }
    … …  
    668690    QSet<QString> acs;
    669691    for (auto itS = _cbLast.constBegin(); itS != _cbLast.constEnd(); ++itS) {
    670       if (itS.key() != staID && votes(itS.key()) && acOf(itS.key()) != acOf(staID)) {
    671         acs.insert(acOf(itS.key()));
     692      if (itS.key() != staID && votes(itS.key()) && solOf(itS.key()) != solOf(staID)) {
     693        acs.insert(solOf(itS.key()));
    672694      }
    673695    }
    … …  
    683705        continue;
    684706      }
    685       numACs++;
    686707      bases.unite(cc.bases);
    687708      items << QString("%1 RMS %2 m, opposite sign %3/%4").arg(ac).arg(cc.rms(), 0, 'f', 2)
    688709                                                         .arg(cc.numOpp).arg(cc.numSign);
    689       if (cc.opposite()) {
    690         oppACs << ac;
    691       }
    692     }
    693     if (numACs > 0) {
     710      // the sign rule counts the solutions of other ACs only
     711      if (acOfSol(ac) != acOf(staID)) {
     712        numACs++;
     713        if (cc.opposite()) {
     714          oppACs << ac;
     715        }
     716      }
     717    }
     718    if (!items.isEmpty()) {
    694719      QStringList ll = bases.values();
    695720      ll.sort();
    696       lines << QString("code biases compared with the other ACs (DCBs to %1): %2").arg(ll.join("/")).arg(items.join("; "));
     721      lines << QString("code biases compared with the other solutions (DCBs to %1): %2").arg(ll.join("/")).arg(items.join("; "));
    697722      if (numACs >= 2 && oppACs.size() > numACs / 2) {
    698         lines << QString("code biases with the opposite sign of %1 of %2 other ACs (%3) - "
     723        lines << QString("code biases with the opposite sign of %1 of %2 solutions of other ACs (%3) - "
    699724                         "SINEX sign convention instead of the SSR one?")
    700725                 .arg(oppACs.size()).arg(numACs).arg(oppACs.join(" "));
    701726      }
    702       deviating(compare(1, QString()), QString("the median of the other ACs (at least %1 ACs)").arg(MIN_VOTE));
     727      deviating(compare(1, QString()), QString("the median of the other ACs (at least %1 solutions)").arg(MIN_VOTE));
    703728    }
    704729  }
    … …  
    828853        if (!votes(oo) || !crd[oo].contains(prn) || !crd[oo][prn].clkOK) continue;
    829854        if (useOff && !off.contains(oo)) continue;
    830         perAC[acOf(oo)] << crd[oo][prn].clk - (useOff ? off[oo] : 0.0);
     855        perAC[solOf(oo)] << crd[oo][prn].clk - (useOff ? off[oo] : 0.0);
    831856      }
    832857      QMap<QString, double> res;
    … …  
    879904          while (itA.hasNext()) {
    880905            itA.next();
    881             if (itA.key() != ownAC) clks << itA.value();
     906            if (acOfSol(itA.key()) != ownAC) clks << itA.value();
    882907          }
    883908          // orbits: per AC the median of its streams with the same reference point
    … …  
    887912            const t_satCrd& rc = crd[oo][prn];
    888913            if (rc.refPoint != sc.refPoint || sc.refPoint == '?') continue;
    889             for (int ii = 0; ii < 3; ii++) perAC[ii][acOf(oo)] << rc.xx[ii];
     914            for (int ii = 0; ii < 3; ii++) perAC[ii][solOf(oo)] << rc.xx[ii];
    890915          }
    891916          for (const QString& ac : perAC[0].keys()) {
  • trunk/BNC/src/ssrQc.h

    r11087 r11091  
    8686  bool           votes(const QString& staID) const;
    8787  static QString acOf(const QString& staID);
     88  static QString solOf(const QString& staID);   // AC solution, e.g. GFZ00, GFZ01
     89  static QString acOfSol(const QString& sol);
    8890
    8991  // Stream comparison: every CMP_SAMPL seconds, the orbits and clocks of each
Note: See TracChangeset for help on using the changeset viewer.