Changeset 11061 in ntrip


Ignore:
Timestamp:
Oct 1, 2026, 6:34:50 PM (5 hours ago)
Author:
stuerze
Message:

some more fixes

Location:
trunk/BNC/src
Files:
3 edited

Legend:

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

    r11058 r11061  
    78437843    - despite the fact, that the delivered code biases of an AC may contain contributions from other biases, also phase
    78447844    biases.
     7845  </p>
     7846  <p>
     7847    <b>Consistency of code biases and clocks:</b>
     7848    This procedure requires that the code biases of an AC are consistent with its clocks. An AC is free to estimate
     7849    its clocks from signals other than the reference signals; its code biases of the reference signals must then
     7850    refer to exactly these clocks, i.e. they have to be estimated together with them or aligned to the same clock
     7851    datum. If an AC combines its clocks with code biases from another source (e.g. a SINEX Bias file of another
     7852    analysis), the ionosphere-free linear combination B_IF of these biases does not belong to the clocks. The clocks
     7853    are then shifted per satellite by the wrong amount before the combination.
     7854  </p>
     7855  <p>
     7856    In the combination (method 'Filter') such errors are absorbed by the satellite-specific clock offsets estimated
     7857    for each AC, which consequently follow B_IF of that AC from satellite to satellite. BNC uses this to check the
     7858    consistency, separately for each AC and system:
     7859  </p>
     7860  <ul>
     7861    <li>Every 5 minutes (the first check 5 minutes after the start), the AC's satellite offsets of the current epoch
     7862      are regressed against its B_IF.</li>
     7863    <li>Only satellites with code biases for both reference signals are used; at least 5 satellites are required.</li>
     7864    <li>B_IF must vary noticeably between the satellites (standard deviation of at least 3 cm). Otherwise, e.g. for
     7865      GPS where B_IF of most ACs is close to zero, an inconsistency is not detectable and the check is skipped.</li>
     7866    <li>An inconsistency is reported if the offsets clearly follow B_IF: regression slope at least 0.3 and correlation
     7867      coefficient at least 0.7. Since the error is shared between the inconsistent AC and the others, a slope of about
     7868      0.5 is to be expected with two ACs; with more ACs it approaches 1. The ACs with consistent biases show no
     7869      correlation with their own B_IF.</li>
     7870  </ul>
     7871  <p>
     7872    The result of each positive check is written to the combination logfile, a warning to the BNC logfile at most once
     7873    per hour per AC and system, e.g.
     7874  </p>
     7875  <pre>
     7876bncComb: BKG E code biases (C1C/C5Q) seem inconsistent with its clocks: satellite offsets follow the bias
     7877combination B_IF (27 satellites, B_IF spread 0.084 m, slope 0.60, correlation 0.88)
     7878</pre>
     7879  <p>
     7880    The AC is still used in the combination, its offsets absorb most of the error. Nevertheless, the code biases
     7881    sent out by this AC should be corrected by its provider: either biases estimated together with the clocks
     7882    should be used, or the external biases have to be aligned to the clocks per satellite (b' = b - B_IF of the
     7883    reference signals, SSR sign convention). The check is not applied with the 'Single-Epoch' method.
    78457884  </p>
    78467885  <p>
  • trunk/BNC/src/combination/bnccomb.cpp

    r11059 r11061  
    899899          _newCorr->_satCodeBiasIF += codeCoeff * codeBiasesRefSig[frqType];
    900900        }
     901        if (codeBiasesRefSig.size() == 2) {
     902          _acBiasIF[acName][prnStr.mid(0,3)] = _newCorr->_satCodeBiasIF;
     903        }
     904        else {
     905          _acBiasIF[acName].remove(prnStr.mid(0,3));
     906        }
    901907        _newCorr->_satCodeBias._bias.clear();
    902908      }
    … …  
    10791085      out.flush();
    10801086    }
     1087    if (_method == filter) {
     1088      checkBiasConsistency(epoTime, sys, out);
     1089    }
    10811090    printResults(epoTime, out, masterCorr);
    10821091    dumpResults(epoTime, masterCorr);
    … …  
    11441153        if (pp->type == cmbParam::offACSat            &&
    11451154            pp->AC   == corrs(sys)[maxResIndex-1]->_acName &&
    1146             pp->prn  == corrs(sys)[maxResIndex-1]->_prn.mid(0,3)) {
     1155            pp->prn  == corrs(sys)[maxResIndex-1]->_prn) {
    11471156          QQ_sav.Row(iPar)    = 0.0;
    11481157          QQ_sav.Column(iPar) = 0.0;
    … …  
    11741183
    11751184  return success;
     1185}
     1186
     1187// Check the consistency of the AC code biases with the AC clocks
     1188////////////////////////////////////////////////////////////////////////////
     1189// An AC's clocks refer to its own clock signals; the code biases of the
     1190// reference signals refer them to the reference signals (B_IF, ionosphere-
     1191// free combination of these biases, added to the AC clocks). If the code
     1192// biases do not belong to the clocks (e.g. taken from another product), the
     1193// error B_IF is absorbed by the AC's satellite offsets. The satellite offsets
     1194// of each AC are therefore regressed against its B_IF every 5 minutes (from
     1195// 5 minutes after the start); a warning is issued (at most once per hour per
     1196// AC and system) if B_IF varies noticeably between the satellites and the
     1197// offsets clearly follow it.
     1198////////////////////////////////////////////////////////////////////////////
     1199void bncComb::checkBiasConsistency(bncTime epoTime, char sys, QTextStream& out) {
     1200
     1201  const double CHECK_INT   = 300.0;   // [s] check interval, first check after start
     1202  const unsigned MIN_SAT   = 5;
     1203  const double MIN_SPREAD  = 0.03;    // [m] minimum std. deviation of B_IF
     1204  const double MIN_SLOPE   = 0.3;     // 0.5 expected for 2 ACs, -> 1 for more ACs
     1205  const double MIN_CORR    = 0.7;
     1206
     1207  if (!_biasCheckStart[sys].valid()) {
     1208    _biasCheckStart[sys] = epoTime;
     1209    _biasCheckLast[sys]  = epoTime;
     1210    return;
     1211  }
     1212  if (epoTime - _biasCheckLast[sys] < CHECK_INT) {
     1213    return;
     1214  }
     1215  _biasCheckLast[sys] = epoTime;
     1216
     1217  QListIterator<cmbAC*> itAc(_ACs);
     1218  while (itAc.hasNext()) {
     1219    const QString& acName = itAc.next()->name;
     1220    if (!_acBiasIF.contains(acName)) {
     1221      continue;
     1222    }
     1223    const QMap<QString, double>& biasIF = _acBiasIF[acName];
     1224
     1225    // satellites of this AC in the current epoch with B_IF available
     1226    QVector<double> xx, yy;
     1227    for (int ii = 0; ii < corrs(sys).size(); ii++) {
     1228      const cmbCorr* corr = corrs(sys)[ii];
     1229      if (corr->_acName != acName || !biasIF.contains(corr->_prn.mid(0,3))) {
     1230        continue;
     1231      }
     1232      for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
     1233        const cmbParam* pp = _params[sys][iPar-1];
     1234        if (pp->type == cmbParam::offACSat && pp->AC == acName && pp->prn == corr->_prn) {
     1235          xx.push_back(biasIF[corr->_prn.mid(0,3)]);
     1236          yy.push_back(pp->xx);
     1237          break;
     1238        }
     1239      }
     1240    }
     1241    unsigned nn = xx.size();
     1242    if (nn < MIN_SAT) {
     1243      continue;
     1244    }
     1245    double mx = 0.0, my = 0.0;
     1246    for (unsigned ii = 0; ii < nn; ii++) {
     1247      mx += xx[ii] / nn;
     1248      my += yy[ii] / nn;
     1249    }
     1250    double sxx = 0.0, syy = 0.0, sxy = 0.0;
     1251    for (unsigned ii = 0; ii < nn; ii++) {
     1252      sxx += (xx[ii] - mx) * (xx[ii] - mx);
     1253      syy += (yy[ii] - my) * (yy[ii] - my);
     1254      sxy += (xx[ii] - mx) * (yy[ii] - my);
     1255    }
     1256    double spread = sqrt(sxx / nn);
     1257    if (spread < MIN_SPREAD || syy <= 0.0) {
     1258      continue;
     1259    }
     1260    double slope = sxy / sxx;
     1261    double corrCoeff = sxy / sqrt(sxx * syy);
     1262    if (slope < MIN_SLOPE || corrCoeff < MIN_CORR) {
     1263      continue;
     1264    }
     1265
     1266    QString refSig;
     1267    for (unsigned ii = 1; ii < cmbRefSig::cIF; ii++) {
     1268      t_frequency::type frqType = cmbRefSig::toFreq(sys, static_cast<cmbRefSig::type>(ii));
     1269      refSig += QString("%1C%2%3").arg(ii > 1 ? "/" : "").arg(t_frequency::toString(frqType)[1])
     1270                                  .arg(cmbRefSig::toAttrib(sys, static_cast<cmbRefSig::type>(ii)));
     1271    }
     1272    QString msg = QString("%1 %2 code biases (%3) seem inconsistent with its clocks: "
     1273                          "satellite offsets follow the bias combination B_IF "
     1274                          "(%4 satellites, B_IF spread %5 m, slope %6, correlation %7)")
     1275                  .arg(acName).arg(sys).arg(refSig).arg(nn)
     1276                  .arg(spread, 0, 'f', 3).arg(slope, 0, 'f', 2).arg(corrCoeff, 0, 'f', 2);
     1277    out << epoTime.datestr().c_str() << " " << epoTime.timestr().c_str()
     1278        << " " << msg << "\n";
     1279    QString key = acName + sys;
     1280    bncTime& warned = _biasCheckWarned[key];
     1281    if (!warned.valid() || epoTime - warned >= 3600.0) {
     1282      warned = epoTime;
     1283      emit newMessage("bncComb: " + msg.toLatin1(), true);
     1284    }
     1285  }
    11761286}
    11771287
  • trunk/BNC/src/combination/bnccomb.h

    r11059 r11061  
    270270  QMap<QString, bncTime>                     _refBiasWarned; // last warning per AC and system
    271271  QMap<char, bncTime>                        _singleACWarned; // last 'fewer than 2 ACs' message per system
     272  QMap<QString, QMap<QString, double> >      _acBiasIF;       // latest B_IF of the reference signals per AC and satellite
     273  QMap<char, bncTime>                        _biasCheckStart; // first combined epoch per system
     274  QMap<char, bncTime>                        _biasCheckLast;  // last bias/clock consistency check per system
     275  QMap<QString, bncTime>                     _biasCheckWarned; // last inconsistency warning per AC and system
     276  void checkBiasConsistency(bncTime epoTime, char sys, QTextStream& out);
    272277  bool allACsBeyond(const bncTime& epoTime) const;
    273278  bncTime                                    _resTime;
Note: See TracChangeset for help on using the changeset viewer.