1 //==============================================================================
2 //
3 // This file is part of GPSTk, the GPS Toolkit.
4 //
5 // The GPSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GPSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GPSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38
39 /**
40 * @file Estimation.cpp
41 * Solve estimation problem using linearized least squares, part of program DDBase.
42 */
43
44 //------------------------------------------------------------------------------------
45 // TD Estimation.cpp SRIF convergence parameters -> input parameters
46 // TD Estimation.cpp For L3 : average DD WL range-phase to solve for widelane bias,
47 // TD Estimation.cpp use this to solve for biases, then allow fixing of biases.
48 // TD Estimation.cpp Need to account for signs in single diff
49 // TD Estimation.cpp Singular problems in Solve
50
51 //------------------------------------------------------------------------------------
52 // system includes
53 #include "TimeString.hpp"
54
55 // GPSTk
56 #include "Vector.hpp"
57 #include "Matrix.hpp"
58 #include "Namelist.hpp"
59 #include "SRIFilter.hpp"
60 #include "EphemerisRange.hpp"
61 #include "PreciseRange.hpp"
62 #include "Stats.hpp"
63 #include "RobustStats.hpp"
64 #include "GNSSconstants.hpp"
65
66 // DDBase
67 #include "DDBase.hpp"
68 #include "index.hpp"
69
70 //------------------------------------------------------------------------------------
71 using namespace std;
72 using namespace gpstk;
73 using namespace StringUtils;
74
75 //------------------------------------------------------------------------------------
76 void BuildStochasticModel(int count, Namelist& DNL, Matrix<double>& MCov);
77 // in StochasticModels.cpp
78
79 // prototypes -- this module only
80 // called by ConfigureEstimation(), which is Configure(3)
81 void DefineStateVector(void);
82 string ComposeName(const string& site1, const string& site2,
83 const GSatID& sat1, const GSatID& sat2);
84 string ComposeName(const DDid& ddid);
85 void DecomposeName(const string& label, string& site1, string& site2,
86 GSatID& sat1, GSatID& sat2);
87 // called by Estimation() -- inside the loop
88 int EditDDdata(int n);
89 int ModifyState(int n);
90 int InitializeEstimator(void);
91 int aPrioriConstraints(void);
92 int FillDataVector(int count);
93 void EvaluateLSEquation(int n, Vector<double>& X,Vector<double>& f,Matrix<double>& P);
94 int MeasurementUpdate(Matrix<double>& P, Vector<double>& f, Matrix<double>& MC);
95 int Solve(void);
96 int UpdateNominalState(void);
97 void OutputIterationResults(bool final);
98 int IterationControl(int iter_n);
99 void OutputFinalResults(int iret);
100 double RMSResidualOfFit(int N, Vector<double>& dX, bool final=false);
101
102 //------------------------------------------------------------------------------------
103 // local data
104 static int N,M; // lengths of state and data
105 static Namelist StateNL; // state vector namelist
106 static Vector<double> State; // state vector
107 static Vector<double> dX; // update to state vector
108 static Matrix<double> Cov; // covariance matrix
109 static Namelist DataNL; // data vector namelist
110 static Vector<double> Data; // data vector
111 static Matrix<double> MeasCov; // measurement covariance matrix
112 static Matrix<double> Partials; // partials matrix
113 static bool Biasfix; // if true, fix estimated biases and solve for
114 // position states only -- NB used widely!
115 static SRIFilter srif; // square root information filter for least squares
116 static double small,big; // condition number in inversion = big/small
117 static int NEp,nDD; // counters used in LS problem
118 static int Mmax; // largest M (data size) encountered
119 static int NState; // true length of the state vector
120 static Vector<double> BiasState; // save the solution for biases, before bias fixing
121 static Matrix<double> BiasCov; // save covariance for biases, before bias fixing
122 static Vector<double> NominalState;// save the nominal state to output with solution
123
124 //------------------------------------------------------------------------------------
125 // currently the estimation problem is designed like this:
126 // start with state of length np
127 // loop over data epochs
128 // fill data vector for this epoch, length nd
129 // fill measurement covariance matrix, nd x nd
130 // compute partials and nominal data vector, P(nd x np), f(nd)
131 // update srif with P(nd x np), data - f (nd), mc(nd x nd)
132 // end loop over data epochs
133 // invert to get solution
134 //
135 // inupt batch size : number of epochs / batch (nepb)
136 //
137 // start with state of length np, nepb
138 // loop over data epochs
139 // fill a data vector for this epoch, length nd
140 // fill a measurement covariance matrix for this epoch, nd x nd
141 // compute a partials and a nominal data vector, P(nd x np), f(nd)
142 // add to current totals: PP = PP && P ff = ff && f
143 // PP = (P1) ff = (f1) MC = (mc1) 0 0
144 // (P2) (f2) 0 (mc2) 0
145 // (P3) (f3) 0 0 (mc3)
146 // (PP grows only in rows, MC grows in rows and columns)
147 // also fill in correlation (off-diagonal) parts of MC
148 // if(its the end || nepb has been reached)
149 // update srif with PP, Data-ff and MC
150 // if(its the end) break
151 // optional - invert to get solution
152 // clear out PP, ff, MC
153 // endif
154 // end loop over data epochs
155 // invert to get solution
Estimation(void)156 int Estimation(void)
157 {
158 try {
159 if(CI.Verbose) oflog << "BEGIN Estimation()"
160 << " at total time " << fixed << setprecision(3)
161 << double(clock()-totaltime)/double(CLOCKS_PER_SEC) << " seconds."
162 << endl;
163 if(CI.noEstimate) {
164 oflog << "Option --noEstimate was chosen .. terminate.\n";
165 return 0;
166 }
167 if(CI.Screen) cout << "BEGIN Estimation..." << endl;
168
169 bool final=false;
170 int iret,n,curr;
171 Vector<double> NomData,RHS;
172
173 // iterative loop for linearized least squares estimation
174 for(n=0; ; n++) {
175
176 if(CI.Verbose) oflog << "BEGIN LLS Iteration #" << n+1
177 << " at total time " << fixed << setprecision(3)
178 << double(clock()-totaltime)/double(CLOCKS_PER_SEC) << " seconds."
179 << "------------------------------------------------------------------\n";
180 if(CI.Screen) cout << "BEGIN LLS Iteration #" << n+1
181 << "------------------------------------------------------------------\n";
182
183 // edit DD data
184 if((iret = EditDDdata(n))) break;
185
186 // modify state - e.g. fix biases:
187 // if user has chosen to fix biases, Biasfix is set true on last iteration
188 if((iret = ModifyState(n))) break;
189
190 //
191 if((iret = InitializeEstimator())) break;
192
193 //
194 if((iret = aPrioriConstraints())) break;
195
196 // ------------------ loop over epochs in the DD buffers
197 // build the data vector and Namelist
198 // build the measurement covariance matrix
199 // update the SRI filter
200 curr = -1; // current value of count
201 NEp = nDD = 0;
202 while(1) {
203 curr++;
204 if(curr > maxCount) break;
205
206 // SolutionEpoch is needed by EvaluateLSEquation, and is used in output
207 SolutionEpoch = FirstEpoch + curr*CI.DataInterval;
208
209 // get the data and the data namelist
210 M = FillDataVector(curr);
211 // no data -- but don't assume this implies the last epoch
212 if(M == 0) continue;
213 nDD += M;
214
215 // compute the measurement covariance matrix
216 BuildStochasticModel(curr,DataNL,MeasCov);
217
218 // get nominal data = NomData(nominal state) and partials
219 // NB position components of state not used in here..
220 EvaluateLSEquation(curr,State,NomData,Partials);
221
222 if(CI.Debug)
223 oflog << "EvaluateLSEquation returns vector\n" << fixed
224 << setw(8) << setprecision(3) << NomData
225 << "\n diff with data " << setw(8) << setprecision(3) << (Data-NomData)
226 << "\n partials matrix\n" << setw(8) << setprecision(3) << Partials
227 << "\n State\n" << setw(8) << setprecision(3) << State << endl;
228
229 RHS = Data - NomData; // RHS of linearized LS equation
230
231 // update the SRI filter
232 if((iret = MeasurementUpdate(Partials,RHS,MeasCov))) break;
233
234 NEp++;
235
236 } // end while loop over data epochs
237 if(iret) break;
238
239 if((iret = Solve())) break;
240
241 if((iret = UpdateNominalState())) break;
242
243 // return -1 quit now
244 // 0 go on
245 // 1 reached convergence and don't fix biases
246 // 2 reached last iteration and don't fix biases
247 // 4 1 and/or 2 and fix biases, i.e. fix the biases then quit
248 iret = IterationControl(n+1);
249
250 oflog << endl;
251
252 //if(iret == -1) { // biases have been fixed
253 // iret = 0;
254 // break;
255 //}
256 //else if(iret == 4) // one more, with biases fixed
257 // final = true;
258 //else if(iret) { // quit now
259 // iret = 0;
260 // break;
261 //}
262 if(iret && iret != 4) final = true;
263
264 OutputIterationResults(final);
265
266 if(iret && iret != 4) {
267 iret = 0;
268 break;
269 }
270
271 } // end iterative loop
272
273 // iret is -2 (singular) or 0
274
275 OutputFinalResults(iret);
276
277 return iret;
278 }
279 catch(Exception& e) { GPSTK_RETHROW(e); }
280 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
281 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
282 } // end Estimation()
283
284 //------------------------------------------------------------------------------------
285 // called by Configure(3)
ConfigureEstimation(void)286 int ConfigureEstimation(void)
287 {
288 try {
289 if(CI.Verbose) oflog << "BEGIN ConfigureEstimation()"
290 << " at total time " << fixed << setprecision(3)
291 << double(clock()-totaltime)/double(CLOCKS_PER_SEC) << " seconds."
292 << endl;
293
294 // find the mean time, get Earth orientation parameters
295 MedianEpoch = FirstEpoch;
296 MedianEpoch += (LastEpoch-FirstEpoch)/2.;
297 double mjd(static_cast<MJD>(MedianEpoch).mjd);
298 eorient = EOPList.getEOP(mjd,IERSConvention::IERS2010);
299 if(CI.Verbose) {
300 oflog << "Earth orientation parameters at median time " << MedianEpoch << " :"
301 << endl << " xp, yp, UT1mUTC*Wearth (all radians) =" << fixed
302 << " " << setprecision(9) << eorient.xp*DEG_TO_RAD/3600.0
303 << ", " << setprecision(9) << eorient.yp*DEG_TO_RAD/3600.0
304 << ", " << setprecision(9) << eorient.UT1mUTC * 7.2921151467e-5 << endl;
305 }
306
307 // define the initial State vector
308 DefineStateVector();
309
310 // initial value
311 Biasfix = false;
312
313 return 0;
314 }
315 catch(Exception& e) { GPSTK_RETHROW(e); }
316 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
317 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
318 }
319
320 //------------------------------------------------------------------------------------
321 // called by ConfigureEstimation()
DefineStateVector(void)322 void DefineStateVector(void)
323 {
324 try {
325 // set up the names of the state vector
326 // set up the initial value of the nominal state
327 // State = offset from nominal position, stored in Stations[].pos
328 // plus offset from nominal biases
329 // NB biases MUST be last, after all other states. This b/c inside
330 // LSIterationLoop(), dX will be State - bias states when Biasfix == true
331
332 int i;
333
334 // add position states for all the non-fixed stations
335 // add residual zenith delay states (per site)
336 map<string,Station>::const_iterator it;
337 for(it=Stations.begin(); it != Stations.end(); it++) {
338 if(!(it->second.fixed)) {
339 StateNL += it->first + string("-X");
340 StateNL += it->first + string("-Y");
341 StateNL += it->first + string("-Z");
342 }
343 if(CI.NRZDintervals > 0) {
344 for(i=0; i<CI.NRZDintervals; i++) {
345 StateNL += it->first + string("-RZD") + asString(i);
346 }
347 }
348 }
349
350 // add bias states
351 map<DDid,DDData>::iterator jt;
352 for(jt=DDDataMap.begin(); jt != DDDataMap.end(); jt++) {
353 // += adds it only if it is unique..
354 StateNL += ComposeName(jt->first);
355 }
356
357 // temp - sanity check
358 //for(int i=0; i<StateNL.size(); i++) {
359 // string site1,site2;
360 // GSatID sat1,sat2;
361 // DecomposeName(StateNL.getName(i), site1, site2, sat1, sat2);
362 // oflog << "State name (" << setw(2) << i << ") decomposes as "
363 // << site1 << " " << site2 << " " << sat1 << " " << sat2;
364
365 // // interpret it
366 // oflog << " [ " << site1;
367 // if(site2 == string("X") || site2 == string("Y") || site2 == string("Z")) {
368 // oflog << " : " << site2 << "-component position";
369 // }
370 // else if(site2.substr(0,3) == "RZD") {
371 // oflog << " : trop delay #" << site2.substr(3,site2.size()-3);
372 // }
373 // else if(Stations.find(site2) != Stations.end() &&
374 // sat1.id != -1 &&
375 // sat2.id != -1) {
376 // oflog << " " << site2 << " " << sat1 << " " << sat2 << " : bias";
377 // }
378 // else
379 // oflog << " : unknown!";
380
381 // oflog << " ]" << endl;
382 //}
383
384 // dimensions
385 // state N, data M, NState=N but if biases are fixed N=non-bias states only
386 // State and StateNL always has length NState
387 // actual state may shrink to N when biases fixed,
388 // but then LSIterationLoop() uses temporaries
389 NState = StateNL.size();
390 State = Vector<double>(NState,0.0);
391 Mmax = DDDataMap.size(); // the largest M (Data.size()) could be
392
393 }
394 catch(Exception& e) { GPSTK_RETHROW(e); }
395 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
396 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
397 }
398
399 //------------------------------------------------------------------------------------
400 //------------------------------------------------------------------------------------
401 // called by Estimation() - inside the iteration loop
402 // currently, n is not used...
403 // currently does nothing but print stats on the residuals
EditDDdata(int n)404 int EditDDdata(int n)
405 {
406 try {
407 int k;
408 size_t i;
409 double res,median,mad,mest;
410 map<DDid,DDData>::iterator it;
411
412 oflog << " Estimation data summary "
413 << "N M-est MAD Ave Std SigYX Slop_um SigSl_um" << endl;
414
415 // loop over the data
416 for(k=1, it = DDDataMap.begin(); it != DDDataMap.end(); it++) {
417 vector<double> ddres,weights;
418 TwoSampleStats<double> tsstats;
419
420 for(i=0; i<it->second.count.size(); i++) {
421 res = (CI.Frequency == 1 ? it->second.DDL1[i] - it->second.DDER[i] :
422 (CI.Frequency == 2 ? it->second.DDL2[i] - it->second.DDER[i] :
423 if1p*it->second.DDL1[i]+if2p*it->second.DDL2[i]
424 - it->second.DDER[i]));
425 tsstats.Add(it->second.count[i],res);
426 ddres.push_back(res);
427 }
428
429 weights.resize(ddres.size());
430 mad = Robust::MedianAbsoluteDeviation(&ddres[0], ddres.size(), median);
431 mest = Robust::MEstimate(&ddres[0], ddres.size(), median, mad, &weights[0]);
432
433 // output
434 oflog << "EDS " << setw(2) << k << " " << it->first
435 << " " << setw(5) << it->second.count.size()
436 << fixed << setprecision(3)
437 << " " << setw(7) << mest
438 << " " << setw(7) << mad
439 << " " << setw(7) << tsstats.AverageY()
440 << " " << setw(7) << tsstats.StdDevY()
441 << " " << setw(7) << tsstats.SigmaYX()
442 << " " << setw(7) << tsstats.Slope()*1000000.0
443 << " " << setw(7) << tsstats.SigmaSlope()*1000000.0
444 << " " << setw(7) << tsstats.Slope()*1000.0*it->second.count.size()
445 << endl;
446
447 k++;
448 }
449
450 return 0;
451 }
452 catch(Exception& e) { GPSTK_RETHROW(e); }
453 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
454 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
455 }
456
457 //------------------------------------------------------------------------------------
458 // called by Estimation() - inside the iteration loop
ModifyState(int niter)459 int ModifyState(int niter)
460 {
461 try {
462 int j,k;
463 size_t i;
464
465 // set the State elements to zero for next iteration
466 map<string,Station>::const_iterator it;
467 for(it=Stations.begin(); it != Stations.end(); it++) {
468
469 // ignore fixed sites
470 if(it->second.fixed) continue;
471
472 // find the position states
473 i = StateNL.index(it->first+string("-X"));
474 j = StateNL.index(it->first+string("-Y"));
475 k = StateNL.index(it->first+string("-Z"));
476 if(i == -1 || j == -1 || k == -1) { // FIXME - i is unsigned!!
477 Exception e("Position states confused: unable to find for " + it->first);
478 GPSTK_THROW(e);
479 }
480
481 State(i) = State(j) = State(k) = 0.0;
482 }
483
484 // ----------------- fix biases?
485 if(Biasfix) {
486 if(CI.Verbose) oflog << "Fix the biases:\n";
487 // State must have the (fixed) biases still in it
488 for(i=0; i<State.size(); i++) {
489 string site1,site2;
490 GSatID sat1,sat2;
491 DecomposeName(StateNL.getName(i), site1, site2, sat1, sat2);
492 if(site2 == string("X") || site2 == string("Y") || site2 == string("Z"))
493 continue;
494 if(site2 == string("rzd"))
495 continue;
496 if(Stations.find(site2) == Stations.end())
497 continue;
498 if(sat1.id == -1 || sat2.id == -2)
499 continue;
500
501 long bias=long(State[i]/wave + (State[i]/wave > 0 ? 0.5 : -0.5));
502 if(CI.Verbose) oflog << " fix " << StateNL.getName(i)
503 << " to " << bias << " cycles" << endl;
504 State(i) = wave*double(bias);
505 }
506 }
507
508 return 0;
509 }
510 catch(Exception& e) { GPSTK_RETHROW(e); }
511 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
512 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
513 }
514
515 //------------------------------------------------------------------------------------
516 // called by Estimation() - inside the iteration loop
517 // actually fixes the biases
InitializeEstimator(void)518 int InitializeEstimator(void)
519 {
520 try {
521 int i;
522 Namelist NL;
523
524 // ----------------- initialize this iteration
525 // determine length of state, reset the LS
526 // Use N and NL rather than NState and StateNL
527 N = NState;
528 NL = StateNL;
529 if(Biasfix) {
530 // State will still be full length = NState
531 // StateNL will also stay full length, but N and NL will not
532 NL.clear();
533 for(N=0,i=0; i<NState; i++) {
534 string site1,site2;
535 GSatID sat1,sat2;
536 DecomposeName(StateNL.getName(i), site1, site2, sat1, sat2);
537 if(Stations.find(site2) != Stations.end() &&
538 sat1.id != -1 &&
539 sat2.id != -1)
540 break; // quit when first bias state found
541 else { // not a bias state
542 NL += StateNL.getName(i);
543 N++;
544 }
545 }
546 oflog << "Fix biases on this iteration (new State dimension is "
547 << N << ")" << endl;
548 if(CI.Screen) cout << "Fix biases on this iteration (new State dimension is "
549 << N << ")" << endl;
550 }
551 dX.resize(N);
552 srif = SRIFilter(NL);
553
554 // save the nominal state for output with Solution (OutputIterationResults)
555 NominalState = State;
556
557 // dump the nominal state (including biases, even if fixed)
558 //if(CI.Verbose) {
559 // LabeledVector LabSt(StateNL,State);
560 // LabSt.setw(20).setprecision(6);
561 // oflog << "Nominal State :\n" << LabSt << endl;
562 //}
563
564 return 0;
565 }
566 catch(Exception& e) { GPSTK_RETHROW(e); }
567 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
568 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
569 }
570
571 //------------------------------------------------------------------------------------
572 // called by Estimation() - inside the iteration loop
aPrioriConstraints(void)573 int aPrioriConstraints(void)
574 {
575 try {
576 // add initial constraints
577 Matrix<double> apCov(N,N,0.0);
578 Vector<double> apState(N,0.0); // most states have apriori value = 0
579
580 int i,j,k;
581 size_t n;
582 double ss;
583 Position BL;
584 map<string,Station>::const_iterator it;
585
586 // set apCov = unity
587 //ident(apCov);
588
589 // loop over baselines - to get the position constraints
590 for(n=0; n<Baselines.size(); n++) {
591 string one=word(Baselines[n],0,'-');
592 string two=word(Baselines[n],1,'-');
593 BL = Stations[one].pos - Stations[two].pos;
594
595 // find the position states
596 i = StateNL.index(two+string("-X"));
597 j = StateNL.index(two+string("-Y"));
598 k = StateNL.index(two+string("-Z"));
599 // you may have a baseline where both sites are fixed.
600 if(i == -1 || j == -1 || k == -1) continue;
601
602 if(Biasfix) { // 10ppm of baseline
603 ss = CI.TightConstraint * fabs(BL.X());
604 apCov(i,i) = (ss*ss);
605 ss = CI.TightConstraint * fabs(BL.Y());
606 apCov(j,j) = (ss*ss);
607 ss = CI.TightConstraint * fabs(BL.Z());
608 apCov(k,k) = (ss*ss);
609 // 1 mm v2.6
610 //ss = 1.e-3 ;
611 //apCov(i,i) = (ss*ss);
612 //ss = 1.e-3 ;
613 //apCov(j,j) = (ss*ss);
614 //ss = 1.e-3 ;
615 //apCov(k,k) = (ss*ss);
616 }
617 else { // loose on position
618 ss = CI.LooseConstraint * fabs(BL.X());
619 apCov(i,i) = (ss*ss);
620 ss = CI.LooseConstraint * fabs(BL.Y());
621 apCov(j,j) = (ss*ss);
622 ss = CI.LooseConstraint * fabs(BL.Z());
623 apCov(k,k) = (ss*ss);
624 }
625
626 if(CI.Verbose) {
627 // assume i,j,k are in order:
628 MatrixSlice<double> Rslice(apCov,i,i,3,3);
629 Matrix<double> R(Rslice);
630 Namelist NL;
631 NL += StateNL.getName(i);
632 NL += StateNL.getName(j);
633 NL += StateNL.getName(k);
634 LabeledMatrix Lapc(NL,R);
635 Lapc.setw(20).setprecision(3).scientific();
636 Lapc.message("a priori covariance");
637 oflog << Lapc << endl;
638 }
639 }
640
641 // constrain the residual trop delay
642 if(CI.NRZDintervals > 0) {
643 // RZD in different intervals correlated; first order Gauss-Markov
644 // dt = time between intervals in hours; these unused if N==1
645 double dt = (LastEpoch-FirstEpoch)/(3600.*CI.NRZDintervals);
646 double exn,ex = exp(-dt/CI.RZDtimeconst);
647
648 // do for each site
649 for(it=Stations.begin(); it != Stations.end(); it++) {
650
651 // find indexes in state vector of all RZD states for this site
652 string stname;
653 vector<int> indexes;
654 for(int ii=0; ii<CI.NRZDintervals; ii++) {
655 stname = it->first + string("-RZD") + asString(ii);
656 i = StateNL.index(stname);
657 if(i == -1) {
658 Exception e("RZD states confused: unable to find state " + stname);
659 GPSTK_THROW(e);
660 }
661 if(CI.Debug) oflog << "RZD state " << stname << " = index " << i << endl;
662 indexes.push_back(i);
663 }
664
665 // fill the matrix
666 for(n=0; n<indexes.size(); n++) {
667 // diagonal element
668 i = indexes[n];
669 apCov(i,i) = CI.RZDsigma * CI.RZDsigma;
670 // off-diagonal elements: rows up and cols to the left
671 exn = ex;
672 for(k=n-1; k>=0; k--) {
673 j = indexes[k];
674 apCov(j,i) = apCov(i,j) = CI.RZDsigma * CI.RZDsigma * exn;
675 exn *= ex;
676 }
677 } // end loop over diagonal matrix elements for this site
678
679 // dump
680 if(CI.Verbose) {
681 if(CI.NRZDintervals > 1) {
682 // assume indexes are in order:
683 MatrixSlice<double> Rslice(apCov,indexes[0],indexes[0],
684 CI.NRZDintervals,CI.NRZDintervals);
685 Matrix<double> R(Rslice);
686 Namelist NL;
687 for(n=0; n<indexes.size(); n++) NL += StateNL.getName(indexes[n]);
688 LabeledMatrix Lapc(NL,R);
689 Lapc.setw(20).setprecision(3).scientific();
690 Lapc.message("a priori covariance");
691 oflog << Lapc << endl;
692 }
693 else
694 oflog << "a priori covariance for RZD at " << it->first
695 << ": " << setprecision(3) << scientific << CI.RZDsigma*CI.RZDsigma
696 << endl;
697 }
698
699 } // end loop over sites
700
701 } // end if there are RZD states..
702
703 // TD need to constrain biases ... what is reasonable?
704 if(!Biasfix) {
705 ss = 0.25 * wave;
706 for(n=0; n<StateNL.size(); n++) {
707 string site1,site2;
708 GSatID sat1,sat2;
709 DecomposeName(StateNL.getName(n), site1, site2, sat1, sat2);
710 if(site2 == string("X") || site2 == string("Y") || site2 == string("Z")) {
711 continue; // oflog << " : " << site2 << "-component position";
712 }
713 else if(site2.substr(0,3) == "RZD") {
714 continue; // oflog << " : trop #" << site2.substr(3,site2.size()-3);
715 }
716 else if(Stations.find(site2) != Stations.end() &&
717 sat1.id != -1 &&
718 sat2.id != -1) {
719 // bias oflog << " " << site2 << " " << sat1 << " " << sat2 << " : bias";
720 apCov(n,n) = ss*ss;
721 }
722 else
723 continue; // oflog << " : unknown!";
724 }
725 oflog << "a priori covariance for biases : " << setprecision(3)
726 << scientific << ss*ss << endl;
727 }
728
729 // dump the whole matrix
730 //if(CI.Verbose) {
731 // LabeledMatrix Lapc(StateNL,apCov);
732 // Lapc.setw(20).setprecision(3).scientific();
733 // Lapc.message("a priori covariance");
734 // oflog << Lapc << endl;
735 //}
736
737 // add it to srif
738 srif.addAPriori(apCov,apState);
739
740 return 0;
741 }
742 catch(Exception& e) { GPSTK_RETHROW(e); }
743 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
744 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
745 }
746
747 //------------------------------------------------------------------------------------
748 // called by Estimation() - inside the data loop, inside the iteration loop
FillDataVector(int count)749 int FillDataVector(int count)
750 {
751 try {
752 int i,j;
753 string lab;
754
755 Data = Vector<double>(Mmax,0.0);
756 DataNL.clear();
757 // loop over the data
758 map<DDid,DDData>::iterator it;
759 for(i=0,it = DDDataMap.begin(); it != DDDataMap.end(); it++) {
760 j = index(it->second.count,count);
761 if(j == -1) continue;
762 if(CI.Frequency == 1) Data(i) = it->second.DDL1[j];
763 if(CI.Frequency == 2) Data(i) = it->second.DDL2[j];
764 if(CI.Frequency == 3) // ionosphere-free phase
765 Data(i) = if1p * it->second.DDL1[j] + if2p * it->second.DDL2[j];
766 lab = ComposeName(it->first);
767 DataNL += lab;
768 i++;
769 }
770
771 if(i > 0) {
772 Data.resize(i);
773 if(CI.Debug) {
774 LabeledVector LD(DataNL,Data);
775 LD.setw(20).setprecision(6);
776 oflog << "At count " << count
777 << " found time " << printTime(SolutionEpoch,"%F %10.3g")
778 << " and Data\n" << LD << endl;
779 }
780 }
781
782 return i;
783 }
784 catch(Exception& e) { GPSTK_RETHROW(e); }
785 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
786 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
787 }
788
789 //------------------------------------------------------------------------------------
790 // called by Estimation() - inside the data loop, inside the iteration loop
791 // Given a nominal state vector X, compute the function f(X) and the partials matrix
792 // P at X.
793 // NB X is not used here ... except that State is used for biases
EvaluateLSEquation(int count,Vector<double> & X,Vector<double> & f,Matrix<double> & P)794 void EvaluateLSEquation(int count, // count of current epoch
795 Vector<double>& X, // nominal state (input)
796 Vector<double>& f, // function f(X) at count (output)
797 Matrix<double>& P) // partials at X at count (output)
798 {
799 try {
800 int i,j,k,n,ntrop;
801 size_t m;
802 double ER,trop,mapf;
803 string site1,site2;
804 GSatID sat1,sat2;
805 CorrectedEphemerisRange CER;
806 Position SatR;
807
808 // Station.pos has been defined outside this routine in UpdateNominalState()
809
810 // find the trop estimation interval for this epoch
811 if(CI.NRZDintervals > 0) {
812 ntrop = int( (SolutionEpoch-FirstEpoch) /
813 (((LastEpoch-FirstEpoch)+CI.DataInterval)/CI.NRZDintervals) );
814 }
815
816 // loop over the data vector, computing f(X) and filling P
817 f = Vector<double>(M,0.0);
818 P = Matrix<double>(M,N,0.0);
819 for(m=0; m<DataNL.size(); m++) {
820
821 // break name into its parts
822 DecomposeName(DataNL.getName(m), site1, site2, sat1, sat2);
823
824 Station& st1=Stations[site1];
825 Station& st2=Stations[site2];
826
827 // -----------------------------------------------------------
828 // site1 ----------------------------------------------------
829 if(!st1.fixed) {
830 i = StateNL.index(site1 + string("-X"));
831 j = StateNL.index(site1 + string("-Y"));
832 k = StateNL.index(site1 + string("-Z"));
833 if(i == -1 || j == -1 || k == -1) {
834 Exception e("Position states confused: unable to find for " + site1);
835 GPSTK_THROW(e);
836 }
837 }
838 // sat 1 -----------------------------------------------------
839 // should you use CER.rawrange here?
840 ER = CER.ComputeAtReceiveTime(SolutionEpoch,st1.pos,sat1,*pEph);
841 SatR.setECEF(CER.svPosVel.x[0],CER.svPosVel.x[1],CER.svPosVel.x[2]);
842 trop = st1.pTropModel->correction(st1.pos,SatR,SolutionEpoch);
843 f(m) += ER+trop;
844 if(!st1.fixed) {
845 P(m,i) += CER.cosines[0];
846 P(m,j) += CER.cosines[1];
847 P(m,k) += CER.cosines[2];
848 }
849 // trop rzd .. depends on site, sat and trop model
850 if(CI.NRZDintervals > 0) {
851 n = StateNL.index(site1 + string("-RZD") + asString(ntrop));
852 if(n == -1) {
853 Exception e("RZD states confused: unable to find state " +
854 site1 + string("-RZD") + asString(ntrop));
855 GPSTK_THROW(e);
856 }
857 mapf = st1.pTropModel->wet_mapping_function(CER.elevation);
858 P(m,n) += mapf;
859 f(m) += mapf * State(n);
860 }
861
862 // sat 2 -----------------------------------------------------
863 ER = CER.ComputeAtReceiveTime(SolutionEpoch,st1.pos,sat2,*pEph);
864 SatR.setECEF(CER.svPosVel.x[0],CER.svPosVel.x[1],CER.svPosVel.x[2]);
865 trop = st1.pTropModel->correction(st1.pos,SatR,SolutionEpoch);
866 f(m) -= ER+trop;
867 if(!st1.fixed) {
868 P(m,i) -= CER.cosines[0];
869 P(m,j) -= CER.cosines[1];
870 P(m,k) -= CER.cosines[2];
871 }
872 // trop rzd .. depends on site, sat and trop model
873 if(CI.NRZDintervals > 0) {
874 mapf = st1.pTropModel->wet_mapping_function(CER.elevation);
875 P(m,n) += mapf;
876 f(m) += mapf * State(n);
877 }
878
879 // -----------------------------------------------------------
880 // site 2 ----------------------------------------------------
881 if(!st2.fixed) {
882 i = StateNL.index(site2 + string("-X"));
883 j = StateNL.index(site2 + string("-Y"));
884 k = StateNL.index(site2 + string("-Z"));
885 if(i == -1 || j == -1 || k == -1) {
886 Exception e("Position states confused: unable to find for " + site2);
887 GPSTK_THROW(e);
888 }
889 }
890 // sat 1 -----------------------------------------------------
891 ER = CER.ComputeAtReceiveTime(SolutionEpoch,st2.pos,sat1,*pEph);
892 SatR.setECEF(CER.svPosVel.x[0],CER.svPosVel.x[1],CER.svPosVel.x[2]);
893 trop = st2.pTropModel->correction(st2.pos,SatR,SolutionEpoch);
894 f(m) -= ER+trop;
895 if(!st2.fixed) {
896 P(m,i) -= CER.cosines[0];
897 P(m,j) -= CER.cosines[1];
898 P(m,k) -= CER.cosines[2];
899 }
900 // trop rzd .. depends on site, sat and trop model
901 if(CI.NRZDintervals > 0) {
902 n = StateNL.index(site2 + string("-RZD") + asString(ntrop));
903 if(n == -1) {
904 Exception e("RZD states confused: unable to find state " +
905 site2 + string("-RZD") + asString(ntrop));
906 GPSTK_THROW(e);
907 }
908 mapf = st2.pTropModel->wet_mapping_function(CER.elevation);
909 P(m,n) += mapf;
910 f(m) += mapf * State(n);
911 }
912
913 // sat 2 -----------------------------------------------------
914 ER = CER.ComputeAtReceiveTime(SolutionEpoch,st2.pos,sat2,*pEph);
915 SatR.setECEF(CER.svPosVel.x[0],CER.svPosVel.x[1],CER.svPosVel.x[2]);
916 trop = st2.pTropModel->correction(st2.pos,SatR,SolutionEpoch);
917 f(m) += ER+trop;
918 if(!st2.fixed) {
919 P(m,i) += CER.cosines[0];
920 P(m,j) += CER.cosines[1];
921 P(m,k) += CER.cosines[2];
922 }
923 // trop rzd .. depends on site, sat and trop model
924 if(CI.NRZDintervals > 0) {
925 mapf = st2.pTropModel->wet_mapping_function(CER.elevation);
926 P(m,n) += mapf;
927 f(m) += mapf * State(n);
928 }
929
930 // -----------------------------------------------------------
931 // bias ------------------------------------------------------
932 j = 1;
933 i = StateNL.index(DataNL.getName(m));
934 if(i == -1) {
935 // but what if the bias is A-B_s-r and the data B-A_r-s?
936 // (Decompose was called at top of loop)
937 j = -1;
938 i = StateNL.index(ComposeName(site1,site2,sat2,sat1)); // most likely
939 if(i == -1) {
940 i = StateNL.index(ComposeName(site2,site1,sat1,sat2));
941 if(i == -1) {
942 j = 1;
943 i = StateNL.index(ComposeName(site2,site1,sat2,sat1));
944 }
945 }
946 }
947 f(m) += j * State(i);
948 if(!Biasfix)
949 P(m,i) = j;
950
951 } // end loop over data
952
953 f.resize(M);
954 P.resize(M,N);
955
956 }
957 catch(Exception& e) { GPSTK_RETHROW(e); }
958 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
959 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
960 }
961
962 //------------------------------------------------------------------------------------
963 // called by Estimation() - inside the data loop, inside the iteration loop
MeasurementUpdate(Matrix<double> & P,Vector<double> & f,Matrix<double> & MC)964 int MeasurementUpdate(Matrix<double>& P, Vector<double>& f, Matrix<double>& MC)
965 {
966 try {
967
968 srif.measurementUpdate(P,f,MC);
969
970 return 0;
971 }
972 catch(Exception& e) { GPSTK_RETHROW(e); }
973 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
974 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
975 }
976
977 //------------------------------------------------------------------------------------
978 // called by Estimation() - inside the iteration loop
Solve(void)979 int Solve(void)
980 {
981 try {
982
983 try {
984 srif.getStateAndCovariance(dX,Cov,&small,&big);
985 }
986 catch(SingularMatrixException& sme) {
987 oflog << "Problem is singular " << endl;
988 return -2; // TD handle singular problems in Solve()
989 }
990
991 return 0;
992 }
993 catch(Exception& e) { GPSTK_RETHROW(e); }
994 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
995 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
996 }
997
998 //------------------------------------------------------------------------------------
999 // called by Estimation() - inside the iteration loop
UpdateNominalState(void)1000 int UpdateNominalState(void)
1001 {
1002 try {
1003 int i,j,k;
1004
1005 if(Biasfix) {
1006 // NB when Biasfix, State has dimension NState buf dX has dimension N>NState
1007 // EvaluateLSEquation uses State bias elements even when Biasfix
1008 for(i=0; i<N; i++) {
1009 State[i] += dX[i];
1010 }
1011 }
1012 else { // regular update, save for when Biasfix is set
1013 State += dX;
1014 BiasState = State;
1015 BiasCov = Cov;
1016 }
1017 // redefine the nominal position
1018 // set all floating position states to zero
1019 map<string,Station>::const_iterator it;
1020 for(it=Stations.begin(); it != Stations.end(); it++) {
1021 if(it->second.fixed) // ignore fixed sites
1022 continue;
1023
1024 // find the position states
1025 i = StateNL.index(it->first+string("-X"));
1026 j = StateNL.index(it->first+string("-Y"));
1027 k = StateNL.index(it->first+string("-Z"));
1028 if(i == -1 || j == -1 || k == -1) {
1029 Exception e("Position states confused: unable to find for " + it->first);
1030 GPSTK_THROW(e);
1031 }
1032
1033 // update the nominal position in Stations[]
1034 Stations[it->first].pos.setECEF(
1035 Stations[it->first].pos.X()+dX(i),
1036 Stations[it->first].pos.Y()+dX(j),
1037 Stations[it->first].pos.Z()+dX(k));
1038 }
1039
1040 return 0;
1041 }
1042 catch(Exception& e) { GPSTK_RETHROW(e); }
1043 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1044 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1045 }
1046
1047 //------------------------------------------------------------------------------------
1048 // called by Estimation() - inside the iteration loop
OutputIterationResults(bool final)1049 void OutputIterationResults(bool final)
1050 {
1051 try {
1052 int j,N=dX.size();
1053 size_t i;
1054 format f166(16,6),f206(20,6),f82s(8,2,2);
1055
1056 oflog << " State label"
1057 << " Nominal State"
1058 << " State Update"
1059 << " New Solution"
1060 << " Sigma"
1061 << endl;
1062 for(j=0; j<N; j++) {
1063 oflog << setw(20) << StateNL.getName(j)
1064 << " " << f166 << NominalState[j]
1065 << " " << f166 << dX[j]
1066 << " " << f166 << State[j]
1067 << " " << f166 << SQRT(Cov(j,j))
1068 << endl;
1069 }
1070
1071 //LabeledVector LSol(StateNL,dX);
1072 //LSol.setw(20).setprecision(6);
1073 //oflog << "Solution\n" << LSol << endl;
1074
1075 ////LabeledMatrix LCov(StateNL,Cov);
1076 //Vector<double> Sig(N);
1077 //for(i=0; i<N; i++) Sig(i)=SQRT(Cov(i,i));
1078 //LabeledVector LCov(StateNL,Sig);
1079 //LCov.setw(20).setprecision(6);
1080 ////oflog << "Covariance\n" << LCov << endl;
1081 //oflog << "Sigma\n" << LCov << endl;
1082
1083 // output baselines
1084 Position BL;
1085 for(i=0; i<CI.OutputBaselines.size(); i++) {
1086 // dependent on the order given in ComputeSingleDifferences()
1087 string one=word(CI.OutputBaselines[i],0,'-');
1088 string two=word(CI.OutputBaselines[i],1,'-');
1089 BL = Stations[one].pos - Stations[two].pos;
1090 oflog << "Baseline " << CI.OutputBaselines[i]
1091 << " " << BL.printf("%16.6x %16.6y %16.6z")
1092 << " " << f166 << BL.getRadius() << endl;
1093 if(CI.Screen) cout << "Baseline " << CI.OutputBaselines[i]
1094 << " " << BL.printf("%16.6x %16.6y %16.6z")
1095 << " " << f166 << BL.getRadius() << endl;
1096 // offset - if one was input
1097 if(CI.OutputBaselineOffsets[i].mag() >= 0.01) {
1098 oflog << " Offset " << CI.OutputBaselines[i]
1099 << " " << f166 << BL.X() - CI.OutputBaselineOffsets[i][0]
1100 << " " << f166 << BL.Y() - CI.OutputBaselineOffsets[i][1]
1101 << " " << f166 << BL.Z() - CI.OutputBaselineOffsets[i][2]
1102 << " " << f166 << BL.getRadius() - CI.OutputBaselineOffsets[i].mag()
1103 << endl;
1104 if(CI.Screen) cout << " Offset " << CI.OutputBaselines[i]
1105 << " " << f166 << BL.X() - CI.OutputBaselineOffsets[i][0]
1106 << " " << f166 << BL.Y() - CI.OutputBaselineOffsets[i][1]
1107 << " " << f166 << BL.Z() - CI.OutputBaselineOffsets[i][2]
1108 << " " << f166 << BL.getRadius() - CI.OutputBaselineOffsets[i].mag()
1109 << endl;
1110 }
1111 }
1112
1113 // compute residuals of fit and output
1114 double rmsrof = RMSResidualOfFit(N,dX,final);
1115 oflog << "RES " << (final ? "final " : "" ) << "total RMS = "
1116 << f82s << rmsrof << endl;
1117
1118 }
1119 catch(Exception& e) { GPSTK_RETHROW(e); }
1120 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1121 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1122 }
1123
1124 //------------------------------------------------------------------------------------
1125 // called by Estimation()
1126 // return -1 quit now
1127 // 0 go on
1128 // 1 reached convergence and don't fix biases
1129 // 2 reached last iteration and don't fix biases
1130 // 4 1 and/or 2 and fix biases, i.e. fix the biases then quit
IterationControl(int iter_n)1131 int IterationControl(int iter_n)
1132 {
1133 try {
1134 int done=0;
1135 double converge;
1136
1137 // has it converged?
1138 converge = norm(dX);
1139 if(converge <= CI.convergence) {
1140 oflog << "DDBase finds convergence: " << iter_n << " iterations"
1141 << ", convergence criterion = " << scientific << setprecision(3)
1142 << converge << " m; (" << CI.convergence << " m)" << endl;
1143 if(CI.Screen)
1144 cout << "DDBase finds convergence: " << iter_n << " iterations"
1145 << ", convergence criterion = " << scientific << setprecision(3)
1146 << converge << " m; (" << CI.convergence << " m)" << endl;
1147 done += 1;
1148 }
1149
1150 // have we reached the last iteration?
1151 if(iter_n == CI.nIter) {
1152 oflog << "DDBase finds last iteration: " << iter_n << " iterations"
1153 << ", convergence criterion = " << scientific << setprecision(3)
1154 << converge << " m; (" << CI.convergence << " m)" << endl;
1155 if(CI.Screen)
1156 cout << "DDBase finds last iteration: " << iter_n << " iterations"
1157 << ", convergence criterion = " << scientific << setprecision(3)
1158 << converge << " m; (" << CI.convergence << " m)" << endl;
1159 done += 2;
1160 }
1161
1162 if(!done && CI.Verbose) {
1163 oflog << "DDBase: " << iter_n << " iterations"
1164 << ", convergence criterion = " << scientific << setprecision(3)
1165 << converge << " m; (" << CI.convergence << " m)" << endl;
1166 if(CI.Screen)
1167 cout << "DDBase: " << iter_n << " iterations"
1168 << ", convergence criterion = " << scientific << setprecision(3)
1169 << converge << " m; (" << CI.convergence << " m)" << endl;
1170 }
1171
1172 // if the previous iteration fixed the biases, we are done no matter what
1173 if(Biasfix) return 5;
1174
1175 if(CI.FixBiases && done) {
1176 Biasfix = true;
1177 return 4; // signals one more iteration
1178 }
1179
1180 return done;
1181 }
1182 catch(Exception& e) { GPSTK_RETHROW(e); }
1183 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1184 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1185 }
1186
1187 //------------------------------------------------------------------------------------
1188 //------------------------------------------------------------------------------------
1189 // Utilities - use consistently throughout! these three routines must change together.
ComposeName(const string & site1,const string & site2,const GSatID & sat1,const GSatID & sat2)1190 string ComposeName(const string& site1,
1191 const string& site2,
1192 const GSatID& sat1,
1193 const GSatID& sat2)
1194 {
1195 try {
1196 return ( site1 + string("-") + site2 + string("_")
1197 + asString(sat1) + string("-") + asString(sat2) );
1198 }
1199 catch(Exception& e) { GPSTK_RETHROW(e); }
1200 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1201 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1202 }
1203 //------------------------------------------------------------------------------------
ComposeName(const DDid & ddid)1204 string ComposeName(const DDid& ddid)
1205 {
1206 try {
1207 if(ddid.ssite > 0) {
1208 if(ddid.ssat > 0)
1209 return ComposeName(ddid.site1,ddid.site2,ddid.sat1,ddid.sat2);
1210 else
1211 return ComposeName(ddid.site1,ddid.site2,ddid.sat2,ddid.sat1);
1212 }
1213 else {
1214 if(ddid.ssat > 0)
1215 return ComposeName(ddid.site2,ddid.site1,ddid.sat1,ddid.sat2);
1216 else
1217 return ComposeName(ddid.site2,ddid.site1,ddid.sat2,ddid.sat1);
1218 }
1219 }
1220 catch(Exception& e) { GPSTK_RETHROW(e); }
1221 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1222 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1223 }
1224 //------------------------------------------------------------------------------------
DecomposeName(const string & label,string & site1,string & site2,GSatID & sat1,GSatID & sat2)1225 void DecomposeName(const string& label,
1226 string& site1,
1227 string& site2,
1228 GSatID& sat1,
1229 GSatID& sat2)
1230 {
1231 try {
1232 string copy=label;
1233 //oflog << "Decompose found " << label << " = ";
1234 site1 = stripFirstWord(copy,'-');
1235 //oflog << site1;
1236 site2 = stripFirstWord(copy,'_');
1237 //oflog << " " << site2;
1238 sat1.fromString(stripFirstWord(copy,'-'));
1239 //oflog << " " << sat1;
1240 sat2.fromString(copy);
1241 //oflog << " " << sat2 << endl;
1242 }
1243 catch(Exception& e) { GPSTK_RETHROW(e); }
1244 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1245 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1246 }
1247
1248 //------------------------------------------------------------------------------------
OutputFinalResults(int iret)1249 void OutputFinalResults(int iret)
1250 {
1251 try {
1252 int j,k,len;
1253 size_t i;
1254 string site1,site2;
1255 GSatID sat1,sat2;
1256 format f133(13,3),f166(16,6);
1257
1258 oflog << "Final Solution:" << endl;
1259
1260 if(iret != -2) {
1261
1262 if(CI.NRZDintervals > 0) {
1263 oflog << "Residual zenith tropospheric delays (m) with sigma" << endl;
1264 for(k=0; k<NState; k++) {
1265 DecomposeName(StateNL.getName(k), site1, site2, sat1, sat2);
1266 if(site2.substr(0,3) != string("RZD")) continue;
1267 oflog << site1 << " : trop delay (m) #" << site2.substr(3,site2.size()-3)
1268 << " " << f133 << State(k)
1269 << " " << f133 << SQRT(Cov(k,k))
1270 << endl;
1271 }
1272 oflog << endl;
1273 }
1274
1275 oflog << "Biases (cycles) with sigma" << endl;
1276 for(k=0; k<NState; k++) {
1277 DecomposeName(StateNL.getName(k), site1, site2, sat1, sat2);
1278 if(site2.size() ==0 || sat1.id == -1 || sat2.id == -1) continue;
1279 oflog << StateNL.getName(k)
1280 << " " << f133 << BiasState(k)/wl1
1281 << " " << f133 << SQRT(BiasCov(k,k))/wl1
1282 << endl;
1283 }
1284 oflog << endl;
1285
1286 // output position and covariance for input to later adjustment
1287 oflog << "Final covariance and position solutions:\n";
1288 for(len=0,j=0; j<NState; j++) {
1289 DecomposeName(StateNL.getName(j), site1, site2, sat1, sat2);
1290 if(site2 == string("X") || site2 == string("Y") || site2 == string("Z")) {
1291 if(len==0) {
1292 len = StateNL.getName(j).size();
1293 oflog << setw(len) << ' ';
1294 if(len < 16) len=16;
1295 }
1296 oflog << setw(len) << StateNL.getName(j);
1297 }
1298 }
1299 oflog << setw(len) << "Position" << endl;
1300 for(k=0; k<NState; k++) {
1301 DecomposeName(StateNL.getName(k), site1, site2, sat1, sat2);
1302 if(site2!=string("X") && site2!=string("Y") && site2!=string("Z"))
1303 continue;
1304 oflog << StateNL.getName(k);
1305 for(j=0; j<NState; j++) {
1306 string site22,site11;
1307 GSatID sat11,sat22;
1308 DecomposeName(StateNL.getName(j), site11, site22, sat11, sat22);
1309 if(site22==string("X") || site22==string("Y") || site22==string("Z"))
1310 oflog << scientific << setw(len) << setprecision(6) << Cov(k,j);
1311 }
1312 if(site2 == string("X")) oflog << fixed << setw(len)
1313 << setprecision(6) << Stations[site1].pos.X();
1314 if(site2 == string("Y")) oflog << fixed << setw(len)
1315 << setprecision(6) << Stations[site1].pos.Y();
1316 if(site2 == string("Z")) oflog << fixed << setw(len)
1317 << setprecision(6) << Stations[site1].pos.Z();
1318 oflog << endl;
1319 }
1320 oflog << endl;
1321
1322 // output position and sigmas for all non-fixed positions
1323 map<string,Station>::const_iterator it;
1324 for(it=Stations.begin(); it != Stations.end(); it++) {
1325 oflog << it->first << ": " << (it->second.fixed ? " Fixed" : "Estimated")
1326 << " Position "
1327 << Stations[it->first].pos.printf("%16.6x %16.6y %16.6z") << endl;
1328 if(!(Stations[it->first].fixed)) {
1329 oflog << it->first << ": Estimated Sigmas";
1330 i = StateNL.index(it->first + string("-X"));
1331 oflog << " " << f166 << SQRT(Cov(i,i));
1332 i = StateNL.index(it->first + string("-Y"));
1333 oflog << " " << f166 << SQRT(Cov(i,i));
1334 i = StateNL.index(it->first + string("-Z"));
1335 oflog << " " << f166 << SQRT(Cov(i,i));
1336 oflog << endl;
1337 }
1338 }
1339
1340 // do for all baselines
1341 for(i=0; i<CI.OutputBaselines.size(); i++) {
1342 string one=word(CI.OutputBaselines[i],0,'-');
1343 string two=word(CI.OutputBaselines[i],1,'-');
1344 Position BL = Stations[one].pos - Stations[two].pos;
1345 oflog << "Final Baseline " << CI.OutputBaselines[i]
1346 << " " << BL.printf("%16.6x %16.6y %16.6z")
1347 << " " << f166 << BL.getRadius() << endl;
1348 if(CI.Screen)
1349 cout << "Final Baseline " << CI.OutputBaselines[i]
1350 << " " << BL.printf("%16.6x %16.6y %16.6z")
1351 << " " << f166 << BL.getRadius() << endl;
1352
1353 // offset - if one was input
1354 if(CI.OutputBaselineOffsets[i].mag() >= 0.01) {
1355 oflog << "Final Offset " << CI.OutputBaselines[i]
1356 << " " << f166 << BL.X() - CI.OutputBaselineOffsets[i][0]
1357 << " " << f166 << BL.Y() - CI.OutputBaselineOffsets[i][1]
1358 << " " << f166 << BL.Z() - CI.OutputBaselineOffsets[i][2]
1359 << " " << f166 << BL.getRadius() - CI.OutputBaselineOffsets[i].mag()
1360 << endl;
1361 if(CI.Screen)
1362 cout << "Final Offset " << CI.OutputBaselines[i]
1363 << " " << f166 << BL.X() - CI.OutputBaselineOffsets[i][0]
1364 << " " << f166 << BL.Y() - CI.OutputBaselineOffsets[i][1]
1365 << " " << f166 << BL.Z() - CI.OutputBaselineOffsets[i][2]
1366 << " " << f166 << BL.getRadius() - CI.OutputBaselineOffsets[i].mag()
1367 << endl;
1368 }
1369 }
1370 }
1371 oflog << "Data Totals: " << NEp << " epochs, " << nDD << " DDs (which is "
1372 << fixed << setprecision(3) << double(nDD)/double(NEp) << " DDs/epoch)"
1373 << " used in estimation." << endl;
1374 if(CI.Screen)
1375 cout << "Data Totals: " << NEp << " epochs, " << nDD << " DDs (which is "
1376 << fixed << setprecision(3) << double(nDD)/double(NEp) << " DDs/epoch) "
1377 << " used in estimation." << endl;
1378 }
1379 catch(Exception& e) { GPSTK_RETHROW(e); }
1380 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1381 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1382 }
1383
1384 //------------------------------------------------------------------------------------
RMSResidualOfFit(int N,Vector<double> & dX,bool final)1385 double RMSResidualOfFit(int N, Vector<double>& dX, bool final)
1386 {
1387 try {
1388 int i,j,nd,cnt;
1389 double rms;
1390 string lab;
1391 Vector<double> f,Res;
1392 Matrix<double> P;
1393 map<DDid,DDData>::iterator it;
1394 format f166(16,6),f133(13,3),f82s(8,2,2);
1395
1396 // open an output file for post fit DD residuals
1397 ofstream ddrofs;
1398 if(final && !CI.OutputDDRFile.empty()) {
1399 ddrofs.open(CI.OutputDDRFile.c_str(),ios::out);
1400 if(ddrofs.is_open()) {
1401 oflog << "Opened file " << CI.OutputDDRFile
1402 << " for post fit residuals output." << endl;
1403 ddrofs << "# " << Title << endl;
1404 ddrofs << "RES site site sat sat week sec_wk count"
1405 << " Data Estimate Residual" << endl;
1406 }
1407 else {
1408 oflog << "Warning - Failed to open DDR output file " << CI.OutputDDRFile
1409 << ". Do not output post fit residuals.\n";
1410 }
1411 }
1412
1413 // go all the way back through the data
1414 nd= 0;
1415 rms = 0.0;
1416 cnt = -1;
1417 while(1) {
1418 cnt++;
1419 if(cnt > maxCount) break;
1420 Data = Vector<double>(Mmax,0.0);
1421 DataNL.clear();
1422 for(i=0,it=DDDataMap.begin(); it != DDDataMap.end(); it++) {
1423 j = index(it->second.count,cnt);
1424 if(j == -1) continue;
1425 if(CI.Frequency == 1) Data(i) = it->second.DDL1[j];
1426 if(CI.Frequency == 2) Data(i) = it->second.DDL2[j];
1427 if(CI.Frequency == 3) // ionosphere-free phase
1428 Data(i) = if1p * it->second.DDL1[j] + if2p * it->second.DDL2[j];
1429 lab = ComposeName(it->first);
1430 DataNL += lab;
1431 i++;
1432 }
1433 if(i==0) continue; // no data -- don't assume this is the end
1434 M = i;
1435 Data.resize(M);
1436
1437 // SolutionEpoch is needed by EvaluateLSEquation
1438 SolutionEpoch = FirstEpoch + cnt*CI.DataInterval;
1439 EvaluateLSEquation(cnt,State,f,P);
1440
1441 Res = Data - f;
1442 if(rms == 0.0) rms = norm(Res);
1443 else rms *= sqrt(1.0+norm(Res)/(rms*rms));
1444 nd += M;
1445
1446 if(final && ddrofs) {
1447 string site1,site2;
1448 GSatID sat1,sat2;
1449 for(i=0; i<M; i++) {
1450 DecomposeName(DataNL.getName(i), site1, site2, sat1, sat2);
1451 ddrofs << "RES " << site1 << " " << site2 << " " << sat1 << " " << sat2
1452 << " " << printTime(SolutionEpoch,"%4F %10.3g")
1453 << " " << setw(5) << cnt
1454 << " " << f166 << Data[i]
1455 << " " << f166 << f[i]
1456 << " " << f166 << Res[i]
1457 << endl;
1458 }
1459 }
1460
1461 } // end loop over data
1462
1463 if(final && ddrofs) ddrofs.close();
1464
1465 rms /= sqrt(double(nd));
1466
1467 return rms;
1468 }
1469 catch(Exception& e) { GPSTK_RETHROW(e); }
1470 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
1471 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
1472 }
1473
1474 //------------------------------------------------------------------------------------
1475 //------------------------------------------------------------------------------------
1476