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

Last change on this file since 9245 was 9245, checked in by stuerze, 7 months ago

another check is added, to prevent the usage of not updated nav data sets during ssr upload

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