source: ntrip/trunk/BNC/src/combination/bnccomb.cpp@ 9635

Last change on this file since 9635 was 9635, checked in by stuerze, 2 years ago

consideration of incoming Code Biases during clock combination

File size: 39.5 KB
Line 
1/* -------------------------------------------------------------------------
2 * BKG NTRIP Client
3 * -------------------------------------------------------------------------
4 *
5 * Class: bncComb
6 *
7 * Purpose: Combinations of Orbit/Clock Corrections
8 *
9 * Author: L. Mervart
10 *
11 * Created: 22-Jan-2011
12 *
13 * Changes:
14 *
15 * -----------------------------------------------------------------------*/
16
17#include <newmatio.h>
18#include <iomanip>
19#include <sstream>
20#include <map>
21
22#include "bnccomb.h"
23#include "bnccore.h"
24#include "upload/bncrtnetdecoder.h"
25#include "bncsettings.h"
26#include "bncutils.h"
27#include "bncsp3.h"
28#include "bncantex.h"
29#include "t_prn.h"
30
31const double sig0_offAC = 1000.0;
32const double sig0_offACSat = 100.0;
33const double sigP_offACSat = 0.01;
34const double sig0_clkSat = 100.0;
35
36const double sigObs = 0.05;
37
38using namespace std;
39
40// Constructor
41////////////////////////////////////////////////////////////////////////////
42bncComb::cmbParam::cmbParam(parType type_, int index_, const QString& ac_, const QString& prn_) {
43
44 type = type_;
45 index = index_;
46 AC = ac_;
47 prn = prn_;
48 xx = 0.0;
49 eph = 0;
50
51 if (type == offACgnss) {
52 epoSpec = true;
53 sig0 = sig0_offAC;
54 sigP = sig0;
55 }
56 else if (type == offACSat) {
57 epoSpec = false;
58 sig0 = sig0_offACSat;
59 sigP = sigP_offACSat;
60 }
61 else if (type == clkSat) {
62 epoSpec = true;
63 sig0 = sig0_clkSat;
64 sigP = sig0;
65 }
66}
67
68// Destructor
69////////////////////////////////////////////////////////////////////////////
70bncComb::cmbParam::~cmbParam() {
71}
72
73// Partial
74////////////////////////////////////////////////////////////////////////////
75double bncComb::cmbParam::partial(char sys, const QString& AC_, const QString& prn_) {
76
77 if (type == offACgnss) {
78 if (AC == AC_ && prn_[0].toLatin1() == sys) {
79 return 1.0;
80 }
81 }
82 else if (type == offACSat) {
83 if (AC == AC_ && prn == prn_) {
84 return 1.0;
85 }
86 }
87 else if (type == clkSat) {
88 if (prn == prn_) {
89 return 1.0;
90 }
91 }
92
93 return 0.0;
94}
95
96//
97////////////////////////////////////////////////////////////////////////////
98QString bncComb::cmbParam::toString(char sys) const {
99
100 QString outStr;
101
102 if (type == offACgnss) {
103 outStr = "AC Offset " + AC + " " + sys + " ";
104 }
105 else if (type == offACSat) {
106 outStr = "Sat Offset " + AC + " " + prn.mid(0,3);
107 }
108 else if (type == clkSat) {
109 outStr = "Clk Corr " + prn.mid(0,3);
110 }
111
112 return outStr;
113}
114
115// Singleton
116////////////////////////////////////////////////////////////////////////////
117bncComb* bncComb::instance() {
118 static bncComb _bncComb;
119 return &_bncComb;
120}
121
122// Constructor
123////////////////////////////////////////////////////////////////////////////
124bncComb::bncComb() : _ephUser(true) {
125
126 bncSettings settings;
127
128 QStringList cmbStreams = settings.value("cmbStreams").toStringList();
129
130 _cmbSampl = settings.value("cmbSampl").toInt();
131 if (_cmbSampl <= 0) {
132 _cmbSampl = 10;
133 }
134 _useGps = (Qt::CheckState(settings.value("cmbGps").toInt()) == Qt::Checked) ? true : false;
135 if (_useGps) {
136 _cmbSysPrn['G'] = t_prn::MAXPRN_GPS;
137 _masterMissingEpochs['G'] = 0;
138 }
139 _useGlo = (Qt::CheckState(settings.value("cmbGlo").toInt()) == Qt::Checked) ? true : false;
140 if (_useGlo) {
141 _cmbSysPrn['R'] = t_prn::MAXPRN_GLONASS;
142 _masterMissingEpochs['R'] = 0;
143 }
144 _useGal = (Qt::CheckState(settings.value("cmbGal").toInt()) == Qt::Checked) ? true : false;
145 if (_useGal) {
146 _cmbSysPrn['E'] = t_prn::MAXPRN_GALILEO;
147 _masterMissingEpochs['E'] = 0;
148 }
149 _useBds = (Qt::CheckState(settings.value("cmbBds").toInt()) == Qt::Checked) ? true : false;
150 if (_useBds) {
151 _cmbSysPrn['C'] = t_prn::MAXPRN_BDS;
152 _masterMissingEpochs['C'] = 0;
153 }
154 _useQzss = (Qt::CheckState(settings.value("cmbQzss").toInt()) == Qt::Checked) ? true : false;
155 if (_useQzss) {
156 _cmbSysPrn['J'] = t_prn::MAXPRN_QZSS;
157 _masterMissingEpochs['J'] = 0;
158 }
159 _useSbas = (Qt::CheckState(settings.value("cmbSbas").toInt()) == Qt::Checked) ? true : false;
160 if (_useSbas) {
161 _cmbSysPrn['S'] = t_prn::MAXPRN_SBAS;
162 _masterMissingEpochs['S'] = 0;
163 }
164 _useIrnss = (Qt::CheckState(settings.value("cmbIrnss").toInt()) == Qt::Checked) ? true : false;
165 if (_useIrnss) {
166 _cmbSysPrn['I'] = t_prn::MAXPRN_IRNSS;
167 _masterMissingEpochs['I'] = 0;
168 }
169
170 if (cmbStreams.size() >= 1 && !cmbStreams[0].isEmpty()) {
171 QListIterator<QString> it(cmbStreams);
172 while (it.hasNext()) {
173 QStringList hlp = it.next().split(" ");
174 cmbAC* newAC = new cmbAC();
175 newAC->mountPoint = hlp[0];
176 newAC->name = hlp[1];
177 newAC->weight = hlp[2].toDouble();
178 QMapIterator<char, unsigned> itSys(_cmbSysPrn);
179 // init
180 while (itSys.hasNext()) {
181 itSys.next();
182 char sys = itSys.key();
183 if (_masterOrbitAC.isEmpty()) {
184 _masterOrbitAC[sys] = newAC->name;
185 }
186 }
187 _ACs.append(newAC);
188 }
189 }
190
191 QString ssrFormat;
192 _ssrCorr = 0;
193 QListIterator<QString> it(settings.value("uploadMountpointsOut").toStringList());
194 while (it.hasNext()) {
195 QStringList hlp = it.next().split(",");
196 if (hlp.size() > 7) {
197 ssrFormat = hlp[7];
198 }
199 }
200 if (ssrFormat == "IGS-SSR") {
201 _ssrCorr = new SsrCorrIgs();
202 }
203 else if (ssrFormat == "RTCM-SSR") {
204 _ssrCorr = new SsrCorrRtcm();
205 }
206 else { // default
207 _ssrCorr = new SsrCorrIgs();
208 }
209
210 _rtnetDecoder = 0;
211
212 connect(this, SIGNAL(newMessage(QByteArray,bool)),
213 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
214
215 connect(BNC_CORE, SIGNAL(providerIDChanged(QString)),
216 this, SLOT(slotProviderIDChanged(QString)));
217
218 connect(BNC_CORE, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
219 this, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
220
221 connect(BNC_CORE, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
222 this, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
223
224 connect(BNC_CORE, SIGNAL(newCodeBiases(QList<t_satCodeBias>)),
225 this, SLOT(slotNewCodeBiases(QList<t_satCodeBias>)));
226
227 // Combination Method
228 // ------------------
229 if (settings.value("cmbMethod").toString() == "Single-Epoch") {
230 _method = singleEpoch;
231 }
232 else {
233 _method = filter;
234 }
235
236 // Initialize Parameters (model: Clk_Corr = AC_Offset + Sat_Offset + Clk)
237 // ----------------------------------------------------------------------
238 if (_method == filter) {
239 // SYSTEM
240 QMapIterator<char, unsigned> itSys(_cmbSysPrn);
241 while (itSys.hasNext()) {
242 itSys.next();
243 int nextPar = 0;
244 char sys = itSys.key();
245 unsigned maxPrn = itSys.value();
246 unsigned flag = 0;
247 if (sys == 'E') {
248 flag = 1;
249 }
250 // AC
251 QListIterator<cmbAC*> itAc(_ACs);
252 while (itAc.hasNext()) {
253 cmbAC* AC = itAc.next();
254 _params[sys].push_back(new cmbParam(cmbParam::offACgnss, ++nextPar, AC->name, ""));
255 for (unsigned iGnss = 1; iGnss <= maxPrn; iGnss++) {
256 QString prn = QString("%1%2_%3").arg(sys).arg(iGnss, 2, 10, QChar('0')).arg(flag);
257 _params[sys].push_back(new cmbParam(cmbParam::offACSat, ++nextPar, AC->name, prn));
258 }
259 }
260 for (unsigned iGnss = 1; iGnss <= maxPrn; iGnss++) {
261 QString prn = QString("%1%2_%3").arg(sys).arg(iGnss, 2, 10, QChar('0')).arg(flag);
262 _params[sys].push_back(new cmbParam(cmbParam::clkSat, ++nextPar, "", prn));
263 }
264 // Initialize Variance-Covariance Matrix
265 // -------------------------------------
266 _QQ[sys].ReSize(_params[sys].size());
267 _QQ[sys] = 0.0;
268 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
269 cmbParam* pp = _params[sys][iPar-1];
270 _QQ[sys](iPar,iPar) = pp->sig0 * pp->sig0;
271 }
272 }
273 }
274
275 // ANTEX File
276 // ----------
277 _antex = 0;
278 QString antexFileName = settings.value("uploadAntexFile").toString();
279 if (!antexFileName.isEmpty()) {
280 _antex = new bncAntex();
281 if (_antex->readFile(antexFileName) != success) {
282 emit newMessage("wrong ANTEX file", true);
283 delete _antex;
284 _antex = 0;
285 }
286 }
287
288 // Maximal Residuum
289 // ----------------
290 _MAXRES = settings.value("cmbMaxres").toDouble();
291 if (_MAXRES <= 0.0) {
292 _MAXRES = 999.0;
293 }
294}
295
296// Destructor
297////////////////////////////////////////////////////////////////////////////
298bncComb::~bncComb() {
299 QListIterator<cmbAC*> icAC(_ACs);
300 while (icAC.hasNext()) {
301 delete icAC.next();
302 }
303 delete _rtnetDecoder;
304 if (_ssrCorr) {
305 delete _ssrCorr;
306 }
307 delete _antex;
308 QMapIterator<char, unsigned> itSys(_cmbSysPrn);
309 while (itSys.hasNext()) {
310 itSys.next();
311 char sys = itSys.key();
312 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
313 delete _params[sys][iPar-1];
314 }
315 QListIterator<bncTime> itTime(_buffer[sys].keys());
316 while (itTime.hasNext()) {
317 bncTime epoTime = itTime.next();
318 _buffer[sys].remove(epoTime);
319 }
320 }
321
322}
323
324// Remember orbit corrections
325////////////////////////////////////////////////////////////////////////////
326void bncComb::slotNewOrbCorrections(QList<t_orbCorr> orbCorrections) {
327 QMutexLocker locker(&_mutex);
328
329 for (int ii = 0; ii < orbCorrections.size(); ii++) {
330 t_orbCorr& orbCorr = orbCorrections[ii];
331 QString staID(orbCorr._staID.c_str());
332 char sys = orbCorr._prn.system();
333
334 if (!_cmbSysPrn.contains(sys)){
335 continue;
336 }
337
338 // Find/Check the AC Name
339 // ----------------------
340 QString acName;
341 QListIterator<cmbAC*> icAC(_ACs);
342 while (icAC.hasNext()) {
343 cmbAC* AC = icAC.next();
344 if (AC->mountPoint == staID) {
345 acName = AC->name;
346 break;
347 }
348 }
349 if (acName.isEmpty()) {
350 continue;
351 }
352
353 // Store the correction
354 // --------------------
355 QMap<t_prn, t_orbCorr>& storage = _orbCorrections[acName];
356 storage[orbCorr._prn] = orbCorr;
357 }
358}
359
360// Remember satllite code biases
361////////////////////////////////////////////////////////////////////////////
362void bncComb::slotNewCodeBiases(QList<t_satCodeBias> satCodeBiases) {
363 QMutexLocker locker(&_mutex);
364
365 for (int ii = 0; ii < satCodeBiases.size(); ii++) {
366 t_satCodeBias& satCodeBias = satCodeBiases[ii];
367 QString staID(satCodeBias._staID.c_str());
368 char sys = satCodeBias._prn.system();
369
370 if (!_cmbSysPrn.contains(sys)){
371 continue;
372 }
373
374 // Find/Check the AC Name
375 // ----------------------
376 QString acName;
377 QListIterator<cmbAC*> icAC(_ACs);
378 while (icAC.hasNext()) {
379 cmbAC* AC = icAC.next();
380 if (AC->mountPoint == staID) {
381 acName = AC->name;
382 break;
383 }
384 }
385 if (acName.isEmpty()) {
386 continue;
387 }
388
389 // Store the correction
390 // --------------------
391 QMap<t_prn, t_satCodeBias>& storage = _satCodeBiases[acName];
392 storage[satCodeBias._prn] = satCodeBias;
393 }
394}
395
396// Process clock corrections
397////////////////////////////////////////////////////////////////////////////
398void bncComb::slotNewClkCorrections(QList<t_clkCorr> clkCorrections) {
399 QMutexLocker locker(&_mutex);
400
401 bncTime lastTime;
402
403 for (int ii = 0; ii < clkCorrections.size(); ii++) {
404 t_clkCorr& clkCorr = clkCorrections[ii];
405 QString staID(clkCorr._staID.c_str());
406 QString prn(clkCorr._prn.toInternalString().c_str());
407 char sys = clkCorr._prn.system();
408
409 if (!_cmbSysPrn.contains(sys)){
410 continue;
411 }
412
413 // Set the last time
414 // -----------------
415 if (lastTime.undef() || clkCorr._time > lastTime) {
416 lastTime = clkCorr._time;
417 }
418
419 // Find/Check the AC Name
420 // ----------------------
421 QString acName;
422 QListIterator<cmbAC*> icAC(_ACs);
423 while (icAC.hasNext()) {
424 cmbAC* AC = icAC.next();
425 if (AC->mountPoint == staID) {
426 acName = AC->name;
427 break;
428 }
429 }
430 if (acName.isEmpty()) {
431 continue;
432 }
433
434 // Check Modulo Time
435 // -----------------
436 int sec = int(nint(clkCorr._time.gpssec()*10));
437 if (sec % (_cmbSampl*10) != 0.0) {
438 continue;
439 }
440
441 // Check Correction Age
442 // --------------------
443 if (_resTime.valid() && clkCorr._time <= _resTime) {
444 emit newMessage("bncComb: old correction: " + acName.toLatin1() + " " + prn.mid(0,3).toLatin1(), true);
445 continue;
446 }
447
448 // Create new correction
449 // ---------------------
450 cmbCorr* newCorr = new cmbCorr();
451 newCorr->_prn = prn;
452 newCorr->_time = clkCorr._time;
453 newCorr->_iod = clkCorr._iod;
454 newCorr->_acName = acName;
455 newCorr->_clkCorr = clkCorr;
456
457 // Check orbit correction
458 // ----------------------
459 if (!_orbCorrections.contains(acName)) {
460 delete newCorr;
461 continue;
462 }
463 else {
464 QMap<t_prn, t_orbCorr>& storage = _orbCorrections[acName];
465 if (!storage.contains(clkCorr._prn) ||
466 storage[clkCorr._prn]._iod != newCorr->_iod) {
467 delete newCorr;
468 continue;
469 }
470 else {
471 newCorr->_orbCorr = storage[clkCorr._prn];
472 }
473 }
474
475 // Check the Ephemeris
476 //--------------------
477 t_eph* ephLast = _ephUser.ephLast(prn);
478 t_eph* ephPrev = _ephUser.ephPrev(prn);
479 if (ephLast == 0) {
480 emit newMessage("bncComb: eph not found for " + prn.mid(0,3).toLatin1(), true);
481 delete newCorr;
482 continue;
483 }
484 else if (ephLast->checkState() == t_eph::bad ||
485 ephLast->checkState() == t_eph::outdated ||
486 ephLast->checkState() == t_eph::unhealthy) {
487 emit newMessage("bncComb: ephLast not ok for " + prn.mid(0,3).toLatin1(), true);
488 delete newCorr;
489 continue;
490 }
491 else {
492 if (ephLast->IOD() == newCorr->_iod) {
493 newCorr->_eph = ephLast;
494 }
495 else if (ephPrev && ephPrev->checkState() == t_eph::ok &&
496 ephPrev->IOD() == newCorr->_iod) {
497 newCorr->_eph = ephPrev;
498 switchToLastEph(ephLast, newCorr);
499 }
500 else {
501 emit newMessage("bncComb: eph not found for " + prn.mid(0,3).toLatin1() +
502 QString(" with IOD %1").arg(newCorr->_iod).toLatin1(), true);
503 delete newCorr;
504 continue;
505 }
506 }
507
508 // Check satellite code biases
509 // ----------------------------
510 if (!_satCodeBiases.contains(acName)) {
511 delete newCorr;
512 continue;
513 }
514 else {
515 QMap<t_prn, t_satCodeBias>& storage = _satCodeBiases[acName];
516 if (!storage.contains(clkCorr._prn)) {
517 delete newCorr;
518 continue;
519 }
520 else {
521 t_satCodeBias& satCodeBias = storage[clkCorr._prn];
522 QMap<t_frequency::type, double> codeBias;
523 for (unsigned ii = 1; ii < t_lcRefSig::cIF; ii++) {
524 t_frequency::type frqType = t_lcRefSig::toFreq(sys, static_cast<t_lcRefSig::type>(ii));
525 char frqNum = t_frequency::toString(frqType)[1];
526 char attrib = t_lcRefSig::toAttrib(sys, static_cast<t_lcRefSig::type>(ii));
527 QString obsType = QString("%1%2").arg(frqNum).arg(attrib);
528 for (unsigned ii = 0; ii < satCodeBias._bias.size(); ii++) {
529 const t_frqCodeBias& bias = satCodeBias._bias[ii];
530 if (obsType.toStdString() == bias._rnxType2ch) {
531 codeBias[frqType] = bias._value;
532 }
533 }
534 }
535 map<t_frequency::type, double> codeCoeff;
536 double channel = double(newCorr->_eph->slotNum());
537 t_lcRefSig::coeff(sys, t_lcRefSig::cIF, channel, codeCoeff);
538 map<t_frequency::type, double>::const_iterator it;
539 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) {
540 t_frequency::type frqType = it->first;
541 newCorr->_codeBiasIF += it->second * codeBias[frqType];
542 }
543 }
544 cout << acName.toStdString() << " " << clkCorr._prn.toString().c_str() << " _codeBiasIF: " << newCorr->_codeBiasIF << endl;
545 }
546
547 // Store correction into the buffer
548 // --------------------------------
549 QVector<cmbCorr*>& corrs = _buffer[sys][newCorr->_time].corrs;
550 corrs.push_back(newCorr);
551 }
552
553 // Process previous Epoch(s)
554 // -------------------------
555 const double outWait = 1.0 * _cmbSampl;
556 QMapIterator<char, unsigned> itSys(_cmbSysPrn);
557 while (itSys.hasNext()) {
558 itSys.next();
559 char sys = itSys.key();
560 QListIterator<bncTime> itTime(_buffer[sys].keys());
561 while (itTime.hasNext()) {
562 bncTime epoTime = itTime.next();
563 if (epoTime < lastTime - outWait) {
564 _resTime = epoTime;
565 processEpoch(sys);
566 }
567 }
568 }
569}
570
571// Change the correction so that it refers to last received ephemeris
572////////////////////////////////////////////////////////////////////////////
573void bncComb::switchToLastEph(t_eph* lastEph, cmbCorr* corr) {
574
575 if (corr->_eph == lastEph) {
576 return;
577 }
578
579 ColumnVector oldXC(6);
580 ColumnVector oldVV(3);
581 if (corr->_eph->getCrd(corr->_time, oldXC, oldVV, false) != success) {
582 return;
583 }
584
585 ColumnVector newXC(6);
586 ColumnVector newVV(3);
587 if (lastEph->getCrd(corr->_time, newXC, newVV, false) != success) {
588 return;
589 }
590
591 ColumnVector dX = newXC.Rows(1,3) - oldXC.Rows(1,3);
592 ColumnVector dV = newVV - oldVV;
593 double dC = newXC(4) - oldXC(4);
594
595 ColumnVector dRAO(3);
596 XYZ_to_RSW(newXC.Rows(1,3), newVV, dX, dRAO);
597
598 ColumnVector dDotRAO(3);
599 XYZ_to_RSW(newXC.Rows(1,3), newVV, dV, dDotRAO);
600
601 QString msg = "switch corr " + corr->_prn.mid(0,3)
602 + QString(" %1 -> %2 %3").arg(corr->_iod,3).arg(lastEph->IOD(),3).arg(dC*t_CST::c, 8, 'f', 4);
603
604 emit newMessage(msg.toLatin1(), false);
605
606 corr->_iod = lastEph->IOD();
607 corr->_eph = lastEph;
608
609 corr->_orbCorr._xr += dRAO;
610 corr->_orbCorr._dotXr += dDotRAO;
611 corr->_clkCorr._dClk -= dC;
612}
613
614// Process Epoch
615////////////////////////////////////////////////////////////////////////////
616void bncComb::processEpoch(char sys) {
617
618 _log.clear();
619
620 QTextStream out(&_log, QIODevice::WriteOnly);
621
622 out << "\n" << "Combination: " << sys << "\n"
623 << "--------------------------------" << "\n";
624
625 // Observation Statistics
626 // ----------------------
627 bool masterPresent = false;
628 QListIterator<cmbAC*> icAC(_ACs);
629 while (icAC.hasNext()) {
630 cmbAC* AC = icAC.next();
631 AC->numObs[sys] = 0;
632 QVectorIterator<cmbCorr*> itCorr(corrs(sys));
633 while (itCorr.hasNext()) {
634 cmbCorr* corr = itCorr.next();
635 if (corr->_acName == AC->name) {
636 AC->numObs[sys] += 1;
637 if (AC->name == _masterOrbitAC[sys]) {
638 masterPresent = true;
639 }
640 }
641 }
642 out << AC->name.toLatin1().data() << ": " << AC->numObs[sys] << "\n";
643 }
644
645 // If Master not present, switch to another one
646 // --------------------------------------------
647 const unsigned switchMasterAfterGap = 1;
648 if (masterPresent) {
649 _masterMissingEpochs[sys] = 0;
650 }
651 else {
652 ++_masterMissingEpochs[sys];
653 if (_masterMissingEpochs[sys] < switchMasterAfterGap) {
654 out << "Missing Master, Epoch skipped" << "\n";
655 _buffer[sys].remove(_resTime);
656 emit newMessage(_log, false);
657 return;
658 }
659 else {
660 _masterMissingEpochs[sys] = 0;
661 QListIterator<cmbAC*> icAC(_ACs);
662 while (icAC.hasNext()) {
663 cmbAC* AC = icAC.next();
664 if (AC->numObs[sys] > 0) {
665 out << "Switching Master AC "
666 << _masterOrbitAC[sys].toLatin1().data() << " --> "
667 << AC->name.toLatin1().data() << " "
668 << _resTime.datestr().c_str() << " "
669 << _resTime.timestr().c_str() << "\n";
670 _masterOrbitAC[sys] = AC->name;
671 break;
672 }
673 }
674 }
675 }
676
677 QMap<QString, cmbCorr*> resCorr;
678
679 // Perform the actual Combination using selected Method
680 // ----------------------------------------------------
681 t_irc irc;
682 ColumnVector dx;
683 if (_method == filter) {
684 irc = processEpoch_filter(sys, out, resCorr, dx);
685 }
686 else {
687 irc = processEpoch_singleEpoch(sys, out, resCorr, dx);
688 }
689
690 // Update Parameter Values, Print Results
691 // --------------------------------------
692 if (irc == success) {
693 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
694 cmbParam* pp = _params[sys][iPar-1];
695 pp->xx += dx(iPar);
696 if (pp->type == cmbParam::clkSat) {
697 if (resCorr.find(pp->prn) != resCorr.end()) {
698 resCorr[pp->prn]->_dClkResult = pp->xx / t_CST::c;
699 }
700 }
701 out << _resTime.datestr().c_str() << " "
702 << _resTime.timestr().c_str() << " ";
703 out.setRealNumberNotation(QTextStream::FixedNotation);
704 out.setFieldWidth(8);
705 out.setRealNumberPrecision(4);
706 out << pp->toString(sys) << " "
707 << pp->xx << " +- " << sqrt(_QQ[sys](pp->index,pp->index)) << "\n";
708 out.setFieldWidth(0);
709 }
710 printResults(out, resCorr);
711 dumpResults(resCorr);
712 }
713
714 // Delete Data, emit Message
715 // -------------------------
716 _buffer[sys].remove(_resTime);
717 emit newMessage(_log, false);
718}
719
720// Process Epoch - Filter Method
721////////////////////////////////////////////////////////////////////////////
722t_irc bncComb::processEpoch_filter(char sys, QTextStream& out,
723 QMap<QString, cmbCorr*>& resCorr,
724 ColumnVector& dx) {
725
726 // Prediction Step
727 // ---------------
728 int nPar = _params[sys].size();
729 ColumnVector x0(nPar);
730 for (int iPar = 1; iPar <= nPar; iPar++) {
731 cmbParam* pp = _params[sys][iPar-1];
732 if (pp->epoSpec) {
733 pp->xx = 0.0;
734 _QQ[sys].Row(iPar) = 0.0;
735 _QQ[sys].Column(iPar) = 0.0;
736 _QQ[sys](iPar,iPar) = pp->sig0 * pp->sig0;
737 }
738 else {
739 _QQ[sys](iPar,iPar) += pp->sigP * pp->sigP;
740 }
741 x0(iPar) = pp->xx;
742 }
743
744 // Check Satellite Positions for Outliers
745 // --------------------------------------
746 if (checkOrbits(sys, out) != success) {
747 return failure;
748 }
749
750 // Update and outlier detection loop
751 // ---------------------------------
752 SymmetricMatrix QQ_sav = _QQ[sys];
753 while (true) {
754
755 Matrix AA;
756 ColumnVector ll;
757 DiagonalMatrix PP;
758
759 if (createAmat(sys, AA, ll, PP, x0, resCorr) != success) {
760 return failure;
761 }
762
763 dx.ReSize(nPar); dx = 0.0;
764 kalman(AA, ll, PP, _QQ[sys], dx);
765
766 ColumnVector vv = ll - AA * dx;
767
768 int maxResIndex;
769 double maxRes = vv.maximum_absolute_value1(maxResIndex);
770 out.setRealNumberNotation(QTextStream::FixedNotation);
771 out.setRealNumberPrecision(3);
772 out << _resTime.datestr().c_str() << " " << _resTime.timestr().c_str()
773 << " Maximum Residuum " << maxRes << ' '
774 << corrs(sys)[maxResIndex-1]->_acName << ' ' << corrs(sys)[maxResIndex-1]->_prn.mid(0,3);
775 if (maxRes > _MAXRES) {
776 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
777 cmbParam* pp = _params[sys][iPar-1];
778 if (pp->type == cmbParam::offACSat &&
779 pp->AC == corrs(sys)[maxResIndex-1]->_acName &&
780 pp->prn == corrs(sys)[maxResIndex-1]->_prn.mid(0,3)) {
781 QQ_sav.Row(iPar) = 0.0;
782 QQ_sav.Column(iPar) = 0.0;
783 QQ_sav(iPar,iPar) = pp->sig0 * pp->sig0;
784 }
785 }
786
787 out << " Outlier" << "\n";
788 _QQ[sys] = QQ_sav;
789 corrs(sys).remove(maxResIndex-1);
790 }
791 else {
792 out << " OK" << "\n";
793 out.setRealNumberNotation(QTextStream::FixedNotation);
794 out.setRealNumberPrecision(4);
795 for (int ii = 0; ii < corrs(sys).size(); ii++) {
796 const cmbCorr* corr = corrs(sys)[ii];
797 out << _resTime.datestr().c_str() << ' '
798 << _resTime.timestr().c_str() << " "
799 << corr->_acName << ' ' << corr->_prn.mid(0,3);
800 out.setFieldWidth(10);
801 out << " res = " << vv[ii] << "\n";
802 out.setFieldWidth(0);
803 }
804 break;
805 }
806 }
807
808 return success;
809}
810
811// Print results
812////////////////////////////////////////////////////////////////////////////
813void bncComb::printResults(QTextStream& out,
814 const QMap<QString, cmbCorr*>& resCorr) {
815
816 QMapIterator<QString, cmbCorr*> it(resCorr);
817 while (it.hasNext()) {
818 it.next();
819 cmbCorr* corr = it.value();
820 const t_eph* eph = corr->_eph;
821 if (eph) {
822 ColumnVector xc(6);
823 ColumnVector vv(3);
824 if (eph->getCrd(_resTime, xc, vv, false) != success) {
825 continue;
826 }
827 out << _resTime.datestr().c_str() << " "
828 << _resTime.timestr().c_str() << " ";
829 out.setFieldWidth(3);
830 out << "Full Clock " << corr->_prn.mid(0,3) << " " << corr->_iod << " ";
831 out.setFieldWidth(14);
832 out << (xc(4) + corr->_dClkResult) * t_CST::c << "\n";
833 out.setFieldWidth(0);
834 }
835 else {
836 out << "bncComb::printResuls bug" << "\n";
837 }
838 }
839}
840
841// Send results to RTNet Decoder and directly to PPP Client
842////////////////////////////////////////////////////////////////////////////
843void bncComb::dumpResults(const QMap<QString, cmbCorr*>& resCorr) {
844
845 QList<t_orbCorr> orbCorrections;
846 QList<t_clkCorr> clkCorrections;
847
848 QString outLines;
849 unsigned year, month, day, hour, minute;
850 double sec;
851 _resTime.civil_date(year, month, day);
852 _resTime.civil_time(hour, minute, sec);
853
854 outLines.sprintf("* %4d %2d %2d %d %d %12.8f\n",
855 year, month, day, hour, minute, sec);
856
857 QMapIterator<QString, cmbCorr*> it(resCorr);
858 while (it.hasNext()) {
859 it.next();
860 cmbCorr* corr = it.value();
861
862 t_orbCorr orbCorr(corr->_orbCorr);
863 orbCorr._staID = "INTERNAL";
864 orbCorrections.push_back(orbCorr);
865
866 t_clkCorr clkCorr(corr->_clkCorr);
867 clkCorr._staID = "INTERNAL";
868 clkCorr._dClk = corr->_dClkResult;
869 clkCorr._dotDClk = 0.0;
870 clkCorr._dotDotDClk = 0.0;
871 clkCorrections.push_back(clkCorr);
872
873 ColumnVector xc(6);
874 ColumnVector vv(3);
875 corr->_eph->setClkCorr(dynamic_cast<const t_clkCorr*>(&clkCorr));
876 corr->_eph->setOrbCorr(dynamic_cast<const t_orbCorr*>(&orbCorr));
877 if (corr->_eph->getCrd(_resTime, xc, vv, true) != success) {
878 delete corr;
879 continue;
880 }
881
882 // Correction Phase Center --> CoM
883 // -------------------------------
884 ColumnVector dx(3); dx = 0.0;
885 if (_antex) {
886 double Mjd = _resTime.mjd() + _resTime.daysec()/86400.0;
887 if (_antex->satCoMcorrection(corr->_prn, Mjd, xc.Rows(1,3), dx) != success) {
888 dx = 0;
889 _log += "antenna not found " + corr->_prn.mid(0,3).toLatin1() + '\n';
890 }
891 }
892
893 outLines += corr->_prn.mid(0,3);
894 QString hlp;
895 hlp.sprintf(" APC 3 %15.4f %15.4f %15.4f"
896 " Clk 1 %15.4f"
897 " Vel 3 %15.4f %15.4f %15.4f"
898 " CoM 3 %15.4f %15.4f %15.4f\n",
899 xc(1), xc(2), xc(3),
900 xc(4) * t_CST::c,
901 vv(1), vv(2), vv(3),
902 xc(1)-dx(1), xc(2)-dx(2), xc(3)-dx(3));
903 outLines += hlp;
904
905 QString line;
906 int messageType = _ssrCorr->COTYPE_GPSCOMBINED;
907 int updateInt = 0;
908 line.sprintf("%d %d %d %.1f %s"
909 " %lu"
910 " %8.3f %8.3f %8.3f %8.3f"
911 " %10.5f %10.5f %10.5f %10.5f"
912 " %10.5f INTERNAL",
913 messageType, updateInt, _resTime.gpsw(), _resTime.gpssec(),
914 corr->_prn.mid(0,3).toLatin1().data(),
915 corr->_iod,
916 corr->_dClkResult * t_CST::c,
917 corr->_orbCorr._xr[0],
918 corr->_orbCorr._xr[1],
919 corr->_orbCorr._xr[2],
920 0.0,
921 corr->_orbCorr._dotXr[0],
922 corr->_orbCorr._dotXr[1],
923 corr->_orbCorr._dotXr[2],
924 0.0);
925
926 delete corr;
927 }
928
929 outLines += "EOE\n"; // End Of Epoch flag
930
931 if (!_rtnetDecoder) {
932 _rtnetDecoder = new bncRtnetDecoder();
933 }
934
935 vector<string> errmsg;
936 _rtnetDecoder->Decode(outLines.toLatin1().data(), outLines.length(), errmsg);
937
938 // Send new Corrections to PPP etc.
939 // --------------------------------
940 if (orbCorrections.size() > 0 && clkCorrections.size() > 0) {
941 emit newOrbCorrections(orbCorrections);
942 emit newClkCorrections(clkCorrections);
943 }
944}
945
946// Create First Design Matrix and Vector of Measurements
947////////////////////////////////////////////////////////////////////////////
948t_irc bncComb::createAmat(char sys, Matrix& AA, ColumnVector& ll, DiagonalMatrix& PP,
949 const ColumnVector& x0, QMap<QString, cmbCorr*>& resCorr) {
950
951 unsigned nPar = _params[sys].size();
952 unsigned nObs = corrs(sys).size();
953
954 if (nObs == 0) {
955 return failure;
956 }
957
958 int maxSat = _cmbSysPrn[sys];
959
960 const int nCon = (_method == filter) ? 1 + maxSat : 0;
961
962 AA.ReSize(nObs+nCon, nPar); AA = 0.0;
963 ll.ReSize(nObs+nCon); ll = 0.0;
964 PP.ReSize(nObs+nCon); PP = 1.0 / (sigObs * sigObs);
965
966 int iObs = 0;
967 QVectorIterator<cmbCorr*> itCorr(corrs(sys));
968 while (itCorr.hasNext()) {
969 cmbCorr* corr = itCorr.next();
970 QString prn = corr->_prn;
971
972 ++iObs;
973
974 if (corr->_acName == _masterOrbitAC[sys] && resCorr.find(prn) == resCorr.end()) {
975 resCorr[prn] = new cmbCorr(*corr);
976 }
977
978 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
979 cmbParam* pp = _params[sys][iPar-1];
980 AA(iObs, iPar) = pp->partial(sys, corr->_acName, prn);
981 }
982
983 ll(iObs) = (corr->_clkCorr._dClk * t_CST::c - corr->_codeBiasIF) - DotProduct(AA.Row(iObs), x0);
984 }
985
986 // Regularization
987 // --------------
988 if (_method == filter) {
989 const double Ph = 1.e6;
990 PP(nObs+1) = Ph;
991 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
992 cmbParam* pp = _params[sys][iPar-1];
993 if ( AA.Column(iPar).maximum_absolute_value() > 0.0 &&
994 pp->type == cmbParam::clkSat ) {
995 AA(nObs+1, iPar) = 1.0;
996 }
997 }
998 unsigned flag = 0;
999 if (sys == 'E') {
1000 flag = 1;
1001 }
1002 if (sys == 'R') {
1003 return success;
1004 }
1005 int iCond = 1;
1006 // GNSS
1007 for (unsigned iGnss = 1; iGnss <= _cmbSysPrn[sys]; iGnss++) {
1008 QString prn = QString("%1%2_%3").arg(sys).arg(iGnss, 2, 10, QChar('0')).arg(flag);
1009 ++iCond;
1010 PP(nObs+iCond) = Ph;
1011 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
1012 cmbParam* pp = _params[sys][iPar-1];
1013 if ( pp &&
1014 AA.Column(iPar).maximum_absolute_value() > 0.0 &&
1015 pp->type == cmbParam::offACSat &&
1016 pp->prn == prn) {
1017 AA(nObs+iCond, iPar) = 1.0;
1018 }
1019 }
1020 }
1021 }
1022
1023 return success;
1024}
1025
1026// Process Epoch - Single-Epoch Method
1027////////////////////////////////////////////////////////////////////////////
1028t_irc bncComb::processEpoch_singleEpoch(char sys, QTextStream& out,
1029 QMap<QString, cmbCorr*>& resCorr,
1030 ColumnVector& dx) {
1031
1032 // Check Satellite Positions for Outliers
1033 // --------------------------------------
1034 if (checkOrbits(sys, out) != success) {
1035 return failure;
1036 }
1037
1038 // Outlier Detection Loop
1039 // ----------------------
1040 while (true) {
1041
1042 // Remove Satellites that are not in Master
1043 // ----------------------------------------
1044 QMutableVectorIterator<cmbCorr*> it(corrs(sys));
1045 while (it.hasNext()) {
1046 cmbCorr* corr = it.next();
1047 QString prn = corr->_prn;
1048 bool foundMaster = false;
1049 QVectorIterator<cmbCorr*> itHlp(corrs(sys));
1050 while (itHlp.hasNext()) {
1051 cmbCorr* corrHlp = itHlp.next();
1052 QString prnHlp = corrHlp->_prn;
1053 QString ACHlp = corrHlp->_acName;
1054 if (ACHlp == _masterOrbitAC[sys] && prn == prnHlp) {
1055 foundMaster = true;
1056 break;
1057 }
1058 }
1059 if (!foundMaster) {
1060 delete corr;
1061 it.remove();
1062 }
1063 }
1064
1065 // Count Number of Observations per Satellite and per AC
1066 // -----------------------------------------------------
1067 QMap<QString, int> numObsPrn;
1068 QMap<QString, int> numObsAC;
1069 QVectorIterator<cmbCorr*> itCorr(corrs(sys));
1070 while (itCorr.hasNext()) {
1071 cmbCorr* corr = itCorr.next();
1072 QString prn = corr->_prn;
1073 QString AC = corr->_acName;
1074 if (numObsPrn.find(prn) == numObsPrn.end()) {
1075 numObsPrn[prn] = 1;
1076 }
1077 else {
1078 numObsPrn[prn] += 1;
1079 }
1080 if (numObsAC.find(AC) == numObsAC.end()) {
1081 numObsAC[AC] = 1;
1082 }
1083 else {
1084 numObsAC[AC] += 1;
1085 }
1086 }
1087
1088 // Clean-Up the Parameters
1089 // -----------------------
1090 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
1091 delete _params[sys][iPar-1];
1092 }
1093 _params[sys].clear();
1094
1095 // Set new Parameters
1096 // ------------------
1097 int nextPar = 0;
1098
1099 QMapIterator<QString, int> itAC(numObsAC);
1100 while (itAC.hasNext()) {
1101 itAC.next();
1102 const QString& AC = itAC.key();
1103 int numObs = itAC.value();
1104 if (AC != _masterOrbitAC[sys] && numObs > 0) {
1105 _params[sys].push_back(new cmbParam(cmbParam::offACgnss, ++nextPar, AC, ""));
1106 }
1107 }
1108
1109 QMapIterator<QString, int> itPrn(numObsPrn);
1110 while (itPrn.hasNext()) {
1111 itPrn.next();
1112 const QString& prn = itPrn.key();
1113 int numObs = itPrn.value();
1114 if (numObs > 0) {
1115 _params[sys].push_back(new cmbParam(cmbParam::clkSat, ++nextPar, "", prn));
1116 }
1117 }
1118
1119 int nPar = _params[sys].size();
1120 ColumnVector x0(nPar);
1121 x0 = 0.0;
1122
1123 // Create First-Design Matrix
1124 // --------------------------
1125 Matrix AA;
1126 ColumnVector ll;
1127 DiagonalMatrix PP;
1128 if (createAmat(sys, AA, ll, PP, x0, resCorr) != success) {
1129 return failure;
1130 }
1131
1132 ColumnVector vv;
1133 try {
1134 Matrix ATP = AA.t() * PP;
1135 SymmetricMatrix NN; NN << ATP * AA;
1136 ColumnVector bb = ATP * ll;
1137 _QQ[sys] = NN.i();
1138 dx = _QQ[sys] * bb;
1139 vv = ll - AA * dx;
1140 }
1141 catch (Exception& exc) {
1142 out << exc.what() << "\n";
1143 return failure;
1144 }
1145
1146 int maxResIndex;
1147 double maxRes = vv.maximum_absolute_value1(maxResIndex);
1148 out.setRealNumberNotation(QTextStream::FixedNotation);
1149 out.setRealNumberPrecision(3);
1150 out << _resTime.datestr().c_str() << " " << _resTime.timestr().c_str()
1151 << " Maximum Residuum " << maxRes << ' '
1152 << corrs(sys)[maxResIndex-1]->_acName << ' ' << corrs(sys)[maxResIndex-1]->_prn.mid(0,3);
1153
1154 if (maxRes > _MAXRES) {
1155 out << " Outlier" << "\n";
1156 delete corrs(sys)[maxResIndex-1];
1157 corrs(sys).remove(maxResIndex-1);
1158 }
1159 else {
1160 out << " OK" << "\n";
1161 out.setRealNumberNotation(QTextStream::FixedNotation);
1162 out.setRealNumberPrecision(3);
1163 for (int ii = 0; ii < vv.Nrows(); ii++) {
1164 const cmbCorr* corr = corrs(sys)[ii];
1165 out << _resTime.datestr().c_str() << ' '
1166 << _resTime.timestr().c_str() << " "
1167 << corr->_acName << ' ' << corr->_prn.mid(0,3);
1168 out.setFieldWidth(6);
1169 out << " res = " << vv[ii] << "\n";
1170 out.setFieldWidth(0);
1171 }
1172 return success;
1173 }
1174
1175 }
1176
1177 return failure;
1178}
1179
1180// Check Satellite Positions for Outliers
1181////////////////////////////////////////////////////////////////////////////
1182t_irc bncComb::checkOrbits(char sys, QTextStream& out) {
1183
1184 const double MAX_DISPLACEMENT = 0.20;
1185
1186 // Switch to last ephemeris (if possible)
1187 // --------------------------------------
1188 QMutableVectorIterator<cmbCorr*> im(corrs(sys));
1189 while (im.hasNext()) {
1190 cmbCorr* corr = im.next();
1191 QString prn = corr->_prn;
1192
1193 t_eph* ephLast = _ephUser.ephLast(prn);
1194 t_eph* ephPrev = _ephUser.ephPrev(prn);
1195
1196 if (ephLast == 0) {
1197 out << "checkOrbit: missing eph (not found) " << corr->_prn.mid(0,3) << "\n";
1198 delete corr;
1199 im.remove();
1200 }
1201 else if (corr->_eph == 0) {
1202 out << "checkOrbit: missing eph (zero) " << corr->_prn.mid(0,3) << "\n";
1203 delete corr;
1204 im.remove();
1205 }
1206 else {
1207 if ( corr->_eph == ephLast || corr->_eph == ephPrev ) {
1208 switchToLastEph(ephLast, corr);
1209 }
1210 else {
1211 out << "checkOrbit: missing eph (deleted) " << corr->_prn.mid(0,3) << "\n";
1212 delete corr;
1213 im.remove();
1214 }
1215 }
1216 }
1217
1218 while (true) {
1219
1220 // Compute Mean Corrections for all Satellites
1221 // -------------------------------------------
1222 QMap<QString, int> numCorr;
1223 QMap<QString, ColumnVector> meanRao;
1224 QVectorIterator<cmbCorr*> it(corrs(sys));
1225 while (it.hasNext()) {
1226 cmbCorr* corr = it.next();
1227 QString prn = corr->_prn;
1228 if (meanRao.find(prn) == meanRao.end()) {
1229 meanRao[prn].ReSize(4);
1230 meanRao[prn].Rows(1,3) = corr->_orbCorr._xr;
1231 meanRao[prn](4) = 1;
1232 }
1233 else {
1234 meanRao[prn].Rows(1,3) += corr->_orbCorr._xr;
1235 meanRao[prn](4) += 1;
1236 }
1237 if (numCorr.find(prn) == numCorr.end()) {
1238 numCorr[prn] = 1;
1239 }
1240 else {
1241 numCorr[prn] += 1;
1242 }
1243 }
1244
1245 // Compute Differences wrt. Mean, find Maximum
1246 // -------------------------------------------
1247 QMap<QString, cmbCorr*> maxDiff;
1248 it.toFront();
1249 while (it.hasNext()) {
1250 cmbCorr* corr = it.next();
1251 QString prn = corr->_prn;
1252 if (meanRao[prn](4) != 0) {
1253 meanRao[prn] /= meanRao[prn](4);
1254 meanRao[prn](4) = 0;
1255 }
1256 corr->_diffRao = corr->_orbCorr._xr - meanRao[prn].Rows(1,3);
1257 if (maxDiff.find(prn) == maxDiff.end()) {
1258 maxDiff[prn] = corr;
1259 }
1260 else {
1261 double normMax = maxDiff[prn]->_diffRao.NormFrobenius();
1262 double norm = corr->_diffRao.NormFrobenius();
1263 if (norm > normMax) {
1264 maxDiff[prn] = corr;
1265 }
1266 }
1267 }
1268
1269 if (_ACs.size() == 1) {
1270 break;
1271 }
1272
1273 // Remove Outliers
1274 // ---------------
1275 bool removed = false;
1276 QMutableVectorIterator<cmbCorr*> im(corrs(sys));
1277 while (im.hasNext()) {
1278 cmbCorr* corr = im.next();
1279 QString prn = corr->_prn;
1280 if (numCorr[prn] < 2) {
1281 delete corr;
1282 im.remove();
1283 }
1284 else if (corr == maxDiff[prn]) {
1285 double norm = corr->_diffRao.NormFrobenius();
1286 if (norm > MAX_DISPLACEMENT) {
1287 out << _resTime.datestr().c_str() << " "
1288 << _resTime.timestr().c_str() << " "
1289 << "Orbit Outlier: "
1290 << corr->_acName.toLatin1().data() << " "
1291 << prn.mid(0,3).toLatin1().data() << " "
1292 << corr->_iod << " "
1293 << norm << "\n";
1294 delete corr;
1295 im.remove();
1296 removed = true;
1297 }
1298 }
1299 }
1300
1301 if (!removed) {
1302 break;
1303 }
1304 }
1305
1306 return success;
1307}
1308
1309//
1310////////////////////////////////////////////////////////////////////////////
1311void bncComb::slotProviderIDChanged(QString mountPoint) {
1312 QMutexLocker locker(&_mutex);
1313
1314 QTextStream out(&_log, QIODevice::WriteOnly);
1315
1316 // Find the AC Name
1317 // ----------------
1318 QString acName;
1319 QListIterator<cmbAC*> icAC(_ACs);
1320 while (icAC.hasNext()) {
1321 cmbAC* AC = icAC.next();
1322 if (AC->mountPoint == mountPoint) {
1323 acName = AC->name;
1324 out << "Provider ID changed: AC " << AC->name.toLatin1().data() << " "
1325 << _resTime.datestr().c_str() << " "
1326 << _resTime.timestr().c_str() << "\n";
1327 break;
1328 }
1329 }
1330 if (acName.isEmpty()) {
1331 return;
1332 }
1333 QMapIterator<char, unsigned> itSys(_cmbSysPrn);
1334 while (itSys.hasNext()) {
1335 itSys.next();
1336 char sys = itSys.key();
1337 // Remove all corrections of the corresponding AC
1338 // ----------------------------------------------
1339 QListIterator<bncTime> itTime(_buffer[sys].keys());
1340 while (itTime.hasNext()) {
1341 bncTime epoTime = itTime.next();
1342 QVector<cmbCorr*>& corrVec = _buffer[sys][epoTime].corrs;
1343 QMutableVectorIterator<cmbCorr*> it(corrVec);
1344 while (it.hasNext()) {
1345 cmbCorr* corr = it.next();
1346 if (acName == corr->_acName) {
1347 delete corr;
1348 it.remove();
1349 }
1350 }
1351 }
1352
1353 // Reset Satellite Offsets
1354 // -----------------------
1355 if (_method == filter) {
1356 for (int iPar = 1; iPar <= _params[sys].size(); iPar++) {
1357 cmbParam* pp = _params[sys][iPar-1];
1358 if (pp->AC == acName && pp->type == cmbParam::offACSat) {
1359 pp->xx = 0.0;
1360 _QQ[sys].Row(iPar) = 0.0;
1361 _QQ[sys].Column(iPar) = 0.0;
1362 _QQ[sys](iPar,iPar) = pp->sig0 * pp->sig0;
1363 }
1364 }
1365 }
1366 }
1367}
Note: See TracBrowser for help on using the repository browser.