source: ntrip/trunk/BNC/bncmodel.cpp@ 2242

Last change on this file since 2242 was 2242, checked in by mervart, 14 years ago

* empty log message *

File size: 24.8 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: bncParam, bncModel
30 *
31 * Purpose: Model for PPP
32 *
33 * Author: L. Mervart
34 *
35 * Created: 01-Dec-2009
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iomanip>
42#include <cmath>
43#include <newmatio.h>
44#include <sstream>
45
46#include "bncmodel.h"
47#include "bncapp.h"
48#include "bncpppclient.h"
49#include "bancroft.h"
50#include "bncutils.h"
51#include "bncsettings.h"
52
53using namespace std;
54
55const unsigned MINOBS = 4;
56const double MINELE = 10.0 * M_PI / 180.0;
57const double MAXRES_CODE = 10.0;
58const double MAXRES_PHASE = 0.10;
59const double sig_crd_0 = 100.0;
60const double sig_crd_p = 100.0;
61const double sig_clk_0 = 1000.0;
62const double sig_trp_0 = 0.01;
63const double sig_trp_p = 1e-6;
64const double sig_amb_0 = 1000.0;
65const double sig_P3 = 1.0;
66const double sig_L3 = 0.01;
67
68// Constructor
69////////////////////////////////////////////////////////////////////////////
70bncParam::bncParam(bncParam::parType typeIn, int indexIn,
71 const QString& prnIn) {
72 type = typeIn;
73 index = indexIn;
74 prn = prnIn;
75 index_old = 0;
76 xx = 0.0;
77}
78
79// Destructor
80////////////////////////////////////////////////////////////////////////////
81bncParam::~bncParam() {
82}
83
84// Partial
85////////////////////////////////////////////////////////////////////////////
86double bncParam::partial(t_satData* satData, bool phase) {
87
88 // Coordinates
89 // -----------
90 if (type == CRD_X) {
91 return (xx - satData->xx(1)) / satData->rho;
92 }
93 else if (type == CRD_Y) {
94 return (xx - satData->xx(2)) / satData->rho;
95 }
96 else if (type == CRD_Z) {
97 return (xx - satData->xx(3)) / satData->rho;
98 }
99
100 // Receiver Clocks
101 // ---------------
102 else if (type == RECCLK_GPS) {
103 if (satData->prn[0] == 'G') {
104 return 1.0;
105 }
106 else {
107 return 0.0;
108 }
109 }
110 else if (type == RECCLK_GLO) {
111 if (satData->prn[0] == 'R') {
112 return 1.0;
113 }
114 else {
115 return 0.0;
116 }
117 }
118
119 // Troposphere
120 // -----------
121 else if (type == TROPO) {
122 return 1.0 / sin(satData->eleSat);
123 }
124
125 // Ambiguities
126 // -----------
127 else if (type == AMB_L3) {
128 if (phase && satData->prn == prn) {
129 return 1.0;
130 }
131 else {
132 return 0.0;
133 }
134 }
135
136 // Default return
137 // --------------
138 return 0.0;
139}
140
141// Constructor
142////////////////////////////////////////////////////////////////////////////
143bncModel::bncModel(QByteArray staID) {
144
145 _staID = staID;
146
147 connect(this, SIGNAL(newMessage(QByteArray,bool)),
148 ((bncApp*)qApp), SLOT(slotMessage(const QByteArray,bool)));
149
150 bncSettings settings;
151
152 _static = false;
153 if ( Qt::CheckState(settings.value("pppStatic").toInt()) == Qt::Checked) {
154 _static = true;
155 }
156
157 _usePhase = false;
158 if ( Qt::CheckState(settings.value("pppUsePhase").toInt()) == Qt::Checked) {
159 _usePhase = true;
160 }
161
162 _estTropo = false;
163 if ( Qt::CheckState(settings.value("pppEstTropo").toInt()) == Qt::Checked) {
164 _estTropo = true;
165 }
166
167 _xcBanc.ReSize(4); _xcBanc = 0.0;
168 _ellBanc.ReSize(3); _ellBanc = 0.0;
169
170 if ( Qt::CheckState(settings.value("pppGLONASS").toInt()) == Qt::Checked) {
171 _useGlonass = true;
172 }
173 else {
174 _useGlonass = false;
175 }
176
177 int nextPar = 0;
178 _params.push_back(new bncParam(bncParam::CRD_X, ++nextPar, ""));
179 _params.push_back(new bncParam(bncParam::CRD_Y, ++nextPar, ""));
180 _params.push_back(new bncParam(bncParam::CRD_Z, ++nextPar, ""));
181 _params.push_back(new bncParam(bncParam::RECCLK_GPS, ++nextPar, ""));
182 if (_useGlonass) {
183 _params.push_back(new bncParam(bncParam::RECCLK_GLO, ++nextPar, ""));
184 }
185 if (_estTropo) {
186 _params.push_back(new bncParam(bncParam::TROPO, ++nextPar, ""));
187 }
188
189 unsigned nPar = _params.size();
190
191 _QQ.ReSize(nPar);
192
193 _QQ = 0.0;
194
195 for (int iPar = 1; iPar <= _params.size(); iPar++) {
196 bncParam* pp = _params[iPar-1];
197 if (pp->isCrd()) {
198 _QQ(iPar,iPar) = sig_crd_0 * sig_crd_0;
199 }
200 else if (pp->isClk()) {
201 _QQ(iPar,iPar) = sig_clk_0 * sig_clk_0;
202 }
203 else if (pp->type == bncParam::TROPO) {
204 _QQ(iPar,iPar) = sig_trp_0 * sig_trp_0;
205 }
206 }
207
208 // NMEA Output
209 // -----------
210 QString nmeaFileName = settings.value("nmeaFile").toString();
211 if (nmeaFileName.isEmpty()) {
212 _nmeaFile = 0;
213 _nmeaStream = 0;
214 }
215 else {
216 expandEnvVar(nmeaFileName);
217 _nmeaFile = new QFile(nmeaFileName);
218 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
219 _nmeaFile->open(QIODevice::WriteOnly | QIODevice::Append);
220 }
221 else {
222 _nmeaFile->open(QIODevice::WriteOnly);
223 }
224 _nmeaStream = new QTextStream();
225 _nmeaStream->setDevice(_nmeaFile);
226 QDateTime dateTime = QDateTime::currentDateTime().toUTC();
227 QString nmStr = "GPRMC," + dateTime.time().toString("hhmmss")
228 + ",A,,,,,,,"
229 + dateTime.date().toString("ddMMyy")
230 + ",,";
231
232 writeNMEAstr(nmStr);
233 }
234}
235
236// Destructor
237////////////////////////////////////////////////////////////////////////////
238bncModel::~bncModel() {
239 delete _nmeaStream;
240 delete _nmeaFile;
241}
242
243// Bancroft Solution
244////////////////////////////////////////////////////////////////////////////
245t_irc bncModel::cmpBancroft(t_epoData* epoData) {
246
247 if (epoData->sizeGPS() < MINOBS) {
248 _log += "\nNot enough data";
249 return failure;
250 }
251
252 Matrix BB(epoData->sizeGPS(), 4);
253
254 QMapIterator<QString, t_satData*> it(epoData->satDataGPS);
255 int iObs = 0;
256 while (it.hasNext()) {
257 ++iObs;
258 it.next();
259 QString prn = it.key();
260 t_satData* satData = it.value();
261 BB(iObs, 1) = satData->xx(1);
262 BB(iObs, 2) = satData->xx(2);
263 BB(iObs, 3) = satData->xx(3);
264 BB(iObs, 4) = satData->P3 + satData->clk;
265 }
266
267 bancroft(BB, _xcBanc);
268
269 // Ellipsoidal Coordinates
270 // ------------------------
271 xyz2ell(_xcBanc.data(), _ellBanc.data());
272
273 // Compute Satellite Elevations
274 // ----------------------------
275 QMutableMapIterator<QString, t_satData*> iGPS(epoData->satDataGPS);
276 while (iGPS.hasNext()) {
277 iGPS.next();
278 QString prn = iGPS.key();
279 t_satData* satData = iGPS.value();
280
281 ColumnVector rr = satData->xx - _xcBanc.Rows(1,3);
282 double rho = rr.norm_Frobenius();
283
284 double neu[3];
285 xyz2neu(_ellBanc.data(), rr.data(), neu);
286
287 satData->eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
288 if (neu[2] < 0) {
289 satData->eleSat *= -1.0;
290 }
291 satData->azSat = atan2(neu[1], neu[0]);
292
293 if (satData->eleSat < MINELE) {
294 delete satData;
295 iGPS.remove();
296 }
297 }
298
299 QMutableMapIterator<QString, t_satData*> iGlo(epoData->satDataGlo);
300 while (iGlo.hasNext()) {
301 iGlo.next();
302 QString prn = iGlo.key();
303 t_satData* satData = iGlo.value();
304
305 ColumnVector rr = satData->xx - _xcBanc.Rows(1,3);
306 double rho = rr.norm_Frobenius();
307
308 double neu[3];
309 xyz2neu(_ellBanc.data(), rr.data(), neu);
310
311 satData->eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
312 if (neu[2] < 0) {
313 satData->eleSat *= -1.0;
314 }
315 satData->azSat = atan2(neu[1], neu[0]);
316
317 if (satData->eleSat < MINELE) {
318 delete satData;
319 iGlo.remove();
320 }
321 }
322
323 return success;
324}
325
326// Computed Value
327////////////////////////////////////////////////////////////////////////////
328double bncModel::cmpValue(t_satData* satData) {
329
330 ColumnVector xRec(3);
331 xRec(1) = x();
332 xRec(2) = y();
333 xRec(3) = z();
334
335 double rho0 = (satData->xx - xRec).norm_Frobenius();
336 double dPhi = t_CST::omega * rho0 / t_CST::c;
337
338 xRec(1) = x() * cos(dPhi) - y() * sin(dPhi);
339 xRec(2) = y() * cos(dPhi) + x() * sin(dPhi);
340 xRec(3) = z();
341
342 satData->rho = (satData->xx - xRec).norm_Frobenius();
343
344 double tropDelay = delay_saast(satData->eleSat) +
345 trp() / sin(satData->eleSat);
346
347 double clk = 0.0;
348 if (satData->prn[0] == 'G') {
349 clk = clkGPS();
350 }
351 else if (satData->prn[0] == 'R') {
352 clk = clkGlo();
353 }
354
355 return satData->rho + clk - satData->clk + tropDelay;
356}
357
358// Tropospheric Model (Saastamoinen)
359////////////////////////////////////////////////////////////////////////////
360double bncModel::delay_saast(double Ele) {
361
362 double height = _ellBanc(3);
363
364 double pp = 1013.25 * pow(1.0 - 2.26e-5 * height, 5.225);
365 double TT = 18.0 - height * 0.0065 + 273.15;
366 double hh = 50.0 * exp(-6.396e-4 * height);
367 double ee = hh / 100.0 * exp(-37.2465 + 0.213166*TT - 0.000256908*TT*TT);
368
369 double h_km = height / 1000.0;
370
371 if (h_km < 0.0) h_km = 0.0;
372 if (h_km > 5.0) h_km = 5.0;
373 int ii = int(h_km + 1);
374 double href = ii - 1;
375
376 double bCor[6];
377 bCor[0] = 1.156;
378 bCor[1] = 1.006;
379 bCor[2] = 0.874;
380 bCor[3] = 0.757;
381 bCor[4] = 0.654;
382 bCor[5] = 0.563;
383
384 double BB = bCor[ii-1] + (bCor[ii]-bCor[ii-1]) * (h_km - href);
385
386 double zen = M_PI/2.0 - Ele;
387
388 return (0.002277/cos(zen)) * (pp + ((1255.0/TT)+0.05)*ee - BB*(tan(zen)*tan(zen)));
389}
390
391// Prediction Step of the Filter
392////////////////////////////////////////////////////////////////////////////
393void bncModel::predict(t_epoData* epoData) {
394
395 if (_usePhase) {
396
397 // Make a copy of QQ and xx, set parameter indices
398 // -----------------------------------------------
399 SymmetricMatrix QQ_old = _QQ;
400
401 for (int iPar = 1; iPar <= _params.size(); iPar++) {
402 _params[iPar-1]->index_old = _params[iPar-1]->index;
403 _params[iPar-1]->index = 0;
404 }
405
406 // Remove Ambiguity Parameters without observations
407 // ------------------------------------------------
408 int iPar = 0;
409 QMutableVectorIterator<bncParam*> it(_params);
410 while (it.hasNext()) {
411 bncParam* par = it.next();
412 bool removed = false;
413 if (par->type == bncParam::AMB_L3) {
414 if (epoData->satDataGPS.find(par->prn) == epoData->satDataGPS.end() &&
415 epoData->satDataGlo.find(par->prn) == epoData->satDataGlo.end() ) {
416 removed = true;
417 delete par;
418 it.remove();
419 }
420 }
421 if (! removed) {
422 ++iPar;
423 par->index = iPar;
424 }
425 }
426
427 // Add new ambiguity parameters
428 // ----------------------------
429 QMapIterator<QString, t_satData*> iGPS(epoData->satDataGPS);
430 while (iGPS.hasNext()) {
431 iGPS.next();
432 QString prn = iGPS.key();
433 bool found = false;
434 for (int iPar = 1; iPar <= _params.size(); iPar++) {
435 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
436 _params[iPar-1]->prn == prn) {
437 found = true;
438 break;
439 }
440 }
441 if (!found) {
442 bncParam* par = new bncParam(bncParam::AMB_L3, _params.size()+1, prn);
443 _params.push_back(par);
444 }
445 }
446
447 QMapIterator<QString, t_satData*> iGlo(epoData->satDataGlo);
448 while (iGlo.hasNext()) {
449 iGlo.next();
450 QString prn = iGlo.key();
451 t_satData* satData = iGlo.value();
452 bool found = false;
453 for (int iPar = 1; iPar <= _params.size(); iPar++) {
454 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
455 _params[iPar-1]->prn == prn) {
456 found = true;
457 break;
458 }
459 }
460 if (!found) {
461 bncParam* par = new bncParam(bncParam::AMB_L3, _params.size()+1, prn);
462 _params.push_back(par);
463 /// par->xx = satData->L3 - cmpValue(satData);
464 }
465 }
466
467 int nPar = _params.size();
468 _QQ.ReSize(nPar); _QQ = 0.0;
469 for (int i1 = 1; i1 <= nPar; i1++) {
470 bncParam* p1 = _params[i1-1];
471 if (p1->index_old != 0) {
472 _QQ(p1->index, p1->index) = QQ_old(p1->index_old, p1->index_old);
473 for (int i2 = 1; i2 <= nPar; i2++) {
474 bncParam* p2 = _params[i2-1];
475 if (p2->index_old != 0) {
476 _QQ(p1->index, p2->index) = QQ_old(p1->index_old, p2->index_old);
477 }
478 }
479 }
480 }
481
482 for (int ii = 1; ii <= nPar; ii++) {
483 bncParam* par = _params[ii-1];
484 if (par->index_old == 0) {
485 _QQ(par->index, par->index) = sig_amb_0 * sig_amb_0;
486 }
487 par->index_old = par->index;
488 }
489 }
490
491 bool firstCrd = x() == 0.0 && y() == 0.0 && z() == 0.0;
492
493 for (int iPar = 1; iPar <= _params.size(); iPar++) {
494 bncParam* pp = _params[iPar-1];
495
496 // Coordinates
497 // -----------
498 if (pp->type == bncParam::CRD_X) {
499 if (firstCrd || !_static) {
500 pp->xx = _xcBanc(1);
501 }
502 _QQ(iPar,iPar) += sig_crd_p * sig_crd_p;
503 }
504 else if (pp->type == bncParam::CRD_Y) {
505 if (firstCrd || !_static) {
506 pp->xx = _xcBanc(2);
507 }
508 _QQ(iPar,iPar) += sig_crd_p * sig_crd_p;
509 }
510 else if (pp->type == bncParam::CRD_Z) {
511 if (firstCrd || !_static) {
512 pp->xx = _xcBanc(3);
513 }
514 _QQ(iPar,iPar) += sig_crd_p * sig_crd_p;
515 }
516
517 // Receiver Clocks
518 // ---------------
519 else if (pp->isClk()) {
520 pp->xx = _xcBanc(4);
521 for (int jj = 1; jj <= _params.size(); jj++) {
522 _QQ(iPar, jj) = 0.0;
523 }
524 _QQ(iPar,iPar) = sig_clk_0 * sig_clk_0;
525 }
526
527 // Tropospheric Delay
528 // ------------------
529 else if (pp->type == bncParam::TROPO) {
530 _QQ(iPar,iPar) += sig_trp_p * sig_trp_p;
531 }
532 }
533}
534
535// Update Step of the Filter (currently just a single-epoch solution)
536////////////////////////////////////////////////////////////////////////////
537t_irc bncModel::update(t_epoData* epoData) {
538
539 _log = "Precise Point Positioning";
540
541 _time = epoData->tt;
542
543 SymmetricMatrix QQsav;
544 ColumnVector dx;
545 ColumnVector vv;
546
547 // Loop over all outliers
548 // ----------------------
549 do {
550
551 // Bancroft Solution
552 // -----------------
553 if (cmpBancroft(epoData) != success) {
554 _log += "\nBancroft failed";
555 emit newMessage(_log, false);
556 return failure;
557 }
558
559 if (epoData->sizeGPS() < MINOBS) {
560 _log += "\nNot enough data";
561 emit newMessage(_log, false);
562 return failure;
563 }
564
565 // Status Prediction
566 // -----------------
567 predict(epoData);
568
569 // Create First-Design Matrix
570 // --------------------------
571 unsigned nPar = _params.size();
572 unsigned nObs = 0;
573 if (_usePhase) {
574 nObs = 2 * epoData->sizeGPS() + epoData->sizeGlo();
575 }
576 else {
577 nObs = epoData->sizeGPS(); // Glonass pseudoranges are not used
578 }
579
580 Matrix AA(nObs, nPar); // first design matrix
581 ColumnVector ll(nObs); // tems observed-computed
582 SymmetricMatrix PP(nObs); PP = 0.0;
583
584 unsigned iObs = 0;
585
586 // GPS code and (optionally) phase observations
587 // --------------------------------------------
588 QMapIterator<QString, t_satData*> itGPS(epoData->satDataGPS);
589 while (itGPS.hasNext()) {
590 ++iObs;
591 itGPS.next();
592 QString prn = itGPS.key();
593 t_satData* satData = itGPS.value();
594
595 double rhoCmp = cmpValue(satData);
596
597 double ellWgtCoeff = 1.0;
598 //// double eleD = satData->eleSat * 180.0 / M_PI;
599 //// if (eleD < 25.0) {
600 //// ellWgtCoeff = 2.5 - (eleD - 10.0) * 0.1;
601 //// ellWgtCoeff *= ellWgtCoeff;
602 //// }
603
604 ll(iObs) = satData->P3 - rhoCmp;
605 PP(iObs,iObs) = 1.0 / (sig_P3 * sig_P3) / ellWgtCoeff;
606 for (int iPar = 1; iPar <= _params.size(); iPar++) {
607 AA(iObs, iPar) = _params[iPar-1]->partial(satData, false);
608 }
609
610 if (_usePhase) {
611 ++iObs;
612 ll(iObs) = satData->L3 - rhoCmp;
613 PP(iObs,iObs) = 1.0 / (sig_L3 * sig_L3) / ellWgtCoeff;
614 for (int iPar = 1; iPar <= _params.size(); iPar++) {
615 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
616 _params[iPar-1]->prn == prn) {
617 ll(iObs) -= _params[iPar-1]->xx;
618 }
619 AA(iObs, iPar) = _params[iPar-1]->partial(satData, true);
620 }
621 }
622 }
623
624 // Glonass phase observations
625 // --------------------------
626 if (_usePhase) {
627 QMapIterator<QString, t_satData*> itGlo(epoData->satDataGlo);
628 while (itGlo.hasNext()) {
629 ++iObs;
630 itGlo.next();
631 QString prn = itGlo.key();
632 t_satData* satData = itGlo.value();
633
634 double rhoCmp = cmpValue(satData);
635
636 double ellWgtCoeff = 1.0;
637 //// double eleD = satData->eleSat * 180.0 / M_PI;
638 //// if (eleD < 25.0) {
639 //// ellWgtCoeff = 2.5 - (eleD - 10.0) * 0.1;
640 //// ellWgtCoeff *= ellWgtCoeff;
641 //// }
642
643 ll(iObs) = satData->L3 - rhoCmp;
644
645 cout.setf(ios::fixed);
646 cout << prn.toAscii().data() << " "
647 << setprecision(3) << rhoCmp << " "
648 << setprecision(3) << satData->P3 << " "
649 << setprecision(3) << satData->L3 << endl;
650
651 PP(iObs,iObs) = 1.0 / (sig_L3 * sig_L3) / ellWgtCoeff;
652 for (int iPar = 1; iPar <= _params.size(); iPar++) {
653 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
654 _params[iPar-1]->prn == prn) {
655 ll(iObs) -= _params[iPar-1]->xx;
656 }
657 AA(iObs, iPar) = _params[iPar-1]->partial(satData, true);
658 }
659
660 //// beg test
661 //double rhoCmp = cmpValue(satData);
662 //cout.setf(ios::fixed);
663 //cout << prn.toAscii().data() << " "
664 // << setprecision(3) << rhoCmp << " "
665 // << setprecision(3) << satData->P3 << " "
666 // << setprecision(3) << satData->L3 << " " << endl;
667 //
668 ////// end test
669 }
670 }
671
672 cout << endl;
673
674 // Compute Filter Update
675 // ---------------------
676 QQsav = _QQ;
677
678 Matrix ATP = AA.t() * PP;
679 SymmetricMatrix NN = _QQ.i();
680 NN << NN + ATP * AA;
681 _QQ = NN.i();
682 dx = _QQ * ATP * ll;
683 vv = ll - AA * dx;
684
685 } while (outlierDetection(QQsav, vv, epoData->satDataGPS,
686 epoData->satDataGlo) != 0);
687
688 // Set Solution Vector
689 // -------------------
690 ostringstream str1;
691 str1.setf(ios::fixed);
692 QVectorIterator<bncParam*> itPar(_params);
693 while (itPar.hasNext()) {
694 bncParam* par = itPar.next();
695 par->xx += dx(par->index);
696 if (par->type == bncParam::RECCLK_GPS) {
697 str1 << "\n clk GPS = " << setw(6) << setprecision(3) << par->xx
698 << " +- " << setw(6) << setprecision(3)
699 << sqrt(_QQ(par->index,par->index));
700 }
701 if (par->type == bncParam::RECCLK_GLO) {
702 str1 << "\n clk GLO = " << setw(6) << setprecision(3) << par->xx
703 << " +- " << setw(6) << setprecision(3)
704 << sqrt(_QQ(par->index,par->index));
705 }
706 else if (par->type == bncParam::AMB_L3) {
707 str1 << "\n amb " << par->prn.toAscii().data() << " = "
708 << setw(6) << setprecision(3) << par->xx
709 << " +- " << setw(6) << setprecision(3)
710 << sqrt(_QQ(par->index,par->index));
711 }
712 else if (par->type == bncParam::TROPO) {
713 str1 << "\n trp = " << par->prn.toAscii().data()
714 << setw(7) << setprecision(3) << delay_saast(M_PI/2.0) << " "
715 << setw(6) << setprecision(3) << showpos << par->xx << noshowpos
716 << " +- " << setw(6) << setprecision(3)
717 << sqrt(_QQ(par->index,par->index));
718 }
719 }
720 _log += str1.str().c_str();
721
722 // Message (both log file and screen)
723 // ----------------------------------
724 ostringstream str2;
725 str2.setf(ios::fixed);
726 str2 << _staID.data() << ": PPP "
727 << epoData->tt.timestr(1) << " " << epoData->sizeAll() << " "
728 << setw(14) << setprecision(3) << x() << " +- "
729 << setw(6) << setprecision(3) << sqrt(_QQ(1,1)) << " "
730 << setw(14) << setprecision(3) << y() << " +- "
731 << setw(6) << setprecision(3) << sqrt(_QQ(2,2)) << " "
732 << setw(14) << setprecision(3) << z() << " +- "
733 << setw(6) << setprecision(3) << sqrt(_QQ(3,3));
734
735 emit newMessage(_log, false);
736 emit newMessage(QByteArray(str2.str().c_str()), true);
737
738 // NMEA Output
739 // -----------
740 double xyz[3];
741 xyz[0] = x();
742 xyz[1] = y();
743 xyz[2] = z();
744 double ell[3];
745 xyz2ell(xyz, ell);
746 double phiDeg = ell[0] * 180 / M_PI;
747 double lamDeg = ell[1] * 180 / M_PI;
748
749 char phiCh = 'N';
750 if (phiDeg < 0) {
751 phiDeg = -phiDeg;
752 phiCh = 'S';
753 }
754 char lamCh = 'E';
755 if (lamDeg < 0) {
756 lamDeg = -lamDeg;
757 lamCh = 'W';
758 }
759
760 double dop = 2.0; // TODO
761
762 ostringstream str3;
763 str3.setf(ios::fixed);
764 str3 << "GPGGA,"
765 << epoData->tt.timestr(0,0) << ','
766 << setw(2) << setfill('0') << int(phiDeg)
767 << setw(10) << setprecision(7) << setfill('0')
768 << fmod(60*phiDeg,60) << ',' << phiCh << ','
769 << setw(2) << setfill('0') << int(lamDeg)
770 << setw(10) << setprecision(7) << setfill('0')
771 << fmod(60*lamDeg,60) << ',' << lamCh
772 << ",1," << setw(2) << setfill('0') << epoData->sizeAll() << ','
773 << setw(3) << setprecision(1) << dop << ','
774 << setprecision(3) << ell[2] << ",M,0.0,M,,,";
775
776 writeNMEAstr(QString(str3.str().c_str()));
777
778 return success;
779}
780
781// Outlier Detection
782////////////////////////////////////////////////////////////////////////////
783int bncModel::outlierDetection(const SymmetricMatrix& QQsav,
784 const ColumnVector& vv,
785 QMap<QString, t_satData*>& satDataGPS,
786 QMap<QString, t_satData*>& satDataGlo) {
787
788 double vvMaxCodeGPS = 0.0;
789 double vvMaxPhaseGPS = 0.0;
790 double vvMaxPhaseGlo = 0.0;
791 QMutableMapIterator<QString, t_satData*> itMaxCodeGPS(satDataGPS);
792 QMutableMapIterator<QString, t_satData*> itMaxPhaseGPS(satDataGPS);
793 QMutableMapIterator<QString, t_satData*> itMaxPhaseGlo(satDataGlo);
794
795 int ii = 0;
796
797 // GPS code and (optionally) phase residuals
798 // -----------------------------------------
799 QMutableMapIterator<QString, t_satData*> itGPS(satDataGPS);
800 while (itGPS.hasNext()) {
801 itGPS.next();
802 ++ii;
803
804 if (vvMaxCodeGPS == 0.0 || fabs(vv(ii)) > vvMaxCodeGPS) {
805 vvMaxCodeGPS = fabs(vv(ii));
806 itMaxCodeGPS = itGPS;
807 }
808
809 if (_usePhase) {
810 ++ii;
811 if (vvMaxPhaseGPS == 0.0 || fabs(vv(ii)) > vvMaxPhaseGPS) {
812 vvMaxPhaseGPS = fabs(vv(ii));
813 itMaxPhaseGPS = itGPS;
814 }
815 }
816 }
817
818 // Glonass phase residuals
819 // -----------------------
820 if (_usePhase) {
821 QMutableMapIterator<QString, t_satData*> itGlo(satDataGlo);
822 while (itGlo.hasNext()) {
823 itGlo.next();
824 ++ii;
825 if (vvMaxPhaseGlo == 0.0 || fabs(vv(ii)) > vvMaxPhaseGlo) {
826 vvMaxPhaseGlo = fabs(vv(ii));
827 itMaxPhaseGlo = itGlo;
828 }
829 }
830 }
831
832 if (vvMaxCodeGPS > MAXRES_CODE) {
833 QString prn = itMaxCodeGPS.key();
834 t_satData* satData = itMaxCodeGPS.value();
835 delete satData;
836 itMaxCodeGPS.remove();
837 _QQ = QQsav;
838
839 _log += "\nOutlier Code " + prn.toAscii() + " "
840 + QByteArray::number(vvMaxCodeGPS, 'f', 3);
841
842 return 1;
843 }
844 else if (vvMaxPhaseGPS > MAXRES_PHASE) {
845 QString prn = itMaxPhaseGPS.key();
846 t_satData* satData = itMaxPhaseGPS.value();
847 delete satData;
848 itMaxPhaseGPS.remove();
849 _QQ = QQsav;
850
851 _log += "\nOutlier Phase " + prn.toAscii() + " "
852 + QByteArray::number(vvMaxPhaseGPS, 'f', 3);
853
854 return 1;
855 }
856 else if (vvMaxPhaseGlo > MAXRES_PHASE) {
857 QString prn = itMaxPhaseGlo.key();
858 t_satData* satData = itMaxPhaseGlo.value();
859 delete satData;
860 itMaxPhaseGlo.remove();
861 _QQ = QQsav;
862
863 _log += "\nOutlier Phase " + prn.toAscii() + " "
864 + QByteArray::number(vvMaxPhaseGlo, 'f', 3);
865
866 return 1;
867 }
868
869 return 0;
870}
871
872//
873////////////////////////////////////////////////////////////////////////////
874void bncModel::writeNMEAstr(const QString& nmStr) {
875
876 unsigned char XOR = 0;
877 for (int ii = 0; ii < nmStr.length(); ii++) {
878 XOR ^= (unsigned char) nmStr[ii].toAscii();
879 }
880
881 QString outStr = '$' + nmStr
882 + QString("*%1\n").arg(int(XOR), 0, 16).toUpper();
883
884 if (_nmeaStream) {
885 *_nmeaStream << outStr;
886 _nmeaStream->flush();
887 }
888
889 emit newNMEAstr(outStr.toAscii());
890}
Note: See TracBrowser for help on using the repository browser.