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

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