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