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

Last change on this file since 6428 was 6428, checked in by mervart, 9 years ago
File size: 12.5 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
51bool excludeSat(const t_prn& prn) {
52 if (prn == t_prn('R', 7)) {
53 return true;
54 }
55 else {
56 return false;
57 }
58}
59
60// Constructor
61////////////////////////////////////////////////////////////////////////////
62t_sp3Comp::t_sp3Comp(QObject* parent) : QThread(parent) {
63
64 bncSettings settings;
65 _sp3FileNames = settings.value("sp3CompFile").toString().split(',', QString::SkipEmptyParts);
66 for (int ii = 0; ii < _sp3FileNames.size(); ii++) {
67 expandEnvVar(_sp3FileNames[ii]);
68 }
69 _logFileName = settings.value("sp3CompOutLogFile").toString(); expandEnvVar(_logFileName);
70 _logFile = 0;
71 _log = 0;
72}
73
74// Destructor
75////////////////////////////////////////////////////////////////////////////
76t_sp3Comp::~t_sp3Comp() {
77 delete _log;
78 delete _logFile;
79}
80
81//
82////////////////////////////////////////////////////////////////////////////
83void t_sp3Comp::run() {
84
85 // Open Log File
86 // -------------
87 _logFile = new QFile(_logFileName);
88 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
89 _log = new QTextStream();
90 _log->setDevice(_logFile);
91 }
92 if (!_log) {
93 goto end;
94 }
95
96 for (int ii = 0; ii < _sp3FileNames.size(); ii++) {
97 *_log << "! SP3 File " << ii+1 << ": " << _sp3FileNames[ii] << endl;
98 }
99 if (_sp3FileNames.size() != 2) {
100 *_log << "ERROR: sp3Comp requires two input SP3 files" << endl;
101 goto end;
102 }
103
104 try {
105 ostringstream msg;
106 compare(msg);
107 *_log << msg.str().c_str();
108 }
109 catch (const string& error) {
110 *_log << "ERROR: " << error.c_str() << endl;
111 }
112 catch (const char* error) {
113 *_log << "ERROR: " << error << endl;
114 }
115 catch (Exception& exc) {
116 *_log << "ERROR: " << exc.what() << endl;
117 }
118 catch (...) {
119 *_log << "ERROR: " << "unknown exception" << endl;
120 }
121
122 // Exit (thread)
123 // -------------
124 end:
125 if (BNC_CORE->mode() != t_bncCore::interactive) {
126 qApp->exit(0);
127 }
128 else {
129 emit finished();
130 deleteLater();
131 }
132}
133
134// Satellite Index in clkSats set
135////////////////////////////////////////////////////////////////////////////////
136int t_sp3Comp::satIndex(const set<t_prn>& clkSats, const t_prn& prn) const {
137 int ret = 0;
138 for (set<t_prn>::const_iterator it = clkSats.begin(); it != clkSats.end(); it++) {
139 if ( *it == prn) {
140 return ret;
141 }
142 ++ret;
143 }
144 return -1;
145}
146
147// Estimate Clock Offsets
148////////////////////////////////////////////////////////////////////////////////
149void t_sp3Comp::processClocks(const set<t_prn>& clkSats, const vector<t_epoch*>& epochsIn,
150 map<string, t_stat>& stat) const {
151
152 if (clkSats.size() == 0) {
153 return;
154 }
155
156 vector<t_epoch*> epochs;
157 for (unsigned ii = 0; ii < epochsIn.size(); ii++) {
158 if (epochsIn[ii]->_dc.size() > 0) {
159 epochs.push_back(epochsIn[ii]);
160 }
161 }
162 if (epochs.size() == 0) {
163 return;
164 }
165
166 int nPar = epochs.size() + clkSats.size();
167 SymmetricMatrix NN(nPar); NN = 0.0;
168 ColumnVector bb(nPar); bb = 0.0;
169
170 // Create Matrix A'A and vector b
171 // ------------------------------
172 for (unsigned ie = 0; ie < epochs.size(); ie++) {
173 const map<t_prn, double>& dc = epochs[ie]->_dc;
174 Matrix AA(dc.size(), nPar); AA = 0.0;
175 ColumnVector ll(dc.size()); ll = 0.0;
176 map<t_prn, double>::const_iterator it;
177 int ii = -1;
178 for (it = dc.begin(); it != dc.end(); it++) {
179 const t_prn& prn = it->first;
180 if (satIndex(clkSats, prn) != -1) {
181 ++ii;
182 int index = epochs.size() + satIndex(clkSats, prn);
183 AA[ii][ie] = 1.0; // epoch-specfic offset (common for all satellites)
184 AA[ii][index] = 1.0; // satellite-specific offset (common for all epochs)
185 ll[ii] = it->second;
186 }
187 }
188 SymmetricMatrix dN; dN << AA.t() * AA;
189 NN += dN;
190 bb += AA.t() * ll;
191 }
192
193 // Regularize NN
194 // -------------
195 RowVector HH(nPar);
196 HH.columns(1, epochs.size()) = 0.0;
197 HH.columns(epochs.size()+1, nPar) = 1.0;
198 SymmetricMatrix dN; dN << HH.t() * HH;
199 NN += dN;
200
201 // Estimate Parameters
202 // -------------------
203 ColumnVector xx = NN.i() * bb;
204
205 // Compute clock residuals
206 // -----------------------
207 for (unsigned ie = 0; ie < epochs.size(); ie++) {
208 map<t_prn, double>& dc = epochs[ie]->_dc;
209 for (map<t_prn, double>::iterator it = dc.begin(); it != dc.end(); it++) {
210 const t_prn& prn = it->first;
211 if (satIndex(clkSats, prn) != -1) {
212 int index = epochs.size() + satIndex(clkSats, prn);
213 dc[prn] = it->second - xx[ie] - xx[index];
214 stat[prn.toString()]._offset = xx[index];
215 }
216 }
217 }
218}
219
220// Main Routine
221////////////////////////////////////////////////////////////////////////////////
222void t_sp3Comp::compare(ostringstream& out) const {
223
224 // Synchronize reading of two sp3 files
225 // ------------------------------------
226 bncSP3 in1(_sp3FileNames[0]); in1.nextEpoch();
227 bncSP3 in2(_sp3FileNames[1]); in2.nextEpoch();
228
229 vector<t_epoch*> epochs;
230 while (in1.currEpoch() && in2.currEpoch()) {
231 bncTime t1 = in1.currEpoch()->_tt;
232 bncTime t2 = in2.currEpoch()->_tt;
233 if (t1 < t2) {
234 in1.nextEpoch();
235 }
236 else if (t1 > t2) {
237 in2.nextEpoch();
238 }
239 else if (t1 == t2) {
240 t_epoch* epo = new t_epoch; epo->_tt = t1;
241 bool epochOK = false;
242 for (int i1 = 0; i1 < in1.currEpoch()->_sp3Sat.size(); i1++) {
243 bncSP3::t_sp3Sat* sat1 = in1.currEpoch()->_sp3Sat[i1];
244 for (int i2 = 0; i2 < in2.currEpoch()->_sp3Sat.size(); i2++) {
245 bncSP3::t_sp3Sat* sat2 = in2.currEpoch()->_sp3Sat[i2];
246 if (sat1->_prn == sat2->_prn) {
247 epochOK = true;
248 epo->_dr[sat1->_prn] = sat1->_xyz - sat2->_xyz;
249 epo->_xyz[sat1->_prn] = sat1->_xyz;
250 if (sat1->_clkValid && sat2->_clkValid) {
251 epo->_dc[sat1->_prn] = sat1->_clk - sat2->_clk;
252 }
253 }
254 }
255 }
256 if (epochOK) {
257 epochs.push_back(epo);
258 }
259 else {
260 delete epo;
261 }
262 in1.nextEpoch();
263 in2.nextEpoch();
264 }
265 }
266
267 // Transform xyz into radial, along-track, and out-of-plane
268 // --------------------------------------------------------
269 if (epochs.size() < 2) {
270 throw "t_sp3Comp: not enough common epochs";
271 }
272
273 set<t_prn> clkSatsAll;
274
275 for (unsigned ie = 0; ie < epochs.size(); ie++) {
276 t_epoch* epoch = epochs[ie];
277 t_epoch* epoch2 = 0;
278 if (ie == 0) {
279 epoch2 = epochs[ie+1];
280 }
281 else {
282 epoch2 = epochs[ie-1];
283 }
284 double dt = epoch->_tt - epoch2->_tt;
285 map<t_prn, ColumnVector>& dr = epoch->_dr;
286 map<t_prn, ColumnVector>& xyz = epoch->_xyz;
287 map<t_prn, ColumnVector>& xyz2 = epoch2->_xyz;
288 for (map<t_prn, ColumnVector>::const_iterator it = dr.begin(); it != dr.end(); it++) {
289 const t_prn& prn = it->first;
290 if (xyz2.find(prn) != xyz2.end()) {
291 const ColumnVector dx = dr[prn];
292 const ColumnVector& x1 = xyz[prn];
293 const ColumnVector& x2 = xyz2[prn];
294 ColumnVector vel = (x1 - x2) / dt;
295 XYZ_to_RSW(x1, vel, dx, dr[prn]);
296 if (epoch->_dc.find(prn) != epoch->_dc.end()) {
297 clkSatsAll.insert(prn);
298 }
299 }
300 else {
301 epoch->_dr.erase(prn);
302 epoch->_xyz.erase(prn);
303 epoch->_dc.erase(prn);
304 }
305 }
306 }
307
308 map<string, t_stat> stat;
309
310 // Estimate Clock Offsets
311 // ----------------------
312 string systems;
313 for (set<t_prn>::const_iterator it = clkSatsAll.begin(); it != clkSatsAll.end(); it++) {
314 if (systems.find(it->system()) == string::npos) {
315 systems += it->system();
316 }
317 }
318 for (unsigned iSys = 0; iSys < systems.size(); iSys++) {
319 char system = systems[iSys];
320 set<t_prn> clkSats;
321 for (set<t_prn>::const_iterator it = clkSatsAll.begin(); it != clkSatsAll.end(); it++) {
322 if (it->system() == system && !excludeSat(*it)) {
323 clkSats.insert(*it);
324 }
325 }
326 processClocks(clkSats, epochs, stat);
327 }
328
329 // Print Residuals
330 // ---------------
331 const string all = "ZZZ";
332
333 out.setf(ios::fixed);
334 out << "!\n! MJD PRN radial along out clk clkRed iPRN"
335 "\n! ----------------------------------------------------------------\n";
336 for (unsigned ii = 0; ii < epochs.size(); ii++) {
337 const t_epoch* epo = epochs[ii];
338 const map<t_prn, ColumnVector>& dr = epochs[ii]->_dr;
339 const map<t_prn, double>& dc = epochs[ii]->_dc;
340 for (map<t_prn, ColumnVector>::const_iterator it = dr.begin(); it != dr.end(); it++) {
341 const t_prn& prn = it->first;
342 if (!excludeSat(prn)) {
343 const ColumnVector& rao = it->second;
344 out << setprecision(6) << epo->_tt.mjddec() << ' ' << prn.toString() << ' '
345 << setw(7) << setprecision(4) << rao[0] << ' '
346 << setw(7) << setprecision(4) << rao[1] << ' '
347 << setw(7) << setprecision(4) << rao[2] << " ";
348 stat[prn.toString()]._rao += SP(rao, rao); // Schur product
349 stat[prn.toString()]._nr += 1;
350 stat[all]._rao += SP(rao, rao);
351 stat[all]._nr += 1;
352 if (dc.find(prn) != dc.end()) {
353 double clkRes = dc.find(prn)->second;
354 double clkResRed = clkRes - it->second[0]; // clock minus radial component
355 out << setw(7) << setprecision(4) << clkRes << ' '
356 << setw(7) << setprecision(4) << clkResRed;
357 stat[prn.toString()]._dc += clkRes * clkRes;
358 stat[prn.toString()]._dcRed += clkResRed * clkResRed;
359 stat[prn.toString()]._nc += 1;
360 stat[all]._dc += clkRes * clkRes;
361 stat[all]._dcRed += clkResRed * clkResRed;
362 stat[all]._nc += 1;
363 }
364 else {
365 out << " . . ";
366 }
367 out << " " << setw(2) << int(prn) << endl;
368 }
369 }
370 delete epo;
371 }
372
373 // Print Summary
374 // -------------
375 out << "!\n! RMS:\n";
376 for (map<string, t_stat>::iterator it = stat.begin(); it != stat.end(); it++) {
377 const string& prn = it->first;
378 t_stat& stat = it->second;
379 if (stat._nr > 0) {
380 stat._rao[0] = sqrt(stat._rao[0] / stat._nr);
381 stat._rao[1] = sqrt(stat._rao[1] / stat._nr);
382 stat._rao[2] = sqrt(stat._rao[2] / stat._nr);
383 if (prn == all) {
384 out << "!\n! Total ";
385 }
386 else {
387 out << "! " << prn << ' ';
388 }
389 out << setw(7) << setprecision(4) << stat._rao[0] << ' '
390 << setw(7) << setprecision(4) << stat._rao[1] << ' '
391 << setw(7) << setprecision(4) << stat._rao[2] << " ";
392 if (stat._nc > 0) {
393 stat._dc = sqrt(stat._dc / stat._nc);
394 stat._dcRed = sqrt(stat._dcRed / stat._nc);
395 out << setw(7) << setprecision(4) << stat._dc << ' '
396 << setw(7) << setprecision(4) << stat._dcRed;
397 if (prn != all) {
398 out << " offset " << setw(9) << setprecision(4) << stat._offset;
399 }
400 }
401 else {
402 out << " . . ";
403 }
404 out << endl;
405 }
406 }
407}
408
409//
410////////////////////////////////////////////////////////////////////////////
411bool t_sp3Comp::excludeSat(const t_prn& prn) const {
412 if (prn == t_prn('R', 7)) {
413 return true;
414 }
415 else {
416 return false;
417 }
418}
419
Note: See TracBrowser for help on using the repository browser.