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

Last change on this file since 3027 was 3027, checked in by mervart, 13 years ago
File size: 14.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
20#include "bnccomb.h"
21#include "bncapp.h"
22#include "cmbcaster.h"
23#include "bncsettings.h"
24#include "bncmodel.h"
25#include "bncutils.h"
26#include "bncpppclient.h"
27
28using namespace std;
29
30// Constructor
31////////////////////////////////////////////////////////////////////////////
32cmbParam::cmbParam(cmbParam::parType typeIn, int indexIn,
33 const QString& acIn, const QString& prnIn) {
34 type = typeIn;
35 index = indexIn;
36 AC = acIn;
37 prn = prnIn;
38 xx = 0.0;
39}
40
41// Destructor
42////////////////////////////////////////////////////////////////////////////
43cmbParam::~cmbParam() {
44}
45
46// Partial
47////////////////////////////////////////////////////////////////////////////
48double cmbParam::partial(const QString& acIn, t_corr* corr) {
49
50 if (type == AC_offset) {
51 if (AC == acIn) {
52 return 1.0;
53 }
54 }
55 else if (type == Sat_offset) {
56 if (AC == acIn && prn == corr->prn) {
57 return 1.0;
58 }
59 }
60 else if (type == clk) {
61 if (prn == corr->prn) {
62 return 1.0;
63 }
64 }
65
66 return 0.0;
67}
68
69//
70////////////////////////////////////////////////////////////////////////////
71QString cmbParam::toString() const {
72
73 QString outStr;
74
75 if (type == AC_offset) {
76 outStr = "AC offset " + AC;
77 }
78 else if (type == Sat_offset) {
79 outStr = "Sat Offset " + AC + " " + prn;
80 }
81 else if (type == clk) {
82 outStr = "Clk Corr " + prn;
83 }
84
85 return outStr;
86}
87
88// Constructor
89////////////////////////////////////////////////////////////////////////////
90bncComb::bncComb() {
91
92 bncSettings settings;
93
94 QStringList combineStreams = settings.value("combineStreams").toStringList();
95
96 if (combineStreams.size() >= 2) {
97 QListIterator<QString> it(combineStreams);
98 while (it.hasNext()) {
99 QStringList hlp = it.next().split(" ");
100 cmbAC* newAC = new cmbAC();
101 newAC->mountPoint = hlp[0];
102 newAC->name = hlp[1];
103 newAC->weight = hlp[2].toDouble();
104
105 _ACs[newAC->mountPoint] = newAC;
106 }
107 }
108
109 _caster = new cmbCaster();
110 connect(this, SIGNAL(newMessage(QByteArray,bool)),
111 ((bncApp*)qApp), SLOT(slotMessage(const QByteArray,bool)));
112
113 // Initialize Parameters
114 // ---------------------
115 int nextPar = 0;
116 QMapIterator<QString, cmbAC*> it(_ACs);
117 while (it.hasNext()) {
118 it.next();
119 cmbAC* AC = it.value();
120 _params.push_back(new cmbParam(cmbParam::AC_offset, ++nextPar, AC->name, ""));
121 }
122 it.toFront();
123 while (it.hasNext()) {
124 it.next();
125 cmbAC* AC = it.value();
126 for (int iGps = 1; iGps <= 32; iGps++) {
127 QString prn = QString("G%1").arg(iGps, 2, 10, QChar('0'));
128 _params.push_back(new cmbParam(cmbParam::Sat_offset, ++nextPar, AC->name, prn));
129 }
130 }
131 for (int iGps = 1; iGps <= 32; iGps++) {
132 QString prn = QString("G%1").arg(iGps, 2, 10, QChar('0'));
133 _params.push_back(new cmbParam(cmbParam::clk, ++nextPar, "", prn));
134 }
135
136 unsigned nPar = _params.size();
137 _QQ.ReSize(nPar);
138 _QQ = 0.0;
139
140 // Clk_Corr = AC_Offset + Sat_Offset + Clk
141 // ---------------------------------------
142 _sigACOff = 100.0; // per analysis center stream and epoch, sigma in meters
143 _sigSatOff = 100.0; // per analysis center stream and satellite, sigma in meters
144 _sigClk = 100.0; // per satellite and epoch, sigma in meters
145
146 for (int iPar = 1; iPar <= _params.size(); iPar++) {
147 cmbParam* pp = _params[iPar-1];
148 if (pp->type == cmbParam::AC_offset) {
149 _QQ(iPar,iPar) = _sigACOff * _sigACOff;
150 }
151 else if (pp->type == cmbParam::Sat_offset) {
152 _QQ(iPar,iPar) = _sigSatOff * _sigSatOff;
153 }
154 else if (pp->type == cmbParam::clk) {
155 _QQ(iPar,iPar) = _sigClk * _sigClk;
156 }
157 }
158}
159
160// Destructor
161////////////////////////////////////////////////////////////////////////////
162bncComb::~bncComb() {
163 QMapIterator<QString, cmbAC*> it(_ACs);
164 while (it.hasNext()) {
165 it.next();
166 delete it.value();
167 }
168 delete _caster;
169}
170
171// Read and store one correction line
172////////////////////////////////////////////////////////////////////////////
173void bncComb::processCorrLine(const QString& staID, const QString& line) {
174 QMutexLocker locker(&_mutex);
175
176 // Find the relevant instance of cmbAC class
177 // -----------------------------------------
178 if (_ACs.find(staID) == _ACs.end()) {
179 return;
180 }
181 cmbAC* AC = _ACs[staID];
182
183 // Read the Correction
184 // -------------------
185 t_corr* newCorr = new t_corr();
186 if (!newCorr->readLine(line) == success) {
187 delete newCorr;
188 return;
189 }
190
191 // Reject delayed corrections
192 // --------------------------
193 if (_processedBeforeTime.valid() && newCorr->tt < _processedBeforeTime) {
194 delete newCorr;
195 return;
196 }
197
198 // Check the IOD
199 //--------------
200 if (_eph.find(newCorr->prn) == _eph.end()) {
201 delete newCorr;
202 return;
203 }
204 else {
205 t_eph* lastEph = _eph[newCorr->prn]->last;
206 t_eph* prevEph = _eph[newCorr->prn]->prev;
207 if (prevEph && prevEph->IOD() == newCorr->iod) {
208 switchToLastEph(lastEph, prevEph, newCorr);
209 }
210 else if (!lastEph || lastEph->IOD() != newCorr->iod) {
211 delete newCorr;
212 return;
213 }
214 newCorr->eph = lastEph;
215 }
216
217 // Process all older Epochs (if there are any)
218 // -------------------------------------------
219 const double waitTime = 5.0; // wait 5 sec
220 _processedBeforeTime = newCorr->tt - waitTime;
221
222 QList<cmbEpoch*> epochsToProcess;
223
224 QMapIterator<QString, cmbAC*> itAC(_ACs);
225 while (itAC.hasNext()) {
226 itAC.next();
227 cmbAC* AC = itAC.value();
228
229 QMutableListIterator<cmbEpoch*> itEpo(AC->epochs);
230 while (itEpo.hasNext()) {
231 cmbEpoch* epoch = itEpo.next();
232 if (epoch->time < _processedBeforeTime) {
233 epochsToProcess.append(epoch);
234 itEpo.remove();
235 }
236 }
237 }
238
239 if (epochsToProcess.size()) {
240 processEpochs(epochsToProcess);
241 }
242
243 // Check Modulo Time
244 // -----------------
245 const int moduloTime = 10;
246 if (int(newCorr->tt.gpssec()) % moduloTime != 0.0) {
247 delete newCorr;
248 return;
249 }
250
251 // Find/Create the instance of cmbEpoch class
252 // ------------------------------------------
253 cmbEpoch* newEpoch = 0;
254 QListIterator<cmbEpoch*> it(AC->epochs);
255 while (it.hasNext()) {
256 cmbEpoch* hlpEpoch = it.next();
257 if (hlpEpoch->time == newCorr->tt) {
258 newEpoch = hlpEpoch;
259 break;
260 }
261 }
262 if (newEpoch == 0) {
263 newEpoch = new cmbEpoch(AC->name);
264 newEpoch->time = newCorr->tt;
265 AC->epochs.append(newEpoch);
266 }
267
268 // Merge or add the correction
269 // ---------------------------
270 if (newEpoch->corr.find(newCorr->prn) != newEpoch->corr.end()) {
271 newEpoch->corr[newCorr->prn]->readLine(line); // merge (multiple messages)
272 }
273 else {
274 newEpoch->corr[newCorr->prn] = newCorr;
275 }
276}
277
278// Send results to caster
279////////////////////////////////////////////////////////////////////////////
280void bncComb::dumpResults(const bncTime& resTime,
281 const QMap<QString, t_corr*>& resCorr) {
282
283 _caster->open();
284
285 unsigned year, month, day;
286 resTime.civil_date (year, month, day);
287 double GPSweeks = resTime.gpssec();
288
289 struct ClockOrbit co;
290 memset(&co, 0, sizeof(co));
291 co.GPSEpochTime = (int)GPSweeks;
292 co.GLONASSEpochTime = (int)fmod(GPSweeks, 86400.0)
293 + 3 * 3600 - gnumleap(year, month, day);
294 co.ClockDataSupplied = 1;
295 co.OrbitDataSupplied = 1;
296 co.SatRefDatum = DATUM_ITRF;
297
298 QMapIterator<QString, t_corr*> it(resCorr);
299 while (it.hasNext()) {
300 it.next();
301 t_corr* corr = it.value();
302
303 struct ClockOrbit::SatData* sd = 0;
304 if (corr->prn[0] == 'G') {
305 sd = co.Sat + co.NumberOfGPSSat;
306 ++co.NumberOfGPSSat;
307 }
308 else if (corr->prn[0] == 'R') {
309 sd = co.Sat + CLOCKORBIT_NUMGPS + co.NumberOfGLONASSSat;
310 ++co.NumberOfGLONASSSat;
311 }
312
313 if (sd != 0) {
314 sd->ID = corr->prn.mid(1).toInt();
315 sd->IOD = corr->iod;
316 sd->Clock.DeltaA0 = corr->dClk * t_CST::c;
317 sd->Orbit.DeltaRadial = corr->rao(1);
318 sd->Orbit.DeltaAlongTrack = corr->rao(2);
319 sd->Orbit.DeltaCrossTrack = corr->rao(3);
320 sd->Orbit.DotDeltaRadial = corr->dotRao(1);
321 sd->Orbit.DotDeltaAlongTrack = corr->dotRao(2);
322 sd->Orbit.DotDeltaCrossTrack = corr->dotRao(3);
323 }
324
325 delete corr;
326 }
327
328 // Send Corrections to Caster
329 // --------------------------
330 if ( _caster->usedSocket() &&
331 (co.NumberOfGPSSat > 0 || co.NumberOfGLONASSSat > 0) ) {
332 char obuffer[CLOCKORBIT_BUFFERSIZE];
333 int len = MakeClockOrbit(&co, COTYPE_AUTO, 0, obuffer, sizeof(obuffer));
334 if (len > 0) {
335 _caster->write(obuffer, len);
336 }
337 }
338
339 // Optionall send new Corrections to PPP client
340 // --------------------------------------------
341 bncApp* app = (bncApp*) qApp;
342 if (app->_bncPPPclient) {
343 QStringList corrLines;
344 co.messageType = COTYPE_GPSCOMBINED;
345 QStringListIterator il(RTCM3coDecoder::corrsToASCIIlines(resTime.gpsw(),
346 resTime.gpssec(), co, 0));
347 while (il.hasNext()) {
348 QString line = il.next() + " " + _caster->mountpoint();
349 corrLines << line;
350 }
351
352 app->_bncPPPclient->slotNewCorrections(corrLines);
353 }
354}
355
356// Change the correction so that it refers to last received ephemeris
357////////////////////////////////////////////////////////////////////////////
358void bncComb::switchToLastEph(const t_eph* lastEph, const t_eph* prevEph,
359 t_corr* newCorr) {
360 ColumnVector oldXC(4);
361 ColumnVector oldVV(3);
362 prevEph->position(newCorr->tt.gpsw(), newCorr->tt.gpssec(),
363 oldXC.data(), oldVV.data());
364
365 ColumnVector newXC(4);
366 ColumnVector newVV(3);
367 lastEph->position(newCorr->tt.gpsw(), newCorr->tt.gpssec(),
368 newXC.data(), newVV.data());
369
370 ColumnVector dX = newXC.Rows(1,3) - oldXC.Rows(1,3);
371 ColumnVector dV = newVV - oldVV;
372 double dC = newXC(4) - oldXC(4);
373
374 ColumnVector dRAO(3);
375 XYZ_to_RSW(newXC.Rows(1,3), newVV, dX, dRAO);
376
377 ColumnVector dDotRAO(3);
378 XYZ_to_RSW(newXC.Rows(1,3), newVV, dV, dDotRAO);
379
380 newCorr->iod = lastEph->IOD();
381 newCorr->rao -= dRAO;
382 newCorr->dotRao -= dDotRAO;
383 newCorr->dClk -= dC;
384
385 QString msg = "switch " + newCorr->prn
386 + QString(" %1 -> %2 %3").arg(prevEph->IOD(),3)
387 .arg(lastEph->IOD(),3).arg(dC*t_CST::c, 8, 'f', 4);
388
389 emit newMessage(msg.toAscii(), false);
390}
391
392// Process Epochs
393////////////////////////////////////////////////////////////////////////////
394void bncComb::processEpochs(const QList<cmbEpoch*>& epochs) {
395
396 _log.clear();
397
398 QTextStream out(&_log, QIODevice::WriteOnly);
399
400 out << "Combination:" << endl
401 << "------------------------------" << endl;
402
403 // Predict Parameters Values, Add White Noise
404 // ------------------------------------------
405 for (int iPar = 1; iPar <= _params.size(); iPar++) {
406 cmbParam* pp = _params[iPar-1];
407 if (pp->type == cmbParam::AC_offset || pp->type == cmbParam::clk) {
408 pp->xx = 0.0;
409 for (int jj = 1; jj <= _params.size(); jj++) {
410 _QQ(iPar, jj) = 0.0;
411 }
412 }
413 if (pp->type == cmbParam::AC_offset) {
414 _QQ(iPar,iPar) = _sigACOff * _sigACOff;
415 }
416 else if (pp->type == cmbParam::clk) {
417 _QQ(iPar,iPar) = _sigClk * _sigClk;
418 }
419 }
420
421 bncTime resTime = epochs.first()->time;
422 QMap<QString, t_corr*> resCorr;
423
424 int nPar = _params.size();
425 int nObs = 0;
426
427 ColumnVector x0(nPar);
428 for (int iPar = 1; iPar <= _params.size(); iPar++) {
429 cmbParam* pp = _params[iPar-1];
430 x0(iPar) = pp->xx;
431 }
432
433 // Count Observations
434 // ------------------
435 QListIterator<cmbEpoch*> itEpo(epochs);
436 while (itEpo.hasNext()) {
437 cmbEpoch* epo = itEpo.next();
438 QMapIterator<QString, t_corr*> itCorr(epo->corr);
439 while (itCorr.hasNext()) {
440 itCorr.next();
441 ++nObs;
442 }
443 }
444
445 if (nObs > 0) {
446 Matrix AA(nObs, nPar);
447 ColumnVector ll(nObs);
448 DiagonalMatrix PP(nObs); PP = 1.0;
449
450 int iObs = 0;
451 QListIterator<cmbEpoch*> itEpo(epochs);
452 while (itEpo.hasNext()) {
453 cmbEpoch* epo = itEpo.next();
454 QMapIterator<QString, t_corr*> itCorr(epo->corr);
455
456 while (itCorr.hasNext()) {
457 itCorr.next();
458 ++iObs;
459 t_corr* corr = itCorr.value();
460
461 //// beg test
462 if (epo->acName == "BKG") {
463 resCorr[corr->prn] = new t_corr(*corr);
464 }
465 //// end test
466
467 for (int iPar = 1; iPar <= _params.size(); iPar++) {
468 cmbParam* pp = _params[iPar-1];
469 AA(iObs, iPar) = pp->partial(epo->acName, corr);
470 }
471
472 ll(iObs) = corr->dClk * t_CST::c - DotProduct(AA.Row(iObs), x0);
473
474 delete corr;
475 }
476 }
477
478 ColumnVector dx;
479 bncModel::kalman(AA, ll, PP, _QQ, dx);
480 ColumnVector vv = ll - AA * dx;
481
482 for (int iPar = 1; iPar <= _params.size(); iPar++) {
483 cmbParam* pp = _params[iPar-1];
484 pp->xx += dx(iPar);
485 if (pp->type == cmbParam::clk) {
486 if (resCorr.find(pp->prn) != resCorr.end()) {
487 resCorr[pp->prn]->dClk = pp->xx / t_CST::c;
488 }
489 }
490 out << currentDateAndTimeGPS().toString("yy-MM-dd hh:mm:ss ").toAscii().data();
491 out.setRealNumberNotation(QTextStream::FixedNotation);
492 out.setFieldWidth(8);
493 out.setRealNumberPrecision(4);
494 out << pp->toString() << " "
495 << pp->xx << " +- " << sqrt(_QQ(pp->index,pp->index)) << endl;
496 }
497 }
498
499 printResults(out, resTime, resCorr);
500 dumpResults(resTime, resCorr);
501
502 emit newMessage(_log, false);
503}
504
505// Print results to caster
506////////////////////////////////////////////////////////////////////////////
507void bncComb::printResults(QTextStream& out, const bncTime& resTime,
508 const QMap<QString, t_corr*>& resCorr) {
509
510 QMapIterator<QString, t_corr*> it(resCorr);
511 while (it.hasNext()) {
512 it.next();
513 t_corr* corr = it.value();
514 t_eph* eph = corr->eph;
515 if (eph) {
516 double xx, yy, zz, cc;
517 eph->position(resTime.gpsw(), resTime.gpssec(), xx, yy, zz, cc);
518
519 out << currentDateAndTimeGPS().toString("yy-MM-dd hh:mm:ss ").toAscii().data();
520 out.setFieldWidth(3);
521 out << "Full Clock " << corr->prn << " " << corr->iod << " ";
522 out.setFieldWidth(14);
523 out << (cc + corr->dClk) * t_CST::c << endl;
524 }
525 else {
526 out << "bncComb::printResuls bug" << endl;
527 }
528 }
529}
Note: See TracBrowser for help on using the repository browser.