source: ntrip/trunk/BNC/src/upload/bncrtnetuploadcaster.cpp@ 6813

Last change on this file since 6813 was 6812, checked in by stoecker, 10 years ago

integrate RTCM3 parsing into BNC and directly fill target structures, add doxygen documentation

File size: 25.1 KB
Line 
1/* -------------------------------------------------------------------------
2 * BKG NTRIP Server
3 * -------------------------------------------------------------------------
4 *
5 * Class: bncRtnetUploadCaster
6 *
7 * Purpose: Connection to NTRIP Caster
8 *
9 * Author: L. Mervart
10 *
11 * Created: 29-Mar-2011
12 *
13 * Changes:
14 *
15 * -----------------------------------------------------------------------*/
16
17#include <math.h>
18#include "bncrtnetuploadcaster.h"
19#include "bncsettings.h"
20#include "bncephuser.h"
21#include "bncclockrinex.h"
22#include "bncsp3.h"
23#include "gnss.h"
24
25using namespace std;
26
27// Constructor
28////////////////////////////////////////////////////////////////////////////
29bncRtnetUploadCaster::bncRtnetUploadCaster(const QString& mountpoint,
30 const QString& outHost, int outPort,
31 const QString& password,
32 const QString& crdTrafo, bool CoM,
33 const QString& sp3FileName,
34 const QString& rnxFileName,
35 int PID, int SID, int IOD, int iRow) :
36 bncUploadCaster(mountpoint, outHost, outPort, password, iRow, 0) {
37
38 if (!outHost.isEmpty()) {
39 _casterID += outHost;
40 }
41 if (!crdTrafo.isEmpty()) {
42 _casterID += " " + crdTrafo;
43 }
44 if (!sp3FileName.isEmpty()) {
45 _casterID += " " + sp3FileName;
46 }
47 if (!rnxFileName.isEmpty()) {
48 _casterID += " " + rnxFileName;
49 }
50
51 _crdTrafo = crdTrafo;
52 _CoM = CoM;
53 _PID = PID;
54 _SID = SID;
55 _IOD = IOD;
56
57 // Member that receives the ephemeris
58 // ----------------------------------
59 _ephUser = new bncEphUser(true);
60
61 bncSettings settings;
62 QString intr = settings.value("uploadIntr").toString();
63 QStringList hlp = settings.value("combineStreams").toStringList();
64 _samplRtcmEphCorr = settings.value("uploadSamplRtcmEphCorr").toDouble();
65 if (hlp.size() > 1) { // combination stream upload
66 _samplRtcmClkCorr = settings.value("cmbSampl").toInt();
67 } else { // single stream upload or sp3 file generation
68 _samplRtcmClkCorr = 5; // default
69 }
70 int samplClkRnx = settings.value("uploadSamplClkRnx").toInt();
71 int samplSp3 = settings.value("uploadSamplSp3").toInt() * 60;
72
73 if (_samplRtcmEphCorr == 0.0) {
74 _usedEph = 0;
75 }
76 else {
77 _usedEph = new QMap<QString, const t_eph*>;
78 }
79
80 // RINEX writer
81 // ------------
82 if (!rnxFileName.isEmpty()) {
83 _rnx = new bncClockRinex(rnxFileName, intr, samplClkRnx);
84 }
85 else {
86 _rnx = 0;
87 }
88
89 // SP3 writer
90 // ----------
91 if (!sp3FileName.isEmpty()) {
92 _sp3 = new bncSP3(sp3FileName, intr, samplSp3);
93 }
94 else {
95 _sp3 = 0;
96 }
97
98 // Set Transformation Parameters
99 // -----------------------------
100 if (_crdTrafo == "ETRF2000") {
101 _dx = 0.0521;
102 _dy = 0.0493;
103 _dz = -0.0585;
104 _dxr = 0.0001;
105 _dyr = 0.0001;
106 _dzr = -0.0018;
107 _ox = 0.000891;
108 _oy = 0.005390;
109 _oz = -0.008712;
110 _oxr = 0.000081;
111 _oyr = 0.000490;
112 _ozr = -0.000792;
113 _sc = 1.34;
114 _scr = 0.08;
115 _t0 = 2000.0;
116 }
117 else if (_crdTrafo == "NAD83") {
118 _dx = 0.99343;
119 _dy = -1.90331;
120 _dz = -0.52655;
121 _dxr = 0.00079;
122 _dyr = -0.00060;
123 _dzr = -0.00134;
124 _ox = -0.02591467;
125 _oy = -0.00942645;
126 _oz = -0.01159935;
127 _oxr = -0.00006667;
128 _oyr = 0.00075744;
129 _ozr = 0.00005133;
130 _sc = 1.71504;
131 _scr = -0.10201;
132 _t0 = 1997.0;
133 }
134 else if (_crdTrafo == "GDA94") {
135 _dx = -0.08468;
136 _dy = -0.01942;
137 _dz = 0.03201;
138 _dxr = 0.00142;
139 _dyr = 0.00134;
140 _dzr = 0.00090;
141 _ox = 0.0004254;
142 _oy = -0.0022578;
143 _oz = -0.0024015;
144 _oxr = -0.0015461;
145 _oyr = -0.0011820;
146 _ozr = -0.0011551;
147 _sc = 9.710;
148 _scr = 0.109;
149 _t0 = 1994.0;
150 }
151 else if (_crdTrafo == "SIRGAS2000") {
152 _dx = 0.0020;
153 _dy = 0.0041;
154 _dz = 0.0039;
155 _dxr = 0.0000;
156 _dyr = 0.0000;
157 _dzr = 0.0000;
158 _ox = 0.000170;
159 _oy = -0.000030;
160 _oz = 0.000070;
161 _oxr = 0.000000;
162 _oyr = 0.000000;
163 _ozr = 0.000000;
164 _sc = -1.000;
165 _scr = 0.000;
166 _t0 = 0000.0;
167 }
168 else if (_crdTrafo == "SIRGAS95") {
169 _dx = 0.0077;
170 _dy = 0.0058;
171 _dz = -0.0138;
172 _dxr = 0.0000;
173 _dyr = 0.0000;
174 _dzr = 0.0000;
175 _ox = 0.000000;
176 _oy = 0.000000;
177 _oz = -0.000030;
178 _oxr = 0.000000;
179 _oyr = 0.000000;
180 _ozr = 0.000000;
181 _sc = 1.570;
182 _scr = 0.000;
183 _t0 = 0000.0;
184 }
185 else if (_crdTrafo == "DREF91") {
186 _dx = -0.0118;
187 _dy = 0.1432;
188 _dz = -0.1117;
189 _dxr = 0.0001;
190 _dyr = 0.0001;
191 _dzr = -0.0018;
192 _ox = 0.003291;
193 _oy = 0.006190;
194 _oz = -0.011012;
195 _oxr = 0.000081;
196 _oyr = 0.000490;
197 _ozr = -0.000792;
198 _sc = 12.24;
199 _scr = 0.08;
200 _t0 = 2000.0;
201 }
202 else if (_crdTrafo == "Custom") {
203 _dx = settings.value("trafo_dx").toDouble();
204 _dy = settings.value("trafo_dy").toDouble();
205 _dz = settings.value("trafo_dz").toDouble();
206 _dxr = settings.value("trafo_dxr").toDouble();
207 _dyr = settings.value("trafo_dyr").toDouble();
208 _dzr = settings.value("trafo_dzr").toDouble();
209 _ox = settings.value("trafo_ox").toDouble();
210 _oy = settings.value("trafo_oy").toDouble();
211 _oz = settings.value("trafo_oz").toDouble();
212 _oxr = settings.value("trafo_oxr").toDouble();
213 _oyr = settings.value("trafo_oyr").toDouble();
214 _ozr = settings.value("trafo_ozr").toDouble();
215 _sc = settings.value("trafo_sc").toDouble();
216 _scr = settings.value("trafo_scr").toDouble();
217 _t0 = settings.value("trafo_t0").toDouble();
218 }
219}
220
221// Destructor
222////////////////////////////////////////////////////////////////////////////
223bncRtnetUploadCaster::~bncRtnetUploadCaster() {
224 if (isRunning()) {
225 wait();
226 }
227 delete _rnx;
228 delete _sp3;
229 delete _ephUser;
230 delete _usedEph;
231}
232
233//
234////////////////////////////////////////////////////////////////////////////
235void bncRtnetUploadCaster::decodeRtnetStream(char* buffer, int bufLen) {
236
237 QMutexLocker locker(&_mutex);
238
239 // Append to internal buffer
240 // -------------------------
241 _rtnetStreamBuffer.append(QByteArray(buffer, bufLen));
242
243 // Select buffer part that contains last epoch
244 // -------------------------------------------
245 QStringList lines;
246 int iEpoBeg = _rtnetStreamBuffer.lastIndexOf('*'); // begin of last epoch
247 if (iEpoBeg == -1) {
248 _rtnetStreamBuffer.clear();
249 return;
250 }
251 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iEpoBeg);
252
253 int iEpoEnd = _rtnetStreamBuffer.lastIndexOf("EOE"); // end of last epoch
254 if (iEpoEnd == -1) {
255 return;
256 }
257 else {
258 lines = _rtnetStreamBuffer.left(iEpoEnd).split('\n', QString::SkipEmptyParts);
259 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iEpoEnd+3);
260 }
261
262 if (lines.size() < 2) {
263 return;
264 }
265
266 // Keep the last unfinished line in buffer
267 // ---------------------------------------
268 int iLastEOL = _rtnetStreamBuffer.lastIndexOf('\n');
269 if (iLastEOL != -1) {
270 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iLastEOL+1);
271 }
272
273 // Read first line (with epoch time)
274 // ---------------------------------
275 QTextStream in(lines[0].toAscii());
276 QString hlp;
277 int year, month, day, hour, min;
278 double sec;
279 in >> hlp >> year >> month >> day >> hour >> min >> sec;
280 bncTime epoTime; epoTime.set( year, month, day, hour, min, sec);
281
282 emit(newMessage("bncRtnetUploadCaster: decode " +
283 QByteArray(epoTime.datestr().c_str()) + " " +
284 QByteArray(epoTime.timestr().c_str()) + " " +
285 _casterID.toAscii(), false));
286
287 struct ClockOrbit co;
288 memset(&co, 0, sizeof(co));
289 co.EpochTime[CLOCKORBIT_SATGPS] = static_cast<int>(epoTime.gpssec());
290 double gt = epoTime.gpssec() + 3 * 3600 - gnumleap(year, month, day);
291 co.EpochTime[CLOCKORBIT_SATGLONASS] = static_cast<int>(fmod(gt, 86400.0));
292
293 co.Supplied[COBOFS_CLOCK] = 1;
294 co.Supplied[COBOFS_ORBIT] = 1;
295 co.SatRefDatum = DATUM_ITRF;
296 co.SSRIOD = _IOD;
297 co.SSRProviderID = _PID; // 256 .. BKG, 257 ... EUREF
298 co.SSRSolutionID = _SID;
299
300 struct CodeBias bias;
301 memset(&bias, 0, sizeof(bias));
302 bias.EpochTime[CLOCKORBIT_SATGPS] = co.EpochTime[CLOCKORBIT_SATGPS];
303 bias.EpochTime[CLOCKORBIT_SATGLONASS] = co.EpochTime[CLOCKORBIT_SATGLONASS];
304
305 // Default Update Interval
306 // -----------------------
307 int clkUpdInd = 2; // 5 sec
308 int ephUpdInd = clkUpdInd; // default
309
310 if (_samplRtcmClkCorr > 5.0 && _samplRtcmEphCorr <= 5.0) { // combined orb and clock
311 ephUpdInd = determineUpdateInd(_samplRtcmClkCorr);
312 }
313 if (_samplRtcmClkCorr > 5.0) {
314 clkUpdInd = determineUpdateInd(_samplRtcmClkCorr);
315 }
316 if (_samplRtcmEphCorr > 5.0) {
317 ephUpdInd = determineUpdateInd(_samplRtcmEphCorr);
318 }
319
320 co.UpdateInterval = clkUpdInd;
321 bias.UpdateInterval = clkUpdInd;
322
323 for (int ii = 1; ii < lines.size(); ii++) {
324
325 QString prn;
326 ColumnVector rtnAPC;
327 ColumnVector rtnVel;
328 ColumnVector rtnCoM;
329 double rtnClk;
330
331 QTextStream in(lines[ii].toAscii());
332
333 in >> prn;
334
335 const t_eph* ephLast = _ephUser->ephLast(prn);
336 const t_eph* ephPrev = _ephUser->ephPrev(prn);
337 const t_eph* eph = ephLast;
338
339 if (eph) {
340
341 // Use previous ephemeris if the last one is too recent
342 // ----------------------------------------------------
343 const int MINAGE = 60; // seconds
344 if (ephPrev && eph->receptDateTime().isValid() &&
345 eph->receptDateTime().secsTo(currentDateAndTimeGPS()) < MINAGE) {
346 eph = ephPrev;
347 }
348
349 // Make sure the clock messages refer to same IOD as orbit messages
350 // ----------------------------------------------------------------
351 if (_usedEph) {
352 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
353 (*_usedEph)[prn] = eph;
354 }
355 else {
356 eph = 0;
357 if (_usedEph->contains(prn)) {
358 const t_eph* usedEph = _usedEph->value(prn);
359 if (usedEph == ephLast) {
360 eph = ephLast;
361 }
362 else if (usedEph == ephPrev) {
363 eph = ephPrev;
364 }
365 }
366 }
367 }
368 }
369
370 if (eph) {
371
372 QMap<QString, double> codeBiases;
373
374 while (true) {
375 QString key;
376 int numVal = 0;
377 in >> key >> numVal;
378 if (in.status() != QTextStream::Ok) {
379 break;
380 }
381 if (key == "APC") {
382 rtnAPC.ReSize(3);
383 in >> rtnAPC[0] >> rtnAPC[1] >> rtnAPC[2];
384 }
385 else if (key == "Clk") {
386 in >> rtnClk;
387 }
388 else if (key == "Vel") {
389 rtnVel.ReSize(3);
390 in >> rtnVel[0] >> rtnVel[1] >> rtnVel[2];
391 }
392 else if (key == "CoM") {
393 rtnCoM.ReSize(3);
394 in >> rtnCoM[0] >> rtnCoM[1] >> rtnCoM[2];
395 }
396 else if (key == "CodeBias") {
397 for (int ii = 0; ii < numVal; ii++) {
398 QString type;
399 double value;
400 in >> type >> value;
401 codeBiases[type] = value;
402 }
403 }
404 else {
405 for (int ii = 0; ii < numVal; ii++) {
406 double dummy;
407 in >> dummy;
408 }
409 }
410 }
411 struct ClockOrbit::SatData* sd = 0;
412 if (prn[0] == 'G') {
413 sd = co.Sat + co.NumberOfSat[CLOCKORBIT_SATGPS];
414 ++co.NumberOfSat[CLOCKORBIT_SATGPS];
415 }
416 else if (prn[0] == 'R') {
417 sd = co.Sat + CLOCKORBIT_NUMGPS + co.NumberOfSat[CLOCKORBIT_SATGLONASS];
418 ++co.NumberOfSat[CLOCKORBIT_SATGLONASS];
419 }
420 if (sd) {
421 QString outLine;
422 processSatellite(eph, epoTime.gpsw(), epoTime.gpssec(), prn,
423 rtnAPC, rtnClk, rtnVel, rtnCoM, sd, outLine);
424 }
425
426 struct CodeBias::BiasSat* biasSat = 0;
427 if (prn[0] == 'G') {
428 biasSat = bias.Sat + bias.NumberOfSat[CLOCKORBIT_SATGPS];
429 ++bias.NumberOfSat[CLOCKORBIT_SATGPS];
430 }
431 else if (prn[0] == 'R') {
432 biasSat = bias.Sat + CLOCKORBIT_NUMGPS + bias.NumberOfSat[CLOCKORBIT_SATGLONASS];
433 ++bias.NumberOfSat[CLOCKORBIT_SATGLONASS];
434 }
435
436 // Code Biases
437 // -----------
438 if (biasSat) {
439 biasSat->ID = prn.mid(1).toInt();
440 biasSat->NumberOfCodeBiases = 0;
441 if (prn[0] == 'G') {
442 QMapIterator<QString, double> it(codeBiases);
443 while (it.hasNext()) {
444 it.next();
445 if (it.key() == "1C") {
446 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
447 biasSat->NumberOfCodeBiases += 1;
448 biasSat->Biases[ii].Type = CODETYPEGPS_L1_CA;
449 biasSat->Biases[ii].Bias = it.value();
450 }
451 else if (it.key() == "1C") {
452 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
453 biasSat->NumberOfCodeBiases += 1;
454 biasSat->Biases[ii].Type = CODETYPEGPS_L1_CA;
455 biasSat->Biases[ii].Bias = it.value();
456 }
457 else if (it.key() == "1P") {
458 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
459 biasSat->NumberOfCodeBiases += 1;
460 biasSat->Biases[ii].Type = CODETYPEGPS_L1_P;
461 biasSat->Biases[ii].Bias = it.value();
462 }
463 else if (it.key() == "1W") {
464 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
465 biasSat->NumberOfCodeBiases += 1;
466 biasSat->Biases[ii].Type = CODETYPEGPS_L1_Z;
467 biasSat->Biases[ii].Bias = it.value();
468 }
469 else if (it.key() == "2C") {
470 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
471 biasSat->NumberOfCodeBiases += 1;
472 biasSat->Biases[ii].Type = CODETYPEGPS_L2_CA;
473 biasSat->Biases[ii].Bias = it.value();
474 }
475 else if (it.key() == "2D") {
476 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
477 biasSat->NumberOfCodeBiases += 1;
478 biasSat->Biases[ii].Type = CODETYPEGPS_SEMI_CODELESS;
479 biasSat->Biases[ii].Bias = it.value();
480 }
481 else if (it.key() == "2S") {
482 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
483 biasSat->NumberOfCodeBiases += 1;
484 biasSat->Biases[ii].Type = CODETYPEGPS_L2_CM;
485 biasSat->Biases[ii].Bias = it.value();
486 }
487 else if (it.key() == "2L") {
488 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
489 biasSat->NumberOfCodeBiases += 1;
490 biasSat->Biases[ii].Type = CODETYPEGPS_L2_CL;
491 biasSat->Biases[ii].Bias = it.value();
492 }
493 else if (it.key() == "2X") {
494 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
495 biasSat->NumberOfCodeBiases += 1;
496 biasSat->Biases[ii].Type = CODETYPEGPS_L2_CML;
497 biasSat->Biases[ii].Bias = it.value();
498 }
499 else if (it.key() == "2P") {
500 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
501 biasSat->NumberOfCodeBiases += 1;
502 biasSat->Biases[ii].Type = CODETYPEGPS_L2_P;
503 biasSat->Biases[ii].Bias = it.value();
504 }
505 else if (it.key() == "2W") {
506 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
507 biasSat->NumberOfCodeBiases += 1;
508 biasSat->Biases[ii].Type = CODETYPEGPS_L2_Z;
509 biasSat->Biases[ii].Bias = it.value();
510 }
511 else if (it.key() == "5I") {
512 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
513 biasSat->NumberOfCodeBiases += 1;
514 biasSat->Biases[ii].Type = CODETYPEGPS_L5_I;
515 biasSat->Biases[ii].Bias = it.value();
516 }
517 else if (it.key() == "5Q") {
518 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
519 biasSat->NumberOfCodeBiases += 1;
520 biasSat->Biases[ii].Type = CODETYPEGPS_L5_Q;
521 biasSat->Biases[ii].Bias = it.value();
522 }
523 }
524 }
525 else if (prn[0] == 'R') {
526 QMapIterator<QString, double> it(codeBiases);
527 while (it.hasNext()) {
528 it.next();
529 if (it.key() == "1C") {
530 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
531 biasSat->NumberOfCodeBiases += 1;
532 biasSat->Biases[ii].Type = CODETYPEGLONASS_L1_CA;
533 biasSat->Biases[ii].Bias = it.value();
534 }
535 else if (it.key() == "1P") {
536 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
537 biasSat->NumberOfCodeBiases += 1;
538 biasSat->Biases[ii].Type = CODETYPEGLONASS_L1_P;
539 biasSat->Biases[ii].Bias = it.value();
540 }
541 else if (it.key() == "2C") {
542 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
543 biasSat->NumberOfCodeBiases += 1;
544 biasSat->Biases[ii].Type = CODETYPEGLONASS_L2_CA;
545 biasSat->Biases[ii].Bias = it.value();
546 }
547 else if (it.key() == "2P") {
548 int ii = biasSat->NumberOfCodeBiases; if (ii >= CLOCKORBIT_NUMBIAS) break;
549 biasSat->NumberOfCodeBiases += 1;
550 biasSat->Biases[ii].Type = CODETYPEGLONASS_L2_P;
551 biasSat->Biases[ii].Bias = it.value();
552 }
553 }
554 }
555 }
556 }
557 }
558
559 QByteArray hlpBufferCo;
560
561 // Orbit and Clock Corrections together
562 // ------------------------------------
563 if (_samplRtcmEphCorr == 0.0) {
564 if (co.NumberOfSat[CLOCKORBIT_SATGPS] > 0 || co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
565 char obuffer[CLOCKORBIT_BUFFERSIZE];
566 int len = MakeClockOrbit(&co, COTYPE_AUTO, 0, obuffer, sizeof(obuffer));
567 if (len > 0) {
568 hlpBufferCo = QByteArray(obuffer, len);
569 }
570 }
571 }
572
573 // Orbit and Clock Corrections separately
574 // --------------------------------------
575 else {
576 if (co.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
577 char obuffer[CLOCKORBIT_BUFFERSIZE];
578 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
579 co.UpdateInterval = ephUpdInd;
580 int len1 = MakeClockOrbit(&co, COTYPE_GPSORBIT, 1, obuffer, sizeof(obuffer));
581 co.UpdateInterval = clkUpdInd;
582 if (len1 > 0) {
583 hlpBufferCo += QByteArray(obuffer, len1);
584 }
585 }
586 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) ? 1 : 0;
587 int len2 = MakeClockOrbit(&co, COTYPE_GPSCLOCK, mmsg, obuffer, sizeof(obuffer));
588 if (len2 > 0) {
589 hlpBufferCo += QByteArray(obuffer, len2);
590 }
591 }
592 if (co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
593 char obuffer[CLOCKORBIT_BUFFERSIZE];
594 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
595 co.UpdateInterval = ephUpdInd;
596 int len1 = MakeClockOrbit(&co, COTYPE_GLONASSORBIT, 1, obuffer, sizeof(obuffer));
597 co.UpdateInterval = clkUpdInd;
598 if (len1 > 0) {
599 hlpBufferCo += QByteArray(obuffer, len1);
600 }
601 }
602 int len2 = MakeClockOrbit(&co, COTYPE_GLONASSCLOCK, 0, obuffer, sizeof(obuffer));
603 if (len2 > 0) {
604 hlpBufferCo += QByteArray(obuffer, len2);
605 }
606 }
607 }
608
609 // Biases
610 // ------
611 QByteArray hlpBufferBias;
612 if (bias.NumberOfSat[CLOCKORBIT_SATGPS] > 0 || bias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
613 char obuffer[CLOCKORBIT_BUFFERSIZE];
614 int len = MakeCodeBias(&bias, BTYPE_AUTO, 0, obuffer, sizeof(obuffer));
615 if (len > 0) {
616 hlpBufferBias = QByteArray(obuffer, len);
617 }
618 }
619
620 _outBuffer += hlpBufferCo + hlpBufferBias;
621}
622
623//
624////////////////////////////////////////////////////////////////////////////
625void bncRtnetUploadCaster::processSatellite(const t_eph* eph, int GPSweek,
626 double GPSweeks, const QString& prn,
627 const ColumnVector& rtnAPC,
628 double rtnClk,
629 const ColumnVector& rtnVel,
630 const ColumnVector& rtnCoM,
631 struct ClockOrbit::SatData* sd,
632 QString& outLine) {
633
634 // Broadcast Position and Velocity
635 // -------------------------------
636 ColumnVector xB(4);
637 ColumnVector vB(3);
638 eph->getCrd(bncTime(GPSweek, GPSweeks), xB, vB, false);
639
640 // Precise Position
641 // ----------------
642 ColumnVector xP = _CoM ? rtnCoM : rtnAPC;
643
644 double dc = 0.0;
645 if (_crdTrafo != "IGS08") {
646 crdTrafo(GPSweek, xP, dc);
647 }
648
649 // Difference in xyz
650 // -----------------
651 ColumnVector dx = xB.Rows(1,3) - xP;
652 ColumnVector dv = vB - rtnVel;
653
654 // Difference in RSW
655 // -----------------
656 ColumnVector rsw(3);
657 XYZ_to_RSW(xB.Rows(1,3), vB, dx, rsw);
658
659 ColumnVector dotRsw(3);
660 XYZ_to_RSW(xB.Rows(1,3), vB, dv, dotRsw);
661
662 // Clock Correction
663 // ----------------
664 double dClk = rtnClk - (xB(4) - dc) * t_CST::c;
665
666 if (sd) {
667 sd->ID = prn.mid(1).toInt();
668 sd->IOD = eph->IOD();
669 sd->Clock.DeltaA0 = dClk;
670 sd->Clock.DeltaA1 = 0.0; // TODO
671 sd->Clock.DeltaA2 = 0.0; // TODO
672 sd->Orbit.DeltaRadial = rsw(1);
673 sd->Orbit.DeltaAlongTrack = rsw(2);
674 sd->Orbit.DeltaCrossTrack = rsw(3);
675 sd->Orbit.DotDeltaRadial = dotRsw(1);
676 sd->Orbit.DotDeltaAlongTrack = dotRsw(2);
677 sd->Orbit.DotDeltaCrossTrack = dotRsw(3);
678 }
679
680 outLine.sprintf("%d %.1f %s %3d %10.3f %8.3f %8.3f %8.3f\n",
681 GPSweek, GPSweeks, eph->prn().toString().c_str(),
682 eph->IOD(), dClk, rsw(1), rsw(2), rsw(3));
683
684 double relativity = -2.0 * DotProduct(xP, rtnVel) / t_CST::c;
685 double sp3Clk = (rtnClk - relativity) / t_CST::c; // in seconds
686
687 if (_rnx) {
688 _rnx->write(GPSweek, GPSweeks, prn, sp3Clk);
689 }
690 if (_sp3) {
691 _sp3->write(GPSweek, GPSweeks, prn, rtnCoM, sp3Clk);
692 }
693}
694
695// Transform Coordinates
696////////////////////////////////////////////////////////////////////////////
697void bncRtnetUploadCaster::crdTrafo(int GPSWeek, ColumnVector& xyz,
698 double& dc) {
699
700 // Current epoch minus 2000.0 in years
701 // ------------------------------------
702 double dt = (GPSWeek - (1042.0+6.0/7.0)) / 365.2422 * 7.0 + 2000.0 - _t0;
703
704 ColumnVector dx(3);
705
706 dx(1) = _dx + dt * _dxr;
707 dx(2) = _dy + dt * _dyr;
708 dx(3) = _dz + dt * _dzr;
709
710 static const double arcSec = 180.0 * 3600.0 / M_PI;
711
712 double ox = (_ox + dt * _oxr) / arcSec;
713 double oy = (_oy + dt * _oyr) / arcSec;
714 double oz = (_oz + dt * _ozr) / arcSec;
715
716 double sc = 1.0 + _sc * 1e-9 + dt * _scr * 1e-9;
717
718 // Specify approximate center of area
719 // ----------------------------------
720 ColumnVector meanSta(3);
721
722 if (_crdTrafo == "ETRF2000") {
723 meanSta(1) = 3661090.0;
724 meanSta(2) = 845230.0;
725 meanSta(3) = 5136850.0;
726 }
727 else if (_crdTrafo == "NAD83") {
728 meanSta(1) = -1092950.0;
729 meanSta(2) = -4383600.0;
730 meanSta(3) = 4487420.0;
731 }
732 else if (_crdTrafo == "GDA94") {
733 meanSta(1) = -4052050.0;
734 meanSta(2) = 4212840.0;
735 meanSta(3) = -2545110.0;
736 }
737 else if (_crdTrafo == "SIRGAS2000") {
738 meanSta(1) = 3740860.0;
739 meanSta(2) = -4964290.0;
740 meanSta(3) = -1425420.0;
741 }
742 else if (_crdTrafo == "SIRGAS95") {
743 meanSta(1) = 3135390.0;
744 meanSta(2) = -5017670.0;
745 meanSta(3) = -2374440.0;
746 }
747 else if (_crdTrafo == "DREF91") {
748 meanSta(1) = 3959579.0;
749 meanSta(2) = 721719.0;
750 meanSta(3) = 4931539.0;
751 }
752 else if (_crdTrafo == "Custom") {
753 meanSta(1) = 0.0; // TODO
754 meanSta(2) = 0.0; // TODO
755 meanSta(3) = 0.0; // TODO
756 }
757
758 // Clock correction proportional to topocentric distance to satellites
759 // -------------------------------------------------------------------
760 double rho = (xyz - meanSta).norm_Frobenius();
761 dc = rho * (sc - 1.0) / sc / t_CST::c;
762
763 Matrix rMat(3,3);
764 rMat(1,1) = 1.0;
765 rMat(1,2) = -oz;
766 rMat(1,3) = oy;
767 rMat(2,1) = oz;
768 rMat(2,2) = 1.0;
769 rMat(2,3) = -ox;
770 rMat(3,1) = -oy;
771 rMat(3,2) = ox;
772 rMat(3,3) = 1.0;
773
774 xyz = sc * rMat * xyz + dx;
775}
776
777int bncRtnetUploadCaster::determineUpdateInd(double samplingRate) {
778
779 if (samplingRate == 10.0) {
780 return 3;
781 }
782 else if (samplingRate == 15.0) {
783 return 4;
784 }
785 else if (samplingRate == 30.0) {
786 return 5;
787 }
788 else if (samplingRate == 60.0) {
789 return 6;
790 }
791 else if (samplingRate == 120.0) {
792 return 7;
793 }
794 else if (samplingRate == 240.0) {
795 return 8;
796 }
797 else if (samplingRate == 300.0) {
798 return 9;
799 }
800 else if (samplingRate == 600.0) {
801 return 10;
802 }
803 else if (samplingRate == 900.0) {
804 return 11;
805 }
806 else if (samplingRate == 1800.0) {
807 return 12;
808 }
809 else if (samplingRate == 3600.0) {
810 return 13;
811 }
812 else if (samplingRate == 7200.0) {
813 return 14;
814 }
815 else if (samplingRate == 10800.0) {
816 return 15;
817 }
818 return 2;// default
819}
Note: See TracBrowser for help on using the repository browser.