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

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