source: ntrip/trunk/BNC/src/orbComp/sp3Comp.cpp@ 8646

Last change on this file since 8646 was 8204, checked in by wiese, 7 years ago

CHANGE: #105 toAscii deprecated

File size: 13.3 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: t_sp3Comp
30 *
31 * Purpose: Compare SP3 Files
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Nov-2014
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include "sp3Comp.h"
44#include "bnccore.h"
45#include "bncsettings.h"
46#include "bncutils.h"
47#include "bncsp3.h"
48
49using namespace std;
50
51// Constructor
52////////////////////////////////////////////////////////////////////////////
53t_sp3Comp::t_sp3Comp(QObject* parent) : QThread(parent) {
54
55 bncSettings settings;
56 _sp3FileNames = settings.value("sp3CompFile").toString().split(QRegExp("[ ,]"), QString::SkipEmptyParts);
57 for (int ii = 0; ii < _sp3FileNames.size(); ii++) {
58 expandEnvVar(_sp3FileNames[ii]);
59 }
60 _logFileName = settings.value("sp3CompOutLogFile").toString(); expandEnvVar(_logFileName);
61 _logFile = 0;
62 _log = 0;
63
64 _excludeSats = settings.value("sp3CompExclude").toString().split(QRegExp("[ ,]"), QString::SkipEmptyParts);
65}
66
67// Destructor
68////////////////////////////////////////////////////////////////////////////
69t_sp3Comp::~t_sp3Comp() {
70 delete _log;
71 delete _logFile;
72}
73
74//
75////////////////////////////////////////////////////////////////////////////
76void t_sp3Comp::run() {
77
78 // Open Log File
79 // -------------
80 _logFile = new QFile(_logFileName);
81 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
82 _log = new QTextStream();
83 _log->setDevice(_logFile);
84 }
85 if (!_log) {
86 goto end;
87 }
88
89 for (int ii = 0; ii < _sp3FileNames.size(); ii++) {
90 *_log << "! SP3 File " << ii+1 << ": " << _sp3FileNames[ii] << endl;
91 }
92 if (_sp3FileNames.size() != 2) {
93 *_log << "ERROR: sp3Comp requires two input SP3 files" << endl;
94 goto end;
95 }
96
97 try {
98 ostringstream msg;
99 compare(msg);
100 *_log << msg.str().c_str();
101 }
102 catch (const string& error) {
103 *_log << "ERROR: " << error.c_str() << endl;
104 }
105 catch (const char* error) {
106 *_log << "ERROR: " << error << endl;
107 }
108 catch (Exception& exc) {
109 *_log << "ERROR: " << exc.what() << endl;
110 }
111 catch (std::exception& exc) {
112 *_log << "ERROR: " << exc.what() << endl;
113 }
114 catch (QString error) {
115 *_log << "ERROR: " << error << endl;
116 }
117 catch (...) {
118 *_log << "ERROR: " << "unknown exception" << endl;
119 }
120
121 // Exit (thread)
122 // -------------
123 end:
124 _log->flush();
125 if (BNC_CORE->mode() != t_bncCore::interactive) {
126 qApp->exit(0);
127 msleep(100); //sleep 0.1 sec
128 }
129 else {
130 emit finished();
131 deleteLater();
132 }
133}
134
135// Satellite Index in clkSats set
136////////////////////////////////////////////////////////////////////////////////
137int t_sp3Comp::satIndex(const set<t_prn>& clkSats, const t_prn& prn) const {
138 int ret = 0;
139 for (set<t_prn>::const_iterator it = clkSats.begin(); it != clkSats.end(); it++) {
140 if ( *it == prn) {
141 return ret;
142 }
143 ++ret;
144 }
145 return -1;
146}
147
148// Estimate Clock Offsets
149////////////////////////////////////////////////////////////////////////////////
150void t_sp3Comp::processClocks(const set<t_prn>& clkSats, const vector<t_epoch*>& epochsIn,
151 map<string, t_stat>& stat) const {
152
153 if (clkSats.size() == 0) {
154 return;
155 }
156
157 vector<t_epoch*> epochs;
158 for (unsigned ii = 0; ii < epochsIn.size(); ii++) {
159 unsigned numSatOK = 0;
160 std::map<t_prn, double>::const_iterator it;
161 for (it = epochsIn[ii]->_dc.begin(); it != epochsIn[ii]->_dc.end(); it++) {
162 if (satIndex(clkSats, it->first) != -1) {
163 numSatOK += 1;
164 }
165 }
166 if (numSatOK > 0) {
167 epochs.push_back(epochsIn[ii]);
168 }
169 }
170 if (epochs.size() == 0) {
171 return;
172 }
173
174 int nPar = epochs.size() + clkSats.size();
175 SymmetricMatrix NN(nPar); NN = 0.0;
176 ColumnVector bb(nPar); bb = 0.0;
177
178 // Create Matrix A'A and vector b
179 // ------------------------------
180 for (unsigned ie = 0; ie < epochs.size(); ie++) {
181 const map<t_prn, double>& dc = epochs[ie]->_dc;
182 Matrix AA(dc.size(), nPar); AA = 0.0;
183 ColumnVector ll(dc.size()); ll = 0.0;
184 map<t_prn, double>::const_iterator it;
185 int ii = -1;
186 for (it = dc.begin(); it != dc.end(); it++) {
187 const t_prn& prn = it->first;
188 if (satIndex(clkSats, prn) != -1) {
189 ++ii;
190 int index = epochs.size() + satIndex(clkSats, prn);
191 AA[ii][ie] = 1.0; // epoch-specfic offset (common for all satellites)
192 AA[ii][index] = 1.0; // satellite-specific offset (common for all epochs)
193 ll[ii] = it->second;
194 }
195 }
196 SymmetricMatrix dN; dN << AA.t() * AA;
197 NN += dN;
198 bb += AA.t() * ll;
199 }
200
201 // Regularize NN
202 // -------------
203 RowVector HH(nPar);
204 HH.columns(1, epochs.size()) = 0.0;
205 HH.columns(epochs.size()+1, nPar) = 1.0;
206 SymmetricMatrix dN; dN << HH.t() * HH;
207 NN += dN;
208
209 // Estimate Parameters
210 // -------------------
211 ColumnVector xx = NN.i() * bb;
212
213 // Compute clock residuals
214 // -----------------------
215 for (unsigned ie = 0; ie < epochs.size(); ie++) {
216 map<t_prn, double>& dc = epochs[ie]->_dc;
217 for (map<t_prn, double>::iterator it = dc.begin(); it != dc.end(); it++) {
218 const t_prn& prn = it->first;
219 if (satIndex(clkSats, prn) != -1) {
220 int index = epochs.size() + satIndex(clkSats, prn);
221 dc[prn] = it->second - xx[ie] - xx[index];
222 stat[prn.toString()]._offset = xx[index];
223 }
224 }
225 }
226}
227
228// Main Routine
229////////////////////////////////////////////////////////////////////////////////
230void t_sp3Comp::compare(ostringstream& out) const {
231
232 // Synchronize reading of two sp3 files
233 // ------------------------------------
234 bncSP3 in1(_sp3FileNames[0]); in1.nextEpoch();
235 bncSP3 in2(_sp3FileNames[1]); in2.nextEpoch();
236
237 vector<t_epoch*> epochs;
238 while (in1.currEpoch() && in2.currEpoch()) {
239 bncTime t1 = in1.currEpoch()->_tt;
240 bncTime t2 = in2.currEpoch()->_tt;
241 if (t1 < t2) {
242 in1.nextEpoch();
243 }
244 else if (t1 > t2) {
245 in2.nextEpoch();
246 }
247 else if (t1 == t2) {
248 t_epoch* epo = new t_epoch; epo->_tt = t1;
249 bool epochOK = false;
250 for (int i1 = 0; i1 < in1.currEpoch()->_sp3Sat.size(); i1++) {
251 bncSP3::t_sp3Sat* sat1 = in1.currEpoch()->_sp3Sat[i1];
252 for (int i2 = 0; i2 < in2.currEpoch()->_sp3Sat.size(); i2++) {
253 bncSP3::t_sp3Sat* sat2 = in2.currEpoch()->_sp3Sat[i2];
254 if (sat1->_prn == sat2->_prn) {
255 epochOK = true;
256 epo->_dr[sat1->_prn] = sat1->_xyz - sat2->_xyz;
257 epo->_xyz[sat1->_prn] = sat1->_xyz;
258 if (sat1->_clkValid && sat2->_clkValid) {
259 epo->_dc[sat1->_prn] = sat1->_clk - sat2->_clk;
260 }
261 }
262 }
263 }
264 if (epochOK) {
265 epochs.push_back(epo);
266 }
267 else {
268 delete epo;
269 }
270 in1.nextEpoch();
271 in2.nextEpoch();
272 }
273 }
274
275 // Transform xyz into radial, along-track, and out-of-plane
276 // --------------------------------------------------------
277 if (epochs.size() < 2) {
278 throw "t_sp3Comp: not enough common epochs";
279 }
280
281 set<t_prn> clkSatsAll;
282
283 for (unsigned ie = 0; ie < epochs.size(); ie++) {
284 t_epoch* epoch = epochs[ie];
285 t_epoch* epoch2 = 0;
286 if (ie == 0) {
287 epoch2 = epochs[ie+1];
288 }
289 else {
290 epoch2 = epochs[ie-1];
291 }
292 double dt = epoch->_tt - epoch2->_tt;
293 map<t_prn, ColumnVector>& dr = epoch->_dr;
294 map<t_prn, ColumnVector>& xyz = epoch->_xyz;
295 map<t_prn, ColumnVector>& xyz2 = epoch2->_xyz;
296 for (map<t_prn, ColumnVector>::const_iterator it = dr.begin(); it != dr.end(); it++) {
297 const t_prn& prn = it->first;
298 if (xyz2.find(prn) != xyz2.end()) {
299 const ColumnVector dx = dr[prn];
300 const ColumnVector& x1 = xyz[prn];
301 const ColumnVector& x2 = xyz2[prn];
302 ColumnVector vel = (x1 - x2) / dt;
303 XYZ_to_RSW(x1, vel, dx, dr[prn]);
304 if (epoch->_dc.find(prn) != epoch->_dc.end()) {
305 clkSatsAll.insert(prn);
306 }
307 }
308 else {
309 epoch->_dc.erase(prn);
310 epoch->_dr.erase(prn);
311 }
312 }
313 }
314
315 map<string, t_stat> stat;
316
317 // Estimate Clock Offsets
318 // ----------------------
319 string systems;
320 for (set<t_prn>::const_iterator it = clkSatsAll.begin(); it != clkSatsAll.end(); it++) {
321 if (systems.find(it->system()) == string::npos) {
322 systems += it->system();
323 }
324 }
325 for (unsigned iSys = 0; iSys < systems.size(); iSys++) {
326 char system = systems[iSys];
327 set<t_prn> clkSats;
328 for (set<t_prn>::const_iterator it = clkSatsAll.begin(); it != clkSatsAll.end(); it++) {
329 if (it->system() == system && !excludeSat(*it)) {
330 clkSats.insert(*it);
331 }
332 }
333 processClocks(clkSats, epochs, stat);
334 }
335
336 // Print Residuals
337 // ---------------
338 const string all = "ZZZ";
339
340 out.setf(ios::fixed);
341 out << "!\n! MJD PRN radial along out clk clkRed iPRN"
342 "\n! ----------------------------------------------------------------\n";
343 for (unsigned ii = 0; ii < epochs.size(); ii++) {
344 const t_epoch* epo = epochs[ii];
345 const map<t_prn, ColumnVector>& dr = epochs[ii]->_dr;
346 const map<t_prn, double>& dc = epochs[ii]->_dc;
347 for (map<t_prn, ColumnVector>::const_iterator it = dr.begin(); it != dr.end(); it++) {
348 const t_prn& prn = it->first;
349 if (!excludeSat(prn)) {
350 const ColumnVector& rao = it->second;
351 out << setprecision(6) << epo->_tt.mjddec() << ' ' << prn.toString() << ' '
352 << setw(7) << setprecision(4) << rao[0] << ' '
353 << setw(7) << setprecision(4) << rao[1] << ' '
354 << setw(7) << setprecision(4) << rao[2] << " ";
355 stat[prn.toString()]._rao += SP(rao, rao); // Schur product
356 stat[prn.toString()]._nr += 1;
357 stat[all]._rao += SP(rao, rao);
358 stat[all]._nr += 1;
359 if (dc.find(prn) != dc.end()) {
360 double clkRes = dc.find(prn)->second;
361 double clkResRed = clkRes - it->second[0]; // clock minus radial component
362 out << setw(7) << setprecision(4) << clkRes << ' '
363 << setw(7) << setprecision(4) << clkResRed;
364 stat[prn.toString()]._dc += clkRes * clkRes;
365 stat[prn.toString()]._dcRed += clkResRed * clkResRed;
366 stat[prn.toString()]._nc += 1;
367 stat[all]._dc += clkRes * clkRes;
368 stat[all]._dcRed += clkResRed * clkResRed;
369 stat[all]._nc += 1;
370 }
371 else {
372 out << " . . ";
373 }
374 out << " " << setw(2) << int(prn) << endl;
375 }
376 }
377 delete epo;
378 }
379
380 // Print Summary
381 // -------------
382 out << "!\n! RMS[m]\n";
383 out << "!\n! PRN radial along out nOrb clk clkRed nClk Offset"
384 "\n! ----------------------------------------------------------------------\n";
385 for (map<string, t_stat>::iterator it = stat.begin(); it != stat.end(); it++) {
386 const string& prn = it->first;
387 t_stat& stat = it->second;
388 if (stat._nr > 0) {
389 stat._rao[0] = sqrt(stat._rao[0] / stat._nr);
390 stat._rao[1] = sqrt(stat._rao[1] / stat._nr);
391 stat._rao[2] = sqrt(stat._rao[2] / stat._nr);
392 if (prn == all) {
393 out << "!\n! Total ";
394 }
395 else {
396 out << "! " << prn << ' ';
397 }
398 out << setw(7) << setprecision(4) << stat._rao[0] << ' '
399 << setw(7) << setprecision(4) << stat._rao[1] << ' '
400 << setw(7) << setprecision(4) << stat._rao[2] << ' '
401 << setw(6) << stat._nr << " ";
402 if (stat._nc > 0) {
403 stat._dc = sqrt(stat._dc / stat._nc);
404 stat._dcRed = sqrt(stat._dcRed / stat._nc);
405 out << setw(7) << setprecision(4) << stat._dc << ' '
406 << setw(7) << setprecision(4) << stat._dcRed << ' '
407 << setw(6) << stat._nc << " ";
408 if (prn != all) {
409 out << setw(9) << setprecision(4) << stat._offset;
410 }
411 }
412 else {
413 out << " . . ";
414 }
415 out << endl;
416 }
417 }
418}
419
420//
421////////////////////////////////////////////////////////////////////////////
422bool t_sp3Comp::excludeSat(const t_prn& prn) const {
423 QStringListIterator it(_excludeSats);
424 while (it.hasNext()) {
425 string prnStr = it.next().toLatin1().data();
426 if (prnStr == prn.toString() || prnStr == prn.toString().substr(0,1)) {
427 return true;
428 }
429 }
430 return false;
431}
432
Note: See TracBrowser for help on using the repository browser.