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

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