source: ntrip/trunk/BNC/combination/bnccomb.cpp@ 3444

Last change on this file since 3444 was 3444, checked in by mervart, 13 years ago
File size: 19.5 KB
RevLine 
[2898]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
[2933]17#include <newmatio.h>
[2921]18#include <iomanip>
[3214]19#include <sstream>
[2898]20
21#include "bnccomb.h"
22#include "bncapp.h"
[3201]23#include "upload/bncrtnetdecoder.h"
[2910]24#include "bncsettings.h"
[2933]25#include "bncmodel.h"
[2988]26#include "bncutils.h"
[3027]27#include "bncpppclient.h"
[3181]28#include "bncsp3.h"
[3052]29#include "bncantex.h"
[3055]30#include "bnctides.h"
[2898]31
[3438]32const int moduloTime = 10;
[2898]33
[3438]34const double sig0_offAC = 1000.0;
[3442]35const double sig0_offACSat = 1000.0;
[3438]36const double sigP_offACSat = 0.0;
[3442]37const double sig0_clkSat = 10.0;
38const double sigP_clkSat = 0.1;
[3438]39
[3440]40const double sigObs = 0.05;
41
[3134]42const int MAXPRN_GPS = 32;
43
[3438]44using namespace std;
45
[2898]46// Constructor
47////////////////////////////////////////////////////////////////////////////
[3429]48cmbParam::cmbParam(parType type_, int index_,
49 const QString& ac_, const QString& prn_) {
[3032]50
[3433]51 type = type_;
52 index = index_;
53 AC = ac_;
54 prn = prn_;
55 xx = 0.0;
[3442]56 eph = 0;
[3429]57
58 if (type == offAC) {
[3439]59 epoSpec = true;
60 sig0 = sig0_offAC;
61 sigP = sig0;
[3429]62 }
63 else if (type == offACSat) {
[3439]64 epoSpec = false;
65 sig0 = sig0_offACSat;
66 sigP = sigP_offACSat;
[3429]67 }
68 else if (type == clkSat) {
[3439]69 epoSpec = false;
70 sig0 = sig0_clkSat;
71 sigP = sigP_clkSat;
[3429]72 }
[2933]73}
74
75// Destructor
76////////////////////////////////////////////////////////////////////////////
77cmbParam::~cmbParam() {
78}
79
80// Partial
81////////////////////////////////////////////////////////////////////////////
[3429]82double cmbParam::partial(const QString& AC_, const QString& prn_) {
[2933]83
[3429]84 if (type == offAC) {
[3032]85 if (AC == AC_) {
[2934]86 return 1.0;
87 }
88 }
[3429]89 else if (type == offACSat) {
90 if (AC == AC_ && prn == prn_) {
[2933]91 return 1.0;
92 }
93 }
[3429]94 else if (type == clkSat) {
95 if (prn == prn_) {
[2933]96 return 1.0;
97 }
98 }
99
100 return 0.0;
101}
102
[2990]103//
104////////////////////////////////////////////////////////////////////////////
105QString cmbParam::toString() const {
[2933]106
[2990]107 QString outStr;
108
[3429]109 if (type == offAC) {
[2992]110 outStr = "AC offset " + AC;
[2990]111 }
[3429]112 else if (type == offACSat) {
[2992]113 outStr = "Sat Offset " + AC + " " + prn;
[2990]114 }
[3429]115 else if (type == clkSat) {
[2992]116 outStr = "Clk Corr " + prn;
[2990]117 }
[2933]118
[2990]119 return outStr;
120}
121
[2933]122// Constructor
123////////////////////////////////////////////////////////////////////////////
[2898]124bncComb::bncComb() {
[2910]125
126 bncSettings settings;
127
128 QStringList combineStreams = settings.value("combineStreams").toStringList();
[2918]129
[3143]130 if (combineStreams.size() >= 1 && !combineStreams[0].isEmpty()) {
[2910]131 QListIterator<QString> it(combineStreams);
132 while (it.hasNext()) {
133 QStringList hlp = it.next().split(" ");
[2918]134 cmbAC* newAC = new cmbAC();
135 newAC->mountPoint = hlp[0];
136 newAC->name = hlp[1];
137 newAC->weight = hlp[2].toDouble();
[3429]138 _ACs.append(newAC);
[2910]139 }
140 }
[2927]141
[3211]142 _rtnetDecoder = 0;
[3201]143
[2990]144 connect(this, SIGNAL(newMessage(QByteArray,bool)),
145 ((bncApp*)qApp), SLOT(slotMessage(const QByteArray,bool)));
[2933]146
[3032]147
148 // Initialize Parameters (model: Clk_Corr = AC_Offset + Sat_Offset + Clk)
149 // ----------------------------------------------------------------------
[2933]150 int nextPar = 0;
[3429]151 QListIterator<cmbAC*> it(_ACs);
[2991]152 while (it.hasNext()) {
[3429]153 cmbAC* AC = it.next();
154 _params.push_back(new cmbParam(cmbParam::offAC, ++nextPar, AC->name, ""));
[3134]155 for (int iGps = 1; iGps <= MAXPRN_GPS; iGps++) {
156 QString prn = QString("G%1").arg(iGps, 2, 10, QChar('0'));
[3429]157 _params.push_back(new cmbParam(cmbParam::offACSat, ++nextPar,
158 AC->name, prn));
[2991]159 }
160 }
[3134]161 for (int iGps = 1; iGps <= MAXPRN_GPS; iGps++) {
[2933]162 QString prn = QString("G%1").arg(iGps, 2, 10, QChar('0'));
[3429]163 _params.push_back(new cmbParam(cmbParam::clkSat, ++nextPar, "", prn));
[2933]164 }
165
[3032]166 // Initialize Variance-Covariance Matrix
167 // -------------------------------------
168 _QQ.ReSize(_params.size());
[2933]169 _QQ = 0.0;
170 for (int iPar = 1; iPar <= _params.size(); iPar++) {
171 cmbParam* pp = _params[iPar-1];
[3439]172 _QQ(iPar,iPar) = pp->sig0 * pp->sig0;
[2933]173 }
[3035]174
[3052]175 // ANTEX File
176 // ----------
177 _antex = 0;
178 QString antexFileName = settings.value("pppAntex").toString();
179 if (!antexFileName.isEmpty()) {
180 _antex = new bncAntex();
181 if (_antex->readFile(antexFileName) != success) {
182 emit newMessage("wrong ANTEX file", true);
183 delete _antex;
184 _antex = 0;
185 }
186 }
[3138]187
[3329]188 // Maximal Residuum
189 // ----------------
190 _MAXRES = settings.value("cmbMaxres").toDouble();
191 if (_MAXRES <= 0.0) {
192 _MAXRES = 999.0;
193 }
[2898]194}
195
196// Destructor
197////////////////////////////////////////////////////////////////////////////
198bncComb::~bncComb() {
[3429]199 QListIterator<cmbAC*> icAC(_ACs);
200 while (icAC.hasNext()) {
201 delete icAC.next();
[2918]202 }
[3201]203 delete _rtnetDecoder;
[3052]204 delete _antex;
[3296]205 for (int iPar = 1; iPar <= _params.size(); iPar++) {
206 delete _params[iPar-1];
207 }
[3434]208 QVectorIterator<cmbCorr*> itCorr(corrs());
[3429]209 while (itCorr.hasNext()) {
210 delete itCorr.next();
211 }
[2898]212}
213
[2928]214// Read and store one correction line
[2898]215////////////////////////////////////////////////////////////////////////////
216void bncComb::processCorrLine(const QString& staID, const QString& line) {
[2906]217 QMutexLocker locker(&_mutex);
[2913]218
[3431]219 // Find the AC Name
220 // ----------------
221 QString acName;
222 QListIterator<cmbAC*> icAC(_ACs);
223 while (icAC.hasNext()) {
224 cmbAC* AC = icAC.next();
225 if (AC->mountPoint == staID) {
226 acName = AC->name;
227 break;
228 }
229 }
230 if (acName.isEmpty()) {
231 return;
232 }
233
[2918]234 // Read the Correction
235 // -------------------
[3429]236 cmbCorr* newCorr = new cmbCorr();
[3431]237 newCorr->acName = acName;
[2913]238 if (!newCorr->readLine(line) == success) {
239 delete newCorr;
240 return;
241 }
242
[3274]243 // Check Modulo Time
244 // -----------------
245 if (int(newCorr->tt.gpssec()) % moduloTime != 0.0) {
246 delete newCorr;
247 return;
248 }
249
[3299]250 // Delete old corrections
251 // ----------------------
[3437]252 if (_resTime.valid() && newCorr->tt <= _resTime) {
[2924]253 delete newCorr;
254 return;
255 }
256
[3029]257 // Check the Ephemeris
258 //--------------------
[2986]259 if (_eph.find(newCorr->prn) == _eph.end()) {
260 delete newCorr;
261 return;
262 }
263 else {
264 t_eph* lastEph = _eph[newCorr->prn]->last;
265 t_eph* prevEph = _eph[newCorr->prn]->prev;
[3029]266 if (lastEph && lastEph->IOD() == newCorr->iod) {
267 newCorr->eph = lastEph;
[2986]268 }
[3029]269 else if (prevEph && prevEph->IOD() == newCorr->iod) {
270 newCorr->eph = prevEph;
[3429]271 switchToLastEph(lastEph, newCorr);
[3029]272 }
273 else {
[2986]274 delete newCorr;
275 return;
276 }
277 }
278
[3435]279 // Process previous Epoch(s)
280 // -------------------------
281 QListIterator<bncTime> itTime(_buffer.keys());
282 while (itTime.hasNext()) {
283 bncTime epoTime = itTime.next();
[3438]284 if (epoTime < newCorr->tt - moduloTime) {
[3435]285 _resTime = epoTime;
286 processEpoch();
287 }
[2927]288 }
289
[3429]290 // Merge or add the correction
291 // ---------------------------
[3435]292 QVector<cmbCorr*>& corrs = _buffer[newCorr->tt].corrs;
[3429]293 cmbCorr* existingCorr = 0;
[3435]294 QVectorIterator<cmbCorr*> itCorr(corrs);
[3429]295 while (itCorr.hasNext()) {
296 cmbCorr* hlp = itCorr.next();
297 if (hlp->prn == newCorr->prn && hlp->acName == newCorr->prn) {
298 existingCorr = hlp;
[2918]299 break;
300 }
301 }
[3429]302 if (existingCorr) {
[3298]303 delete newCorr;
[3429]304 existingCorr->readLine(line); // merge (multiple messages)
[2918]305 }
[2919]306 else {
[3435]307 corrs.append(newCorr);
[2919]308 }
[2898]309}
310
[2986]311// Change the correction so that it refers to last received ephemeris
312////////////////////////////////////////////////////////////////////////////
[3029]313void bncComb::switchToLastEph(const t_eph* lastEph, t_corr* corr) {
[3028]314
[3429]315 if (corr->eph == lastEph) {
316 return;
317 }
318
[2987]319 ColumnVector oldXC(4);
320 ColumnVector oldVV(3);
[3029]321 corr->eph->position(corr->tt.gpsw(), corr->tt.gpssec(),
322 oldXC.data(), oldVV.data());
[2988]323
[2987]324 ColumnVector newXC(4);
325 ColumnVector newVV(3);
[3029]326 lastEph->position(corr->tt.gpsw(), corr->tt.gpssec(),
[2987]327 newXC.data(), newVV.data());
[2988]328
329 ColumnVector dX = newXC.Rows(1,3) - oldXC.Rows(1,3);
[2989]330 ColumnVector dV = newVV - oldVV;
331 double dC = newXC(4) - oldXC(4);
332
[2988]333 ColumnVector dRAO(3);
334 XYZ_to_RSW(newXC.Rows(1,3), newVV, dX, dRAO);
[2989]335
336 ColumnVector dDotRAO(3);
337 XYZ_to_RSW(newXC.Rows(1,3), newVV, dV, dDotRAO);
338
[3442]339 QString msg = "switch corr " + corr->prn
[3029]340 + QString(" %1 -> %2 %3").arg(corr->iod,3)
[3013]341 .arg(lastEph->IOD(),3).arg(dC*t_CST::c, 8, 'f', 4);
342
[3029]343 emit newMessage(msg.toAscii(), false);
[3028]344
[3029]345 corr->iod = lastEph->IOD();
346 corr->eph = lastEph;
[3031]347 corr->rao += dRAO;
348 corr->dotRao += dDotRAO;
[3029]349 corr->dClk -= dC;
[2986]350}
351
[3429]352// Process Epoch
[2928]353////////////////////////////////////////////////////////////////////////////
[3429]354void bncComb::processEpoch() {
[2918]355
[3429]356 int nPar = _params.size();
357
[2990]358 _log.clear();
359
360 QTextStream out(&_log, QIODevice::WriteOnly);
361
[3371]362 out << endl << "Combination:" << endl
[3275]363 << "------------------------------" << endl;
[2990]364
[3433]365 // Observation Statistics
366 // ----------------------
367 QListIterator<cmbAC*> icAC(_ACs);
368 while (icAC.hasNext()) {
369 cmbAC* AC = icAC.next();
370 AC->numObs = 0;
[3434]371 QVectorIterator<cmbCorr*> itCorr(corrs());
[3433]372 while (itCorr.hasNext()) {
373 cmbCorr* corr = itCorr.next();
374 if (corr->acName == AC->name) {
375 AC->numObs += 1;
376 }
377 }
378 out << AC->name.toAscii().data() << ": " << AC->numObs << endl;
379 }
380
[3429]381 // Prediction Step
382 // ---------------
[2933]383 ColumnVector x0(nPar);
384 for (int iPar = 1; iPar <= _params.size(); iPar++) {
[3442]385 cmbParam* pp = _params[iPar-1];
386 QString prn = pp->prn;
387 if (!prn.isEmpty() && _eph.find(prn) != _eph.end()) {
388 switchToLastEph(_eph[prn]->last, pp);
389 }
[3439]390 if (pp->epoSpec) {
391 pp->xx = 0.0;
392 _QQ.Row(iPar) = 0.0;
393 _QQ.Column(iPar) = 0.0;
394 _QQ(iPar,iPar) = pp->sig0 * pp->sig0;
395 }
396 else {
397 _QQ(iPar,iPar) += pp->sigP * pp->sigP;
398 }
[2933]399 x0(iPar) = pp->xx;
400 }
401
[3441]402 SymmetricMatrix QQ_sav = _QQ;
403
404 ColumnVector dx;
[3429]405 QMap<QString, t_corr*> resCorr;
[3441]406
407 // Update and outlier detection loop
408 // ---------------------------------
409 while (true) {
[3135]410
[3441]411 Matrix AA;
412 ColumnVector ll;
413 DiagonalMatrix PP;
[3429]414
[3441]415 if (createAmat(AA, ll, PP, x0, resCorr) != success) {
416 return;
417 }
[2933]418
[3429]419 bncModel::kalman(AA, ll, PP, _QQ, dx);
420 ColumnVector vv = ll - AA * dx;
[3080]421
[3429]422 int maxResIndex;
423 double maxRes = vv.maximum_absolute_value1(maxResIndex);
424 out.setRealNumberNotation(QTextStream::FixedNotation);
425 out.setRealNumberPrecision(3);
426 out << _resTime.datestr().c_str() << " " << _resTime.timestr().c_str()
[3432]427 << " Maximum Residuum " << maxRes << ' '
[3434]428 << corrs()[maxResIndex-1]->acName << ' ' << corrs()[maxResIndex-1]->prn;
[3080]429
[3432]430 if (maxRes > _MAXRES) {
431 for (int iPar = 1; iPar <= _params.size(); iPar++) {
432 cmbParam* pp = _params[iPar-1];
433 if (pp->type == cmbParam::offACSat &&
[3434]434 pp->AC == corrs()[maxResIndex-1]->acName &&
435 pp->prn == corrs()[maxResIndex-1]->prn) {
[3432]436 QQ_sav.Row(iPar) = 0.0;
437 QQ_sav.Column(iPar) = 0.0;
[3439]438 QQ_sav(iPar,iPar) = pp->sig0 * pp->sig0;
[3432]439 }
440 }
441
442 out << " Outlier" << endl;
443 _QQ = QQ_sav;
[3441]444 corrs().remove(maxResIndex-1);
[3432]445 }
446 else {
447 out << " OK" << endl;
448 break;
449 }
450 }
451
452 // Update Parameter Values
453 // -----------------------
[3429]454 for (int iPar = 1; iPar <= _params.size(); iPar++) {
455 cmbParam* pp = _params[iPar-1];
456 pp->xx += dx(iPar);
457 if (pp->type == cmbParam::clkSat) {
458 if (resCorr.find(pp->prn) != resCorr.end()) {
459 resCorr[pp->prn]->dClk = pp->xx / t_CST::c;
[3080]460 }
461 }
[3429]462 out << _resTime.datestr().c_str() << " "
463 << _resTime.timestr().c_str() << " ";
464 out.setRealNumberNotation(QTextStream::FixedNotation);
465 out.setFieldWidth(8);
466 out.setRealNumberPrecision(4);
467 out << pp->toString() << " "
468 << pp->xx << " +- " << sqrt(_QQ(pp->index,pp->index)) << endl;
469 out.setFieldWidth(0);
[2918]470 }
[2919]471
[3432]472 // Print Results
473 // -------------
[3429]474 printResults(out, resCorr);
475 dumpResults(resCorr);
[2928]476
[2990]477 emit newMessage(_log, false);
[3296]478
[3432]479 // Delete Data
480 // -----------
[3434]481 _buffer.remove(_resTime);
[2918]482}
[3011]483
[3201]484// Print results
[3011]485////////////////////////////////////////////////////////////////////////////
[3429]486void bncComb::printResults(QTextStream& out,
[3011]487 const QMap<QString, t_corr*>& resCorr) {
488
489 QMapIterator<QString, t_corr*> it(resCorr);
490 while (it.hasNext()) {
491 it.next();
492 t_corr* corr = it.value();
[3029]493 const t_eph* eph = corr->eph;
[3015]494 if (eph) {
495 double xx, yy, zz, cc;
[3429]496 eph->position(_resTime.gpsw(), _resTime.gpssec(), xx, yy, zz, cc);
[3015]497
[3429]498 out << _resTime.datestr().c_str() << " "
499 << _resTime.timestr().c_str() << " ";
[3015]500 out.setFieldWidth(3);
501 out << "Full Clock " << corr->prn << " " << corr->iod << " ";
502 out.setFieldWidth(14);
503 out << (cc + corr->dClk) * t_CST::c << endl;
[3370]504 out.setFieldWidth(0);
[3015]505 }
506 else {
507 out << "bncComb::printResuls bug" << endl;
508 }
[3011]509 }
510}
[3202]511
512// Send results to RTNet Decoder and directly to PPP Client
513////////////////////////////////////////////////////////////////////////////
[3429]514void bncComb::dumpResults(const QMap<QString, t_corr*>& resCorr) {
[3202]515
[3214]516 ostringstream out; out.setf(std::ios::fixed);
[3216]517 QStringList corrLines;
[3214]518
519 unsigned year, month, day, hour, minute;
520 double sec;
[3429]521 _resTime.civil_date(year, month, day);
522 _resTime.civil_time(hour, minute, sec);
[3214]523
524 out << "* "
525 << setw(4) << year << " "
526 << setw(2) << month << " "
527 << setw(2) << day << " "
528 << setw(2) << hour << " "
529 << setw(2) << minute << " "
530 << setw(12) << setprecision(8) << sec << " "
531 << endl;
532
[3202]533 QMapIterator<QString, t_corr*> it(resCorr);
534 while (it.hasNext()) {
535 it.next();
536 t_corr* corr = it.value();
537
[3214]538 double dT = 60.0;
[3202]539
[3214]540 for (int iTime = 1; iTime <= 2; iTime++) {
541
[3429]542 bncTime time12 = (iTime == 1) ? _resTime : _resTime + dT;
[3214]543
544 ColumnVector xc(4);
545 ColumnVector vv(3);
546 corr->eph->position(time12.gpsw(), time12.gpssec(),
547 xc.data(), vv.data());
548 bncPPPclient::applyCorr(time12, corr, xc, vv);
549
550 // Relativistic Correction
551 // -----------------------
552 double relCorr = - 2.0 * DotProduct(xc.Rows(1,3),vv) / t_CST::c / t_CST::c;
553 xc(4) -= relCorr;
554
555 // Code Biases
556 // -----------
557 double dcbP1C1 = 0.0;
558 double dcbP1P2 = 0.0;
559
560 // Correction Phase Center --> CoM
561 // -------------------------------
562 ColumnVector dx(3); dx = 0.0;
563 if (_antex) {
564 double Mjd = time12.mjd() + time12.daysec()/86400.0;
565 if (_antex->satCoMcorrection(corr->prn, Mjd, xc.Rows(1,3), dx) == success) {
566 xc(1) -= dx(1);
567 xc(2) -= dx(2);
568 xc(3) -= dx(3);
569 }
570 else {
571 cout << "antenna not found" << endl;
572 }
573 }
574
575 if (iTime == 1) {
576 out << 'P' << corr->prn.toAscii().data()
577 << setw(14) << setprecision(6) << xc(1) / 1000.0
578 << setw(14) << setprecision(6) << xc(2) / 1000.0
579 << setw(14) << setprecision(6) << xc(3) / 1000.0
580 << setw(14) << setprecision(6) << xc(4) * 1e6
581 << setw(14) << setprecision(6) << relCorr * 1e6
582 << setw(8) << setprecision(3) << dx(1)
583 << setw(8) << setprecision(3) << dx(2)
584 << setw(8) << setprecision(3) << dx(3)
585 << setw(8) << setprecision(3) << dcbP1C1
586 << setw(8) << setprecision(3) << dcbP1P2
587 << setw(6) << setprecision(1) << dT;
[3216]588
[3218]589 QString line;
[3217]590 int messageType = COTYPE_GPSCOMBINED;
[3218]591 int updateInt = 0;
592 line.sprintf("%d %d %d %.1f %s"
593 " %3d"
594 " %8.3f %8.3f %8.3f %8.3f"
595 " %10.5f %10.5f %10.5f %10.5f"
[3262]596 " %10.5f %10.5f %10.5f %10.5f INTERNAL",
[3218]597 messageType, updateInt, time12.gpsw(), time12.gpssec(),
598 corr->prn.toAscii().data(),
599 corr->iod,
[3219]600 corr->dClk * t_CST::c,
[3218]601 corr->rao[0],
602 corr->rao[1],
603 corr->rao[2],
[3219]604 corr->dotDClk * t_CST::c,
[3218]605 corr->dotRao[0],
606 corr->dotRao[1],
607 corr->dotRao[2],
[3262]608 corr->dotDotDClk * t_CST::c,
609 corr->dotDotRao[0],
610 corr->dotDotRao[1],
611 corr->dotDotRao[2]);
[3220]612 corrLines << line;
[3214]613 }
614 else {
615 out << setw(14) << setprecision(6) << xc(1) / 1000.0
616 << setw(14) << setprecision(6) << xc(2) / 1000.0
617 << setw(14) << setprecision(6) << xc(3) / 1000.0 << endl;
618 }
619 }
620
621 delete corr;
622 }
[3228]623 out << "EOE" << endl; // End Of Epoch flag
[3214]624
[3215]625 if (!_rtnetDecoder) {
626 _rtnetDecoder = new bncRtnetDecoder();
627 }
[3221]628
[3215]629 vector<string> errmsg;
[3221]630 _rtnetDecoder->Decode((char*) out.str().data(), out.str().size(), errmsg);
[3215]631
[3216]632 // Optionally send new Corrections to PPP
633 // --------------------------------------
634 bncApp* app = (bncApp*) qApp;
635 if (app->_bncPPPclient) {
636 app->_bncPPPclient->slotNewCorrections(corrLines);
637 }
[3202]638}
[3440]639
640// Create First Design Matrix and Vector of Measurements
641////////////////////////////////////////////////////////////////////////////
642t_irc bncComb::createAmat(Matrix& AA, ColumnVector& ll, DiagonalMatrix& PP,
643 const ColumnVector& x0,
644 QMap<QString, t_corr*>& resCorr) {
645
646 unsigned nPar = _params.size();
647 unsigned nObs = corrs().size();
648
649 if (nObs == 0) {
650 return failure;
651 }
652
[3442]653 const int nCon = 2;
[3440]654
655 AA.ReSize(nObs+nCon, nPar); AA = 0.0;
656 ll.ReSize(nObs+nCon); ll = 0.0;
657 PP.ReSize(nObs+nCon); PP = 1.0 / (sigObs * sigObs);
658
659 int iObs = 0;
660
661 QVectorIterator<cmbCorr*> itCorr(corrs());
662 while (itCorr.hasNext()) {
663 cmbCorr* corr = itCorr.next();
664 QString prn = corr->prn;
665 switchToLastEph(_eph[prn]->last, corr);
666 ++iObs;
667
668 if (resCorr.find(prn) == resCorr.end()) {
669 resCorr[prn] = new t_corr(*corr);
670 }
671
672 for (int iPar = 1; iPar <= _params.size(); iPar++) {
673 cmbParam* pp = _params[iPar-1];
674 AA(iObs, iPar) = pp->partial(corr->acName, prn);
675 }
676
677 ll(iObs) = corr->dClk * t_CST::c - DotProduct(AA.Row(iObs), x0);
678 }
679
680 // Regularization
681 // --------------
682 const double Ph = 1.e6;
[3442]683 PP(nObs+1) = Ph;
684 PP(nObs+2) = Ph;
[3440]685 for (int iPar = 1; iPar <= _params.size(); iPar++) {
686 cmbParam* pp = _params[iPar-1];
[3442]687 if (pp->type == cmbParam::clkSat) {
688 AA(nObs+1, iPar) = 1.0;
[3440]689 }
[3442]690 else if (pp->type == cmbParam::offAC) {
691 AA(nObs+2, iPar) = 1.0;
692 }
[3440]693 }
694
[3442]695 return success;
696}
697
698// Change the parameter so that it refers to last received ephemeris
699////////////////////////////////////////////////////////////////////////////
700void bncComb::switchToLastEph(const t_eph* lastEph, cmbParam* pp) {
701
702 if (pp->type != cmbParam::clkSat) {
703 return;
[3440]704 }
705
[3442]706 if (pp->eph == 0) {
707 pp->eph = lastEph;
708 return;
[3440]709 }
710
[3442]711 if (pp->eph == lastEph) {
712 return;
713 }
714
715 ColumnVector oldXC(4);
716 ColumnVector oldVV(3);
717 pp->eph->position(_resTime.gpsw(), _resTime.gpssec(),
718 oldXC.data(), oldVV.data());
719
720 ColumnVector newXC(4);
721 ColumnVector newVV(3);
722 lastEph->position(_resTime.gpsw(), _resTime.gpssec(),
723 newXC.data(), newVV.data());
724
725 double dC = newXC(4) - oldXC(4);
726
727 QString msg = "switch param " + pp->prn
728 + QString(" %1 -> %2 %3").arg(pp->eph->IOD(),3)
729 .arg(lastEph->IOD(),3).arg(dC*t_CST::c, 8, 'f', 4);
730
731 emit newMessage(msg.toAscii(), false);
732
733 pp->eph = lastEph;
[3444]734 pp->xx -= dC * t_CST::c;
[3440]735}
[3442]736
Note: See TracBrowser for help on using the repository browser.