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

Last change on this file since 10371 was 10330, checked in by stuerze, 11 months ago

another test is added in PPP and combination mode to check if stored ephemerides were outdated and/or not updated in between

File size: 42.7 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 "bncbiassinex.h"
23#include "bncsp3.h"
24#include "gnss.h"
25#include "bncutils.h"
26
27using namespace std;
28
29// Constructor
30////////////////////////////////////////////////////////////////////////////
31bncRtnetUploadCaster::bncRtnetUploadCaster(const QString& mountpoint,
32 const QString& outHost, int outPort,
33 const QString& ntripVersion,
34 const QString& userName, const QString& password,
35 const QString& crdTrafo, const QString& ssrFormat, bool CoM, const QString& sp3FileName,
36 const QString& rnxFileName, const QString& bsxFileName, int PID, int SID, int IOD, int iRow) :
37 bncUploadCaster(mountpoint, outHost, outPort, ntripVersion, userName, password, iRow, 0) {
38
39 if (!mountpoint.isEmpty()) {
40 _casterID += mountpoint;
41 }
42 if (!outHost.isEmpty()) {
43 _casterID += " " + outHost;
44 if (outPort) {
45 _casterID += ":" + QString("%1").arg(outPort, 10);
46 }
47 }
48 if (!crdTrafo.isEmpty()) {
49 _casterID += " " + crdTrafo;
50 }
51 if (!sp3FileName.isEmpty()) {
52 _casterID += " " + sp3FileName;
53 }
54 if (!rnxFileName.isEmpty()) {
55 _casterID += " " + rnxFileName;
56 }
57
58 if (!bsxFileName.isEmpty()) {
59 _casterID += " " + bsxFileName;
60 }
61
62 _crdTrafo = crdTrafo;
63
64 _ssrFormat = ssrFormat;
65
66 _ssrCorr = 0;
67 if (_ssrFormat == "IGS-SSR") {
68 _ssrCorr = new SsrCorrIgs();
69 }
70 else if (_ssrFormat == "RTCM-SSR") {
71 _ssrCorr = new SsrCorrRtcm();
72 }
73
74 _CoM = CoM;
75 _PID = PID;
76 _SID = SID;
77 _IOD = IOD;
78 _phaseBiasInformationDecoded = false;
79
80 // Member that receives the ephemeris
81 // ----------------------------------
82 _ephUser = new bncEphUser(true);
83
84 bncSettings settings;
85 QString intr = settings.value("uploadIntr").toString();
86 QStringList hlp = settings.value("cmbStreams").toStringList();
87 _samplRtcmEphCorr = settings.value("uploadSamplRtcmEphCorr").toDouble();
88 if (hlp.size() > 1) { // combination stream upload
89 _samplRtcmClkCorr = settings.value("cmbSampl").toInt();
90 }
91 else { // single stream upload or sp3 file generation
92 _samplRtcmClkCorr = 5; // default
93 }
94 int samplClkRnx = settings.value("uploadSamplClkRnx").toInt();
95 int samplSp3 = settings.value("uploadSamplSp3").toString().split("sec").first().toInt();
96 int samplBiaSnx = settings.value("uploadSamplBiaSnx").toInt();
97
98 if (_samplRtcmEphCorr == 0.0) {
99 _usedEph = 0;
100 }
101 else {
102 _usedEph = new QMap<QString, const t_eph*>;
103 }
104
105 // RINEX writer
106 // ------------
107 if (!rnxFileName.isEmpty()) {
108 _rnx = new bncClockRinex(rnxFileName, intr, samplClkRnx);
109 }
110 else {
111 _rnx = 0;
112 }
113
114 // SP3 writer
115 // ----------
116 if (!sp3FileName.isEmpty()) {
117 _sp3 = new bncSP3(sp3FileName, intr, samplSp3);
118 }
119 else {
120 _sp3 = 0;
121 }
122
123 // SINEX writer
124 // ------------
125 if (!bsxFileName.isEmpty()) {
126 _bsx = new bncBiasSinex(bsxFileName, intr, samplBiaSnx);
127 }
128 else {
129 _bsx = 0;
130 }
131
132
133 // Set Transformation Parameters
134 // -----------------------------
135 // Transformation Parameters from ITRF2014 to ETRF2000
136 // EUREF Technical Note 1 Relationship and Transformation between the ITRF and ETRF
137 // Zuheir Altamimi, June 28, 2018
138 if (_crdTrafo == "ETRF2000") {
139 _dx = 0.0547;
140 _dy = 0.0522;
141 _dz = -0.0741;
142
143 _dxr = 0.0001;
144 _dyr = 0.0001;
145 _dzr = -0.0019;
146
147 _ox = 0.001701;
148 _oy = 0.010290;
149 _oz = -0.016632;
150
151 _oxr = 0.000081;
152 _oyr = 0.000490;
153 _ozr = -0.000729;
154
155 _sc = 2.12;
156 _scr = 0.11;
157
158 _t0 = 2010.0;
159 }
160 // Transformation Parameters from ITRF2014 to GDA2020 (Ryan Ruddick, GA)
161 else if (_crdTrafo == "GDA2020") {
162 _dx = 0.0;
163 _dy = 0.0;
164 _dz = 0.0;
165
166 _dxr = 0.0;
167 _dyr = 0.0;
168 _dzr = 0.0;
169
170 _ox = 0.0;
171 _oy = 0.0;
172 _oz = 0.0;
173
174 _oxr = 0.00150379;
175 _oyr = 0.00118346;
176 _ozr = 0.00120716;
177
178 _sc = 0.0;
179 _scr = 0.0;
180
181 _t0 = 2020.0;
182 }
183 // Transformation Parameters from IGb14 to SIRGAS2000 (Thanks to Sonia Costa, BRA)
184 // June 29 2020: TX:-0.0027 m TY:-0.0025 m TZ:-0.0042 m SCL:1.20 (ppb) no rotations and no rates.*/
185 else if (_crdTrafo == "SIRGAS2000") {
186 _dx = -0.0027;
187 _dy = -0.0025;
188 _dz = -0.0042;
189
190 _dxr = 0.0;
191 _dyr = 0.0;
192 _dzr = 0.0;
193
194 _ox = 0.0;
195 _oy = 0.0;
196 _oz = 0.0;
197
198 _oxr = 0.0;
199 _oyr = 0.0;
200 _ozr = 0.0;
201
202 _sc = 1.2;
203 _scr = 0.0;
204 _t0 = 2000.0;
205 }
206 // Transformation Parameters from ITRF2014 to DREF91
207 else if (_crdTrafo == "DREF91") {
208 _dx = 0.0547;
209 _dy = 0.0522;
210 _dz = -0.0741;
211
212 _dxr = 0.0001;
213 _dyr = 0.0001;
214 _dzr = -0.0019;
215 // ERTF200 + rotation parameters (ETRF2000 => DREF91)
216 _ox = 0.001701 + 0.000658;
217 _oy = 0.010290 - 0.000208;
218 _oz = -0.016632 + 0.000755;
219
220 _oxr = 0.000081;
221 _oyr = 0.000490;
222 _ozr = -0.000729;
223
224 _sc = 2.12;
225 _scr = 0.11;
226
227 _t0 = 2010.0;
228 }
229 else if (_crdTrafo == "Custom") {
230 _dx = settings.value("trafo_dx").toDouble();
231 _dy = settings.value("trafo_dy").toDouble();
232 _dz = settings.value("trafo_dz").toDouble();
233 _dxr = settings.value("trafo_dxr").toDouble();
234 _dyr = settings.value("trafo_dyr").toDouble();
235 _dzr = settings.value("trafo_dzr").toDouble();
236 _ox = settings.value("trafo_ox").toDouble();
237 _oy = settings.value("trafo_oy").toDouble();
238 _oz = settings.value("trafo_oz").toDouble();
239 _oxr = settings.value("trafo_oxr").toDouble();
240 _oyr = settings.value("trafo_oyr").toDouble();
241 _ozr = settings.value("trafo_ozr").toDouble();
242 _sc = settings.value("trafo_sc").toDouble();
243 _scr = settings.value("trafo_scr").toDouble();
244 _t0 = settings.value("trafo_t0").toDouble();
245 }
246 // TODO: the following lines can be deleted if all parameters are updated regarding ITRF2020
247 if (_crdTrafo == "ETRF2000" ||
248 _crdTrafo == "GDA2020" ||
249 _crdTrafo == "DREF91" ||
250 _crdTrafo == "SIRGAS2000") {
251 // Transformation Parameters from ITRF2020 to ITRF2014
252 // from ITRF web site: https://itrf.ign.fr/en/solutions/transformations
253 _dx14 = -0.0014;
254 _dy14 = -0.0009;
255 _dz14 = 0.0014;
256 _dxr14 = 0.0;
257 _dyr14 = -0.0001;
258 _dzr14 = -0.0002;
259 _ox14 = 0.0;
260 _oy14 = 0.0;
261 _oz14 = 0.0;
262 _oxr14 = 0.0;
263 _oyr14 = 0.0;
264 _ozr14 = 0.0;
265 _sc14 = -0.42;
266 _scr14 = 0.0;
267 _t014 = 2015.0;
268 }
269}
270
271// Destructor
272////////////////////////////////////////////////////////////////////////////
273bncRtnetUploadCaster::~bncRtnetUploadCaster() {
274 if (isRunning()) {
275 wait();
276 }
277 delete _rnx;
278 delete _sp3;
279 delete _ephUser;
280 delete _usedEph;
281 delete _ssrCorr;
282}
283
284//
285////////////////////////////////////////////////////////////////////////////
286void bncRtnetUploadCaster::decodeRtnetStream(char* buffer, int bufLen) {
287
288 QMutexLocker locker(&_mutex);
289
290 // Append to internal buffer
291 // -------------------------
292 _rtnetStreamBuffer.append(QByteArray(buffer, bufLen));
293
294 // Select buffer part that contains last epoch
295 // -------------------------------------------
296
297 // Find the begin of last epoch
298 int iEpoBeg = _rtnetStreamBuffer.lastIndexOf('*');
299 if (iEpoBeg == -1) {
300 _rtnetStreamBuffer.clear();
301 emit(newMessage(QString("bncRtnetUploadCaster: no Epoch line found: %1").arg(_casterID).toLatin1(), false));
302 return;
303 }
304
305 // Find the begin of the first epoch
306 int iEpoBegEarlier = _rtnetStreamBuffer.indexOf('*');
307 if (iEpoBegEarlier != -1 && iEpoBegEarlier < iEpoBeg) {
308 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iEpoBegEarlier);
309 }
310 else {
311 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iEpoBeg);
312 }
313
314 // Find End of the last epoch
315 int iEpoEnd = _rtnetStreamBuffer.lastIndexOf("EOE");
316 if (iEpoEnd == -1) {
317 _rtnetStreamBuffer.clear();
318 emit(newMessage(QString("bncRtnetUploadCaster: no EOE found: %1").arg(_casterID).toLatin1(), false));
319 return;
320 }
321
322 QStringList lines;
323 // If there is there more than 1 epoch line in the buffer
324 while (_rtnetStreamBuffer.count('*') > 1) {
325 emit(newMessage(QString("bncRtnetUploadCaster: more than 1 epoch in buffer: %1").arg(_rtnetStreamBuffer.count('*')).toLatin1(), false));
326 QString rtnetStreamBuffer = _rtnetStreamBuffer;
327 int nextEpoch = rtnetStreamBuffer.indexOf('*');
328 int nextEpochEnd = rtnetStreamBuffer.indexOf("EOE");
329 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(1);
330 if (nextEpoch != -1 && nextEpoch < iEpoEnd) {
331 rtnetStreamBuffer = rtnetStreamBuffer.mid(nextEpoch, nextEpochEnd);
332 lines = rtnetStreamBuffer.split('\n', QString::SkipEmptyParts);
333 if (lines.size() > 2) {
334 decodeRtnetEpoch(lines);
335 }
336 nextEpochEnd = _rtnetStreamBuffer.indexOf("EOE");
337 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(nextEpochEnd+3);
338 }
339 else if (nextEpoch != -1 && nextEpoch >= iEpoEnd) {
340 break;
341 }
342 }
343
344 lines = _rtnetStreamBuffer.left(iEpoEnd).split('\n', QString::SkipEmptyParts);
345
346 _rtnetStreamBuffer = _rtnetStreamBuffer.mid(iEpoEnd + 3);
347
348 if (lines.size() < 2) {
349 emit(newMessage(QString("bncRtnetUploadCaster: less than 2 lines to decode : %1").arg(_casterID).toLatin1(), false));
350 return;
351 }
352 decodeRtnetEpoch(lines);
353}
354
355//
356////////////////////////////////////////////////////////////////////////////
357void bncRtnetUploadCaster::decodeRtnetEpoch(QStringList epochLines) {
358
359 // Read first line (with epoch time)
360 // ---------------------------------
361 QTextStream in(epochLines[0].toLatin1());
362 QString hlp;
363 int year, month, day, hour, min;
364 double sec;
365 in >> hlp >> year >> month >> day >> hour >> min >> sec;
366 bncTime epoTime;
367 epoTime.set(year, month, day, hour, min, sec);
368
369 emit(newMessage(
370 "bncRtnetUploadCaster: decode " + QByteArray(epoTime.datestr().c_str())
371 + " " + QByteArray(epoTime.timestr().c_str()) + " "
372 + _casterID.toLatin1(), false));
373
374 struct SsrCorr::ClockOrbit co;
375 memset(&co, 0, sizeof(co));
376 co.EpochTime[CLOCKORBIT_SATGPS] = static_cast<int>(epoTime.gpssec());
377 if (_ssrFormat == "RTCM-SSR") {
378 double gt = epoTime.gpssec() + 3 * 3600 - gnumleap(year, month, day);
379 co.EpochTime[CLOCKORBIT_SATGLONASS] = static_cast<int>(fmod(gt, 86400.0));
380 }
381 else if (_ssrFormat == "IGS-SSR") {
382 co.EpochTime[CLOCKORBIT_SATGLONASS] = static_cast<int>(epoTime.gpssec());
383 }
384 co.EpochTime[CLOCKORBIT_SATGALILEO] = static_cast<int>(epoTime.gpssec());
385 co.EpochTime[CLOCKORBIT_SATQZSS] = static_cast<int>(epoTime.gpssec());
386 co.EpochTime[CLOCKORBIT_SATSBAS] = static_cast<int>(epoTime.gpssec());
387 if (_ssrFormat == "RTCM-SSR") {
388 co.EpochTime[CLOCKORBIT_SATBDS] = static_cast<int>(epoTime.bdssec());
389 }
390 else if (_ssrFormat == "IGS-SSR") {
391 co.EpochTime[CLOCKORBIT_SATBDS] = static_cast<int>(epoTime.gpssec());
392 }
393 co.Supplied[_ssrCorr->COBOFS_CLOCK] = 1;
394 co.Supplied[_ssrCorr->COBOFS_ORBIT] = 1;
395 co.SatRefDatum = _ssrCorr->DATUM_ITRF; // ToDo: to decode from RTNET format
396 co.SSRIOD = _IOD;
397 co.SSRProviderID = _PID; // 256 .. BKG, 257 ... EUREF
398 co.SSRSolutionID = _SID;
399
400 struct SsrCorr::CodeBias bias;
401 memset(&bias, 0, sizeof(bias));
402 bias.EpochTime[CLOCKORBIT_SATGPS] = co.EpochTime[CLOCKORBIT_SATGPS];
403 bias.EpochTime[CLOCKORBIT_SATGLONASS] = co.EpochTime[CLOCKORBIT_SATGLONASS];
404 bias.EpochTime[CLOCKORBIT_SATGALILEO] = co.EpochTime[CLOCKORBIT_SATGALILEO];
405 bias.EpochTime[CLOCKORBIT_SATQZSS] = co.EpochTime[CLOCKORBIT_SATQZSS];
406 bias.EpochTime[CLOCKORBIT_SATSBAS] = co.EpochTime[CLOCKORBIT_SATSBAS];
407 bias.EpochTime[CLOCKORBIT_SATBDS] = co.EpochTime[CLOCKORBIT_SATBDS];
408 bias.SSRIOD = _IOD;
409 bias.SSRProviderID = _PID;
410 bias.SSRSolutionID = _SID;
411
412 struct SsrCorr::PhaseBias phasebias;
413 memset(&phasebias, 0, sizeof(phasebias));
414 unsigned int dispersiveBiasConsistenyIndicator = 0;
415 unsigned int mwConsistencyIndicator = 0;
416 phasebias.EpochTime[CLOCKORBIT_SATGPS] = co.EpochTime[CLOCKORBIT_SATGPS];
417 phasebias.EpochTime[CLOCKORBIT_SATGLONASS] = co.EpochTime[CLOCKORBIT_SATGLONASS];
418 phasebias.EpochTime[CLOCKORBIT_SATGALILEO] = co.EpochTime[CLOCKORBIT_SATGALILEO];
419 phasebias.EpochTime[CLOCKORBIT_SATQZSS] = co.EpochTime[CLOCKORBIT_SATQZSS];
420 phasebias.EpochTime[CLOCKORBIT_SATSBAS] = co.EpochTime[CLOCKORBIT_SATSBAS];
421 phasebias.EpochTime[CLOCKORBIT_SATBDS] = co.EpochTime[CLOCKORBIT_SATBDS];
422 phasebias.SSRIOD = _IOD;
423 phasebias.SSRProviderID = _PID;
424 phasebias.SSRSolutionID = _SID;
425
426 struct SsrCorr::VTEC vtec;
427 memset(&vtec, 0, sizeof(vtec));
428 vtec.EpochTime = static_cast<int>(epoTime.gpssec());
429 vtec.SSRIOD = _IOD;
430 vtec.SSRProviderID = _PID;
431 vtec.SSRSolutionID = _SID;
432
433 // Default Update Interval
434 // -----------------------
435 int clkUpdInd = 2; // 5 sec
436 int ephUpdInd = clkUpdInd; // default
437
438 if (!_samplRtcmEphCorr) {
439 _samplRtcmEphCorr = 5.0;
440 }
441
442 if (_samplRtcmClkCorr > 5.0 && _samplRtcmEphCorr <= 5.0) { // combined orb and clock
443 ephUpdInd = determineUpdateInd(_samplRtcmClkCorr);
444 }
445 if (_samplRtcmClkCorr > 5.0) {
446 clkUpdInd = determineUpdateInd(_samplRtcmClkCorr);
447 }
448 if (_samplRtcmEphCorr > 5.0) {
449 ephUpdInd = determineUpdateInd(_samplRtcmEphCorr);
450 }
451
452 co.UpdateInterval = clkUpdInd;
453 bias.UpdateInterval = ephUpdInd;
454 phasebias.UpdateInterval = ephUpdInd;
455
456 for (int ii = 1; ii < epochLines.size(); ii++) {
457 QString key; // prn or key VTEC, IND (phase bias indicators)
458 double rtnUra = 0.0; // [m]
459 ColumnVector rtnAPC; rtnAPC.ReSize(3); rtnAPC = 0.0; // [m, m, m]
460 ColumnVector rtnVel; rtnVel.ReSize(3); rtnVel = 0.0; // [m/s, m/s, m/s]
461 ColumnVector rtnCoM; rtnCoM.ReSize(3); rtnCoM = 0.0; // [m, m, m]
462 ColumnVector rtnClk; rtnClk.ReSize(3); rtnClk = 0.0; // [m, m/s, m/s²]
463 ColumnVector rtnClkSig; rtnClkSig.ReSize(3); rtnClkSig = 0.0; // [m, m/s, m/s²]
464 t_prn prn;
465
466 QTextStream in(epochLines[ii].toLatin1());
467
468 in >> key;
469
470 // non-satellite specific parameters
471 if (key.contains("IND", Qt::CaseSensitive)) {
472 in >> dispersiveBiasConsistenyIndicator >> mwConsistencyIndicator;
473 continue;
474 }
475 // non-satellite specific parameters
476 if (key.contains("VTEC", Qt::CaseSensitive)) {
477 double ui;
478 in >> ui >> vtec.NumLayers;
479 vtec.UpdateInterval = (unsigned int) determineUpdateInd(ui);
480 for (unsigned ll = 0; ll < vtec.NumLayers; ll++) {
481 int dummy;
482 in >> dummy >> vtec.Layers[ll].Degree >> vtec.Layers[ll].Order
483 >> vtec.Layers[ll].Height;
484 for (unsigned iDeg = 0; iDeg <= vtec.Layers[ll].Degree; iDeg++) {
485 for (unsigned iOrd = 0; iOrd <= vtec.Layers[ll].Order; iOrd++) {
486 in >> vtec.Layers[ll].Cosinus[iDeg][iOrd];
487 }
488 }
489 for (unsigned iDeg = 0; iDeg <= vtec.Layers[ll].Degree; iDeg++) {
490 for (unsigned iOrd = 0; iOrd <= vtec.Layers[ll].Order; iOrd++) {
491 in >> vtec.Layers[ll].Sinus[iDeg][iOrd];
492 }
493 }
494 }
495 continue;
496 }
497 // satellite specific parameters
498 char sys = key.mid(0, 1).at(0).toLatin1();
499 int number = key.mid(1, 2).toInt();
500 int flags = 0;
501 if (sys == 'E') { // I/NAV
502 flags = 1;
503 }
504 if (number == 0) {
505 continue;
506 }
507 prn.set(sys, number, flags);
508 QString prnInternalStr = QString::fromStdString(prn.toInternalString());
509 QString prnStr = QString::fromStdString(prn.toString());
510
511 const t_eph* ephLast = _ephUser->ephLast(prnInternalStr);
512 const t_eph* ephPrev = _ephUser->ephPrev(prnInternalStr);
513 const t_eph* eph = ephLast;
514 if (eph) {
515
516 // Use previous ephemeris if the last one is too recent
517 // ----------------------------------------------------
518 const int MINAGE = 60; // seconds
519 if (ephPrev && eph->receptDateTime().isValid() &&
520 eph->receptDateTime().secsTo(currentDateAndTimeGPS()) < MINAGE) {
521 eph = ephPrev;
522 }
523
524 // Make sure the clock messages refer to same IOD as orbit messages
525 // ----------------------------------------------------------------
526 if (_usedEph) {
527 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
528 (*_usedEph)[prnInternalStr] = eph;
529 }
530 else {
531 eph = 0;
532 if (_usedEph->contains(prnInternalStr)) {
533 const t_eph* usedEph = _usedEph->value(prnInternalStr);
534 if (usedEph == ephLast) {
535 eph = ephLast;
536 }
537 else if (usedEph == ephPrev) {
538 eph = ephPrev;
539 }
540 }
541 }
542 }
543 }
544
545 QDateTime now = currentDateAndTimeGPS();
546 bncTime currentTime(now.toString(Qt::ISODate).toStdString());
547 if (eph &&
548 !outDatedBcep(eph, currentTime) && // detected from storage because of no update
549 eph->checkState() != t_eph::bad &&
550 eph->checkState() != t_eph::unhealthy &&
551 eph->checkState() != t_eph::outdated) { // detected during reception (bncephuser)
552 QMap<QString, double> codeBiases;
553 QList<phaseBiasSignal> phaseBiasList;
554 phaseBiasesSat pbSat;
555 _phaseBiasInformationDecoded = false;
556
557 while (true) {
558 QString key;
559 int numVal = 0;
560 in >> key;
561 if (in.status() != QTextStream::Ok) {
562 break;
563 }
564 if (key == "APC") {
565 in >> numVal;
566 rtnAPC.ReSize(3); rtnAPC = 0.0;
567 for (int ii = 0; ii < numVal; ii++) {
568 in >> rtnAPC[ii];
569 }
570 }
571 else if (key == "Ura") {
572 in >> numVal;
573 if (numVal == 1)
574 in >> rtnUra;
575 }
576 else if (key == "Clk") {
577 in >> numVal;
578 rtnClk.ReSize(3); rtnClk = 0.0;
579 for (int ii = 0; ii < numVal; ii++) {
580 in >> rtnClk[ii];
581 }
582 }
583 else if (key == "ClkSig") {
584 in >> numVal;
585 rtnClkSig.ReSize(3); rtnClkSig = 0.0;
586 for (int ii = 0; ii < numVal; ii++) {
587 in >> rtnClkSig[ii];
588 }
589 }
590 else if (key == "Vel") {
591 in >> numVal;
592 rtnVel.ReSize(3); rtnVel = 0.0;
593 for (int ii = 0; ii < numVal; ii++) {
594 in >> rtnVel[ii];
595 }
596 }
597 else if (key == "CoM") {
598 in >> numVal;
599 rtnCoM.ReSize(3); rtnCoM = 0.0;
600 for (int ii = 0; ii < numVal; ii++) {
601 in >> rtnCoM[ii];
602 }
603 }
604 else if (key == "CodeBias") {
605 in >> numVal;
606 for (int ii = 0; ii < numVal; ii++) {
607 QString type;
608 double value;
609 in >> type >> value;
610 codeBiases[type] = value;
611 }
612 }
613 else if (key == "YawAngle") {
614 _phaseBiasInformationDecoded = true;
615 in >> numVal >> pbSat.yawAngle;
616 if (pbSat.yawAngle < 0.0) {
617 pbSat.yawAngle += (2*M_PI);
618 }
619 else if (pbSat.yawAngle > 2*M_PI) {
620 pbSat.yawAngle -= (2*M_PI);
621 }
622 }
623 else if (key == "YawRate") {
624 _phaseBiasInformationDecoded = true;
625 in >> numVal >> pbSat.yawRate;
626 }
627 else if (key == "PhaseBias") {
628 _phaseBiasInformationDecoded = true;
629 in >> numVal;
630 for (int ii = 0; ii < numVal; ii++) {
631 phaseBiasSignal pb;
632 in >> pb.type >> pb.bias >> pb.integerIndicator
633 >> pb.wlIndicator >> pb.discontinuityCounter;
634 phaseBiasList.append(pb);
635 }
636 }
637 else {
638 in >> numVal;
639 for (int ii = 0; ii < numVal; ii++) {
640 double dummy;
641 in >> dummy;
642 }
643 emit(newMessage(" RTNET format error: "
644 + epochLines[ii].toLatin1(), false));
645 break;
646 }
647 }
648
649 struct SsrCorr::ClockOrbit::SatData* sd = 0;
650 if (prn.system() == 'G') {
651 sd = co.Sat + co.NumberOfSat[CLOCKORBIT_SATGPS];
652 ++co.NumberOfSat[CLOCKORBIT_SATGPS];
653 }
654 else if (prn.system() == 'R') {
655 sd = co.Sat + CLOCKORBIT_NUMGPS + co.NumberOfSat[CLOCKORBIT_SATGLONASS];
656 ++co.NumberOfSat[CLOCKORBIT_SATGLONASS];
657 }
658 else if (prn.system() == 'E') {
659 sd = co.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
660 + co.NumberOfSat[CLOCKORBIT_SATGALILEO];
661 ++co.NumberOfSat[CLOCKORBIT_SATGALILEO];
662 }
663 else if (prn.system() == 'J') {
664 sd = co.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
665 + CLOCKORBIT_NUMGALILEO
666 + co.NumberOfSat[CLOCKORBIT_SATQZSS];
667 ++co.NumberOfSat[CLOCKORBIT_SATQZSS];
668 }
669 else if (prn.system() == 'S') {
670 sd = co.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
671 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
672 + co.NumberOfSat[CLOCKORBIT_SATSBAS];
673 ++co.NumberOfSat[CLOCKORBIT_SATSBAS];
674 }
675 else if (prn.system() == 'C') {
676 sd = co.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
677 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
678 + CLOCKORBIT_NUMSBAS
679 + co.NumberOfSat[CLOCKORBIT_SATBDS];
680 ++co.NumberOfSat[CLOCKORBIT_SATBDS];
681 }
682 if (sd) {
683 QString outLine;
684 t_irc irc = processSatellite(eph, epoTime.gpsw(), epoTime.gpssec(), prnStr, rtnAPC,
685 rtnUra, rtnClk, rtnVel, rtnCoM, rtnClkSig, sd, outLine);
686 if (irc != success) {
687 continue;
688 }
689 }
690
691 // Code Biases
692 // -----------
693 struct SsrCorr::CodeBias::BiasSat* biasSat = 0;
694 if (!codeBiases.isEmpty()) {
695 if (prn.system() == 'G') {
696 biasSat = bias.Sat + bias.NumberOfSat[CLOCKORBIT_SATGPS];
697 ++bias.NumberOfSat[CLOCKORBIT_SATGPS];
698 }
699 else if (prn.system() == 'R') {
700 biasSat = bias.Sat + CLOCKORBIT_NUMGPS
701 + bias.NumberOfSat[CLOCKORBIT_SATGLONASS];
702 ++bias.NumberOfSat[CLOCKORBIT_SATGLONASS];
703 }
704 else if (prn.system() == 'E') {
705 biasSat = bias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
706 + bias.NumberOfSat[CLOCKORBIT_SATGALILEO];
707 ++bias.NumberOfSat[CLOCKORBIT_SATGALILEO];
708 }
709 else if (prn.system() == 'J') {
710 biasSat = bias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
711 + CLOCKORBIT_NUMGALILEO
712 + bias.NumberOfSat[CLOCKORBIT_SATQZSS];
713 ++bias.NumberOfSat[CLOCKORBIT_SATQZSS];
714 }
715 else if (prn.system() == 'S') {
716 biasSat = bias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
717 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
718 + bias.NumberOfSat[CLOCKORBIT_SATSBAS];
719 ++bias.NumberOfSat[CLOCKORBIT_SATSBAS];
720 }
721 else if (prn.system() == 'C') {
722 biasSat = bias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
723 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
724 + CLOCKORBIT_NUMSBAS
725 + bias.NumberOfSat[CLOCKORBIT_SATBDS];
726 ++bias.NumberOfSat[CLOCKORBIT_SATBDS];
727 }
728 }
729
730 if (biasSat) {
731 biasSat->ID = prn.number();
732 biasSat->NumberOfCodeBiases = 0;
733 QMapIterator<QString, double> it(codeBiases);
734 while (it.hasNext()) {
735 it.next();
736 int ii = biasSat->NumberOfCodeBiases;
737 if (ii >= CLOCKORBIT_NUMBIAS)
738 break;
739 SsrCorr::CodeType type = _ssrCorr->rnxTypeToCodeType(prn.system(), it.key().toStdString());
740 if (type != _ssrCorr->RESERVED) {
741 biasSat->NumberOfCodeBiases += 1;
742 biasSat->Biases[ii].Type = type;
743 biasSat->Biases[ii].Bias = it.value();
744 if (_bsx) {
745 QString obsCode = 'C' + it.key();
746 _bsx->write(epoTime.gpsw(), epoTime.gpssec(), prnStr, obsCode, it.value());
747 }
748 }
749 }
750 }
751
752 // Phase Biases
753 // ------------
754 struct SsrCorr::PhaseBias::PhaseBiasSat* phasebiasSat = 0;
755 if (prn.system() == 'G') {
756 phasebiasSat = phasebias.Sat
757 + phasebias.NumberOfSat[CLOCKORBIT_SATGPS];
758 ++phasebias.NumberOfSat[CLOCKORBIT_SATGPS];
759 }
760 else if (prn.system() == 'R') {
761 phasebiasSat = phasebias.Sat + CLOCKORBIT_NUMGPS
762 + phasebias.NumberOfSat[CLOCKORBIT_SATGLONASS];
763 ++phasebias.NumberOfSat[CLOCKORBIT_SATGLONASS];
764 }
765 else if (prn.system() == 'E') {
766 phasebiasSat = phasebias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
767 + phasebias.NumberOfSat[CLOCKORBIT_SATGALILEO];
768 ++phasebias.NumberOfSat[CLOCKORBIT_SATGALILEO];
769 }
770 else if (prn.system() == 'J') {
771 phasebiasSat = phasebias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
772 + CLOCKORBIT_NUMGALILEO
773 + phasebias.NumberOfSat[CLOCKORBIT_SATQZSS];
774 ++phasebias.NumberOfSat[CLOCKORBIT_SATQZSS];
775 }
776 else if (prn.system() == 'S') {
777 phasebiasSat = phasebias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
778 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
779 + phasebias.NumberOfSat[CLOCKORBIT_SATSBAS];
780 ++phasebias.NumberOfSat[CLOCKORBIT_SATSBAS];
781 }
782 else if (prn.system() == 'C') {
783 phasebiasSat = phasebias.Sat + CLOCKORBIT_NUMGPS + CLOCKORBIT_NUMGLONASS
784 + CLOCKORBIT_NUMGALILEO + CLOCKORBIT_NUMQZSS
785 + CLOCKORBIT_NUMSBAS
786 + phasebias.NumberOfSat[CLOCKORBIT_SATBDS];
787 ++phasebias.NumberOfSat[CLOCKORBIT_SATBDS];
788 }
789
790 if (phasebiasSat && _phaseBiasInformationDecoded) {
791 phasebias.DispersiveBiasConsistencyIndicator = dispersiveBiasConsistenyIndicator;
792 phasebias.MWConsistencyIndicator = mwConsistencyIndicator;
793 phasebiasSat->ID = prn.number();
794 phasebiasSat->NumberOfPhaseBiases = 0;
795 phasebiasSat->YawAngle = pbSat.yawAngle;
796 phasebiasSat->YawRate = pbSat.yawRate;
797 QListIterator<phaseBiasSignal> it(phaseBiasList);
798 while (it.hasNext()) {
799 const phaseBiasSignal &pbSig = it.next();
800 int ii = phasebiasSat->NumberOfPhaseBiases;
801 if (ii >= CLOCKORBIT_NUMBIAS)
802 break;
803 SsrCorr::CodeType type = _ssrCorr->rnxTypeToCodeType(prn.system(), pbSig.type.toStdString());
804 if (type != _ssrCorr->RESERVED) {
805 phasebiasSat->NumberOfPhaseBiases += 1;
806 phasebiasSat->Biases[ii].Type = type;
807 phasebiasSat->Biases[ii].Bias = pbSig.bias;
808 phasebiasSat->Biases[ii].SignalIntegerIndicator = pbSig.integerIndicator;
809 phasebiasSat->Biases[ii].SignalsWideLaneIntegerIndicator = pbSig.wlIndicator;
810 phasebiasSat->Biases[ii].SignalDiscontinuityCounter = pbSig.discontinuityCounter;
811 if (_bsx) {
812 QString obsCode = 'L' + pbSig.type;
813 _bsx->write(epoTime.gpsw(), epoTime.gpssec(), prnStr, obsCode, pbSig.bias);
814 }
815 }
816 }
817 }
818 }
819 }
820
821 QByteArray hlpBufferCo;
822
823 // Orbit and Clock Corrections together
824 // ------------------------------------
825 if (_samplRtcmEphCorr == _samplRtcmClkCorr) {
826 if (co.NumberOfSat[CLOCKORBIT_SATGPS] > 0
827 || co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0
828 || co.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0
829 || co.NumberOfSat[CLOCKORBIT_SATQZSS] > 0
830 || co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0
831 || co.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
832 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
833 int len = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_AUTO, 0, obuffer, sizeof(obuffer));
834 if (len > 0) {
835 hlpBufferCo = QByteArray(obuffer, len);
836 }
837 }
838 }
839
840 // Orbit and Clock Corrections separately
841 // --------------------------------------
842 else {
843 if (co.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
844 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
845 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
846 co.UpdateInterval = ephUpdInd;
847 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GPSORBIT, 1, obuffer, sizeof(obuffer));
848 co.UpdateInterval = clkUpdInd;
849 if (len1 > 0) {
850 hlpBufferCo += QByteArray(obuffer, len1);
851 }
852 }
853 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0 ||
854 co.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0 ||
855 co.NumberOfSat[CLOCKORBIT_SATQZSS] > 0 ||
856 co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 ||
857 co.NumberOfSat[CLOCKORBIT_SATBDS] > 0 ) ? 1 : 0;
858 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GPSCLOCK, mmsg, obuffer, sizeof(obuffer));
859 if (len2 > 0) {
860 hlpBufferCo += QByteArray(obuffer, len2);
861 }
862 }
863 if (co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
864 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
865 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
866 co.UpdateInterval = ephUpdInd;
867 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GLONASSORBIT, 1, obuffer, sizeof(obuffer));
868 co.UpdateInterval = clkUpdInd;
869 if (len1 > 0) {
870 hlpBufferCo += QByteArray(obuffer, len1);
871 }
872 }
873 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0 ||
874 co.NumberOfSat[CLOCKORBIT_SATQZSS] > 0 ||
875 co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 ||
876 co.NumberOfSat[CLOCKORBIT_SATBDS] > 0 ) ? 1 : 0;
877 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GLONASSCLOCK, mmsg, obuffer, sizeof(obuffer));
878 if (len2 > 0) {
879 hlpBufferCo += QByteArray(obuffer, len2);
880 }
881 }
882 if (co.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
883 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
884 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
885 co.UpdateInterval = ephUpdInd;
886 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GALILEOORBIT, 1, obuffer, sizeof(obuffer));
887 co.UpdateInterval = clkUpdInd;
888 if (len1 > 0) {
889 hlpBufferCo += QByteArray(obuffer, len1);
890 }
891 }
892 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATQZSS] > 0 ||
893 co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 ||
894 co.NumberOfSat[CLOCKORBIT_SATBDS] > 0 ) ? 1 : 0;
895 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_GALILEOCLOCK, mmsg, obuffer, sizeof(obuffer));
896 if (len2 > 0) {
897 hlpBufferCo += QByteArray(obuffer, len2);
898 }
899 }
900 if (co.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
901 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
902 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
903 co.UpdateInterval = ephUpdInd;
904 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_QZSSORBIT, 1, obuffer, sizeof(obuffer));
905 co.UpdateInterval = clkUpdInd;
906 if (len1 > 0) {
907 hlpBufferCo += QByteArray(obuffer, len1);
908 }
909 }
910 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 ||
911 co.NumberOfSat[CLOCKORBIT_SATBDS] > 0 ) ? 1 : 0;
912 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_QZSSCLOCK, mmsg, obuffer, sizeof(obuffer));
913 if (len2 > 0) {
914 hlpBufferCo += QByteArray(obuffer, len2);
915 }
916 }
917 if (co.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
918 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
919 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
920 co.UpdateInterval = ephUpdInd;
921 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_SBASORBIT, 1, obuffer, sizeof(obuffer));
922 co.UpdateInterval = clkUpdInd;
923 if (len1 > 0) {
924 hlpBufferCo += QByteArray(obuffer, len1);
925 }
926 }
927 int mmsg = (co.NumberOfSat[CLOCKORBIT_SATBDS] > 0) ? 1 : 0;
928 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_SBASCLOCK, mmsg, obuffer,
929 sizeof(obuffer));
930 if (len2 > 0) {
931 hlpBufferCo += QByteArray(obuffer, len2);
932 }
933 }
934 if (co.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
935 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
936 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
937 co.UpdateInterval = ephUpdInd;
938 int len1 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_BDSORBIT, 1, obuffer, sizeof(obuffer));
939 co.UpdateInterval = clkUpdInd;
940 if (len1 > 0) {
941 hlpBufferCo += QByteArray(obuffer, len1);
942 }
943 }
944 int mmsg = 0;
945 int len2 = _ssrCorr->MakeClockOrbit(&co, _ssrCorr->COTYPE_BDSCLOCK, mmsg, obuffer, sizeof(obuffer));
946 if (len2 > 0) {
947 hlpBufferCo += QByteArray(obuffer, len2);
948 }
949 }
950 }
951
952 // Code Biases
953 // -----------
954 QByteArray hlpBufferBias;
955 if (bias.NumberOfSat[CLOCKORBIT_SATGPS] > 0
956 || bias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0
957 || bias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0
958 || bias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0
959 || bias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0
960 || bias.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
961 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
962 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
963 int len = _ssrCorr->MakeCodeBias(&bias, _ssrCorr->CBTYPE_AUTO, 0, obuffer, sizeof(obuffer));
964 if (len > 0) {
965 hlpBufferBias = QByteArray(obuffer, len);
966 }
967 }
968 }
969
970 // Phase Biases
971 // ------------
972 QByteArray hlpBufferPhaseBias;
973 if ((phasebias.NumberOfSat[CLOCKORBIT_SATGPS] > 0
974 || phasebias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0
975 || phasebias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0
976 || phasebias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0
977 || phasebias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0
978 || phasebias.NumberOfSat[CLOCKORBIT_SATBDS] > 0)
979 && (_phaseBiasInformationDecoded)) {
980 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
981 if (fmod(epoTime.gpssec(), _samplRtcmEphCorr) == 0.0) {
982 int len = _ssrCorr->MakePhaseBias(&phasebias, _ssrCorr->PBTYPE_AUTO, 0, obuffer, sizeof(obuffer));
983 if (len > 0) {
984 hlpBufferPhaseBias = QByteArray(obuffer, len);
985 }
986 }
987 }
988
989 // VTEC
990 // ----
991 QByteArray hlpBufferVtec;
992 if (vtec.NumLayers > 0) {
993 char obuffer[CLOCKORBIT_BUFFERSIZE] = {'\0'};
994 int len = _ssrCorr->MakeVTEC(&vtec, 0, obuffer, sizeof(obuffer));
995 if (len > 0) {
996 hlpBufferVtec = QByteArray(obuffer, len);
997 }
998 }
999
1000 _outBuffer += hlpBufferCo + hlpBufferBias + hlpBufferPhaseBias + hlpBufferVtec + '\0';
1001}
1002//
1003////////////////////////////////////////////////////////////////////////////
1004t_irc bncRtnetUploadCaster::processSatellite(const t_eph* eph, int GPSweek,
1005 double GPSweeks, const QString& prn, const ColumnVector& rtnAPC,
1006 double rtnUra, const ColumnVector& rtnClk, const ColumnVector& rtnVel,
1007 const ColumnVector& rtnCoM, const ColumnVector& rtnClkSig,
1008 struct SsrCorr::ClockOrbit::SatData* sd, QString& outLine) {
1009
1010 // Broadcast Position and Velocity
1011 // -------------------------------
1012 ColumnVector xB(6);
1013 ColumnVector vB(3);
1014 t_irc irc = eph->getCrd(bncTime(GPSweek, GPSweeks), xB, vB, false);
1015
1016 if (irc != success) {
1017 return irc;
1018 }
1019
1020 // Precise Position
1021 // ----------------
1022 ColumnVector xP = _CoM ? rtnCoM : rtnAPC;
1023
1024 if (xP.size() == 0) {
1025 return failure;
1026 }
1027
1028 double dc = 0.0;
1029 if (_crdTrafo != "IGS20") {
1030 crdTrafo14(GPSweek, xP, dc); // ITRF2020 => ITRF2014
1031 crdTrafo(GPSweek, xP, dc); // ITRF2014 to other reference frames
1032 }
1033
1034 // Difference in xyz
1035 // -----------------
1036 ColumnVector dx = xB.Rows(1, 3) - xP;
1037 ColumnVector dv = vB - rtnVel;
1038
1039 // Difference in RSW
1040 // -----------------
1041 ColumnVector rsw(3);
1042 XYZ_to_RSW(xB.Rows(1, 3), vB, dx, rsw);
1043
1044 ColumnVector dotRsw(3);
1045 XYZ_to_RSW(xB.Rows(1, 3), vB, dv, dotRsw);
1046
1047 // Clock Correction
1048 // ----------------
1049 double dClkA0 = rtnClk(1) - (xB(4) - dc) * t_CST::c;
1050 double dClkA1 = 0.0;
1051 if (rtnClk(2)) {
1052 dClkA1 = rtnClk(2) - xB(5) * t_CST::c;
1053 }
1054 double dClkA2 = 0.0;
1055 if (rtnClk(3)) {
1056 dClkA2 = rtnClk(3) - xB(6) * t_CST::c;
1057 }
1058
1059 if (sd) {
1060 sd->ID = prn.mid(1).toInt();
1061 sd->IOD = eph->IOD();
1062 sd->Clock.DeltaA0 = dClkA0;
1063 sd->Clock.DeltaA1 = dClkA1;
1064 sd->Clock.DeltaA2 = dClkA2;
1065 sd->UserRangeAccuracy = rtnUra;
1066 sd->Orbit.DeltaRadial = rsw(1);
1067 sd->Orbit.DeltaAlongTrack = rsw(2);
1068 sd->Orbit.DeltaCrossTrack = rsw(3);
1069 sd->Orbit.DotDeltaRadial = dotRsw(1);
1070 sd->Orbit.DotDeltaAlongTrack = dotRsw(2);
1071 sd->Orbit.DotDeltaCrossTrack = dotRsw(3);
1072
1073 if (corrIsOutOfRange(sd)) {
1074 return failure;
1075 }
1076 }
1077
1078 outLine = QString().asprintf("%d %.1f %s %u %10.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", GPSweek,
1079 GPSweeks, eph->prn().toString().c_str(), eph->IOD(), dClkA0, dClkA1, dClkA2,
1080 rsw(1), rsw(2), rsw(3)); //fprintf(stderr, "%s\n", outLine.toStdString().c_str());
1081
1082 // RTNET full clock for RINEX and SP3 file
1083 // ---------------------------------------
1084 double relativity = -2.0 * DotProduct(xP, rtnVel) / t_CST::c;
1085 double clkRnx = (rtnClk[0] - relativity) / t_CST::c; // [s]
1086 double clkRnxRate = rtnClk[1] / t_CST::c; // [s/s = -]
1087 double clkRnxAcc = rtnClk[2] / t_CST::c; // [s/s² = -/s]
1088
1089 if (_rnx) {
1090 double clkRnxSig, clkRnxRateSig, clkRnxAccSig;
1091 int s = rtnClkSig.size();
1092 switch (s) {
1093 case 1:
1094 clkRnxSig = rtnClkSig[0] / t_CST::c; // [s]
1095 clkRnxRateSig = 0.0; // [s/s = -]
1096 clkRnxAccSig = 0.0; // [s/s² ) -/s]
1097 break;
1098 case 2:
1099 clkRnxSig = rtnClkSig[0] / t_CST::c; // [s]
1100 clkRnxRateSig = rtnClkSig[1] / t_CST::c; // [s/s = -]
1101 clkRnxAccSig = 0.0; // [s/s² ) -/s]
1102 break;
1103 case 3:
1104 clkRnxSig = rtnClkSig[0] / t_CST::c; // [s]
1105 clkRnxRateSig = rtnClkSig[1] / t_CST::c; // [s/s = -]
1106 clkRnxAccSig = rtnClkSig[2] / t_CST::c; // [s/s² ) -/s]
1107 break;
1108 }
1109 _rnx->write(GPSweek, GPSweeks, prn, clkRnx, clkRnxRate, clkRnxAcc,
1110 clkRnxSig, clkRnxRateSig, clkRnxAccSig);
1111 }
1112 if (_sp3) {
1113 _sp3->write(GPSweek, GPSweeks, prn, rtnCoM, clkRnx, rtnVel, clkRnxRate);
1114 }
1115 return success;
1116}
1117
1118// Transform Coordinates
1119////////////////////////////////////////////////////////////////////////////
1120void bncRtnetUploadCaster::crdTrafo(int GPSWeek, ColumnVector& xyz,
1121 double& dc) {
1122
1123 // Current epoch minus 2000.0 in years
1124 // ------------------------------------
1125 double dt = (GPSWeek - (1042.0 + 6.0 / 7.0)) / 365.2422 * 7.0 + 2000.0 - _t0;
1126
1127 ColumnVector dx(3);
1128
1129 dx(1) = _dx + dt * _dxr;
1130 dx(2) = _dy + dt * _dyr;
1131 dx(3) = _dz + dt * _dzr;
1132
1133 static const double arcSec = 180.0 * 3600.0 / M_PI;
1134
1135 double ox = (_ox + dt * _oxr) / arcSec;
1136 double oy = (_oy + dt * _oyr) / arcSec;
1137 double oz = (_oz + dt * _ozr) / arcSec;
1138
1139 double sc = 1.0 + _sc * 1e-9 + dt * _scr * 1e-9;
1140
1141 // Specify approximate center of area
1142 // ----------------------------------
1143 ColumnVector meanSta(3);
1144
1145 if (_crdTrafo == "ETRF2000") {
1146 meanSta(1) = 3661090.0;
1147 meanSta(2) = 845230.0;
1148 meanSta(3) = 5136850.0;
1149 }
1150 else if (_crdTrafo == "GDA2020") {
1151 meanSta(1) = -4052050.0;
1152 meanSta(2) = 4212840.0;
1153 meanSta(3) = -2545110.0;
1154 }
1155 else if (_crdTrafo == "SIRGAS2000") {
1156 meanSta(1) = 3740860.0;
1157 meanSta(2) = -4964290.0;
1158 meanSta(3) = -1425420.0;
1159 }
1160 else if (_crdTrafo == "DREF91") {
1161 meanSta(1) = 3959579.0;
1162 meanSta(2) = 721719.0;
1163 meanSta(3) = 4931539.0;
1164 }
1165 else if (_crdTrafo == "Custom") {
1166 meanSta(1) = 0.0;
1167 meanSta(2) = 0.0;
1168 meanSta(3) = 0.0;
1169 }
1170
1171 // Clock correction proportional to topocentric distance to satellites
1172 // -------------------------------------------------------------------
1173 double rho = (xyz - meanSta).NormFrobenius();
1174 dc = rho * (sc - 1.0) / sc / t_CST::c;
1175
1176 Matrix rMat(3, 3);
1177 rMat(1, 1) = 1.0;
1178 rMat(1, 2) = -oz;
1179 rMat(1, 3) = oy;
1180 rMat(2, 1) = oz;
1181 rMat(2, 2) = 1.0;
1182 rMat(2, 3) = -ox;
1183 rMat(3, 1) = -oy;
1184 rMat(3, 2) = ox;
1185 rMat(3, 3) = 1.0;
1186
1187 xyz = sc * rMat * xyz + dx;
1188}
1189
1190// Transform Coordinates
1191////////////////////////////////////////////////////////////////////////////
1192void bncRtnetUploadCaster::crdTrafo14(int GPSWeek, ColumnVector& xyz,
1193 double& dc) {
1194
1195 // Current epoch minus 2000.0 in years
1196 // ------------------------------------
1197 double dt = (GPSWeek - (1042.0 + 6.0 / 7.0)) / 365.2422 * 7.0 + 2000.0 - _t0;
1198
1199 ColumnVector dx(3);
1200
1201 dx(1) = _dx14 + dt * _dxr14;
1202 dx(2) = _dy14 + dt * _dyr14;
1203 dx(3) = _dz14 + dt * _dzr14;
1204
1205 static const double arcSec = 180.0 * 3600.0 / M_PI;
1206
1207 double ox = (_ox14 + dt * _oxr14) / arcSec;
1208 double oy = (_oy14 + dt * _oyr14) / arcSec;
1209 double oz = (_oz14 + dt * _ozr14) / arcSec;
1210
1211 double sc = 1.0 + _sc14 * 1e-9 + dt * _scr14 * 1e-9;
1212
1213 // Specify approximate center of area
1214 // ----------------------------------
1215 ColumnVector meanSta(3);
1216 meanSta(1) = 0.0; // TODO
1217 meanSta(2) = 0.0; // TODO
1218 meanSta(3) = 0.0; // TODO
1219
1220 // Clock correction proportional to topocentric distance to satellites
1221 // -------------------------------------------------------------------
1222 double rho = (xyz - meanSta).NormFrobenius();
1223 dc = rho * (sc - 1.0) / sc / t_CST::c;
1224
1225 Matrix rMat(3, 3);
1226 rMat(1, 1) = 1.0;
1227 rMat(1, 2) = -oz;
1228 rMat(1, 3) = oy;
1229 rMat(2, 1) = oz;
1230 rMat(2, 2) = 1.0;
1231 rMat(2, 3) = -ox;
1232 rMat(3, 1) = -oy;
1233 rMat(3, 2) = ox;
1234 rMat(3, 3) = 1.0;
1235
1236 xyz = sc * rMat * xyz + dx;
1237}
1238
1239// Update Interval
1240////////////////////////////////////////////////////////////////////////////
1241int bncRtnetUploadCaster::determineUpdateInd(double samplingRate) {
1242
1243 if (samplingRate == 10.0) {
1244 return 3;
1245 }
1246 else if (samplingRate == 15.0) {
1247 return 4;
1248 }
1249 else if (samplingRate == 30.0) {
1250 return 5;
1251 }
1252 else if (samplingRate == 60.0) {
1253 return 6;
1254 }
1255 else if (samplingRate == 120.0) {
1256 return 7;
1257 }
1258 else if (samplingRate == 240.0) {
1259 return 8;
1260 }
1261 else if (samplingRate == 300.0) {
1262 return 9;
1263 }
1264 else if (samplingRate == 600.0) {
1265 return 10;
1266 }
1267 else if (samplingRate == 900.0) {
1268 return 11;
1269 }
1270 else if (samplingRate == 1800.0) {
1271 return 12;
1272 }
1273 else if (samplingRate == 3600.0) {
1274 return 13;
1275 }
1276 else if (samplingRate == 7200.0) {
1277 return 14;
1278 }
1279 else if (samplingRate == 10800.0) {
1280 return 15;
1281 }
1282 return 2; // default
1283}
1284
1285// Check corrections
1286////////////////////////////////////////////////////////////////////////////
1287bool bncRtnetUploadCaster::corrIsOutOfRange(struct SsrCorr::ClockOrbit::SatData* sd) {
1288
1289 if (fabs(sd->Clock.DeltaA0) > 209.7151) {return true;}
1290 if (fabs(sd->Clock.DeltaA1) > 1.048575) {return true;}
1291 if (fabs(sd->Clock.DeltaA2) > 1.34217726) {return true;}
1292
1293 if (fabs(sd->Orbit.DeltaRadial) > 209.7151) {return true;}
1294 if (fabs(sd->Orbit.DeltaAlongTrack) > 209.7148) {return true;}
1295 if (fabs(sd->Orbit.DeltaCrossTrack) > 209.7148) {return true;}
1296
1297 if (fabs(sd->Orbit.DotDeltaRadial) > 1.048575) {return true;}
1298 if (fabs(sd->Orbit.DotDeltaAlongTrack) > 1.048572) {return true;}
1299 if (fabs(sd->Orbit.DotDeltaCrossTrack) > 1.048572) {return true;}
1300 return false;
1301}
Note: See TracBrowser for help on using the repository browser.