DiscCorr.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk 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 GNSSTk 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 GNSSTk; 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-2022, 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 
46 //------------------------------------------------------------------------------------
47 // system
48 #include <algorithm>
49 #include <deque>
50 #include <iostream>
51 #include <list>
52 #include <sstream>
53 #include <string>
54 #include <vector>
55 // gnsstk
56 #include "GNSSconstants.hpp" // PI,C_MPS,OSC_FREQ_GPS,L1_MULT_GPS,L2_MULT_GPS
57 #include "PolyFit.hpp"
58 #include "RobustStats.hpp"
59 #include "Stats.hpp"
60 #include "StringUtils.hpp"
61 // geomatics
62 #include "DiscCorr.hpp"
63 
64 using namespace std;
65 using namespace gnsstk;
66 using namespace StringUtils;
67 
68 //------------------------------------------------------------------------------------
69 // class GDCconfiguration
70 //------------------------------------------------------------------------------------
71 // class GDCconfiguration: string giving version of gnsstk Discontinuity
72 // Corrector
73 const string GDCconfiguration::GDCVersion = string("6.3 12/15/2015");
74 
75 // class GDCconfiguration: member functions
76 //------------------------------------------------------------------------------------
77 // Set a parameter in the configuration; the input string 'cmd' is of the form
78 // '[--DC]<id><s><value>' : separator s is one of ':=,' and leading --DC is
79 // optional.
80 void GDCconfiguration::setParameter(std::string cmd)
81 {
82  try
83  {
84  if (cmd.empty())
85  {
86  return;
87  }
88  // remove leading --DC
89  while (cmd[0] == '-')
90  {
91  cmd.erase(0, 1);
92  }
93 
94  if (cmd.substr(0, 2) == "DC")
95  {
96  cmd.erase(0, 2);
97  }
98 
99  string label, value;
100  string::size_type pos = cmd.find_first_of(",=:");
101  if (pos == string::npos)
102  {
103  label = cmd;
104  }
105  else
106  {
107  label = cmd.substr(0, pos);
108  value = cmd;
109  value.erase(0, pos + 1);
110  }
111 
112  setParameter(label, asDouble(value));
113  }
114  catch (Exception& e)
115  {
116  GNSSTK_RETHROW(e);
117  }
118  catch (std::exception& e)
119  {
120  Exception E("std except: " + string(e.what()));
121  GNSSTK_THROW(E);
122  }
123  catch (...)
124  {
125  Exception e("Unknown exception");
126  GNSSTK_THROW(e);
127  }
128 }
129 
130 //------------------------------------------------------------------------------------
131 /* Set a parameter in the configuration using the label and the value,
132  for booleans use (T,F)=(non-zero,zero). */
133 void GDCconfiguration::setParameter(const std::string& label, double value)
134 {
135  try
136  {
137  if (CFG.find(label) == CFG.end())
138  {
139  {};
140  }
141  else
142  {
143  // log is not defined yet
144  if (CFG["Debug"] > 0)
145  {
146  *(p_oflog) << "GDCconfiguration::setParameter sets " << label
147  << " to " << value << endl;
148  }
149  CFG[label] = value;
150  }
151  }
152  catch (Exception& e)
153  {
154  GNSSTK_RETHROW(e);
155  }
156  catch (std::exception& e)
157  {
158  Exception E("std except: " + string(e.what()));
159  GNSSTK_THROW(E);
160  }
161  catch (...)
162  {
163  Exception e("Unknown exception");
164  GNSSTK_THROW(e);
165  }
166 }
167 
168 //------------------------------------------------------------------------------------
169 /* Print help page, including descriptions and current values of all
170  the parameters, to the ostream. */
171 void GDCconfiguration::DisplayParameterUsage(ostream& os, bool advanced)
172 {
173  try
174  {
175  os << "GNSSTk Discontinuity Corrector (GDC) v." << GDCVersion
176  << " configuration:"
177  //<< "\n [ pass setParameter() a string '<label><sep><value>';"
178  //<< " <sep> is one of ,=: ]"
179  << endl;
180 
181  map<string, double>::const_iterator it;
182  for (it = CFG.begin(); it != CFG.end(); it++)
183  {
184  if (CFGdescription[it->first][0] == '*') // advanced options
185  {
186  continue;
187  }
188  ostringstream stst;
189  stst << it->first // label
190  << "=" << it->second; // value
191  os << " " << leftJustify(stst.str(), 18) << " : "
192  << CFGdescription[it->first] // description
193  << endl;
194  }
195  if (advanced)
196  {
197  os << " Advanced options:\n";
198  for (it = CFG.begin(); it != CFG.end(); it++)
199  {
200  if (CFGdescription[it->first][0] != '*') // ordinary options
201  {
202  continue;
203  }
204  ostringstream stst;
205  stst << it->first // label
206  << "=" << it->second; // value
207  os << " " << leftJustify(stst.str(), 25) << " : "
208  << CFGdescription[it->first].substr(2) // description
209  << endl;
210  }
211  }
212  }
213  catch (Exception& e)
214  {
215  GNSSTK_RETHROW(e);
216  }
217  catch (std::exception& e)
218  {
219  Exception E("std except: " + string(e.what()));
220  GNSSTK_THROW(E);
221  }
222  catch (...)
223  {
224  Exception e("Unknown exception");
225  GNSSTK_THROW(e);
226  }
227 }
228 
229 //------------------------------------------------------------------------------------
230 #define setcfg(a, b, c) \
231  { \
232  CFG[#a] = b; \
233  CFGdescription[#a] = c; \
234  }
235 // initialize with default values
237 {
238  try
239  {
240  p_oflog = &cout;
241 
242  // bookkeeping
243  setcfg(ResetUnique, 0, "if non-zero, reset the unique number to zero");
244 
245  // use cfg(DT) NOT dt - dt is part of SatPass...
246  setcfg(DT, -1,
247  "nominal timestep of data (seconds) [required - no default!]");
248  setcfg(Debug, 0,
249  "level of diagnostic output to log, from 0(none) to 7(extreme)");
250  setcfg(useCA1, 0, "use L1 C/A code pseudorange (C1) ()");
251  setcfg(useCA2, 0, "use L2 C/A code pseudorange (C2) ()");
252  setcfg(MaxGap, 180,
253  "maximum allowed time gap within a segment (seconds)");
254  setcfg(MinPts, 13, "minimum number of good points in phase segment ()");
255  setcfg(WLSigma, 1.5,
256  "expected WL sigma (WL cycle) [NB = ~0.83*p-range noise(m)]");
257  setcfg(GFVariation, 16, // about 300 5.4-cm wavelengths
258  "expected maximum variation in GF phase in time DT (meters)");
259  // output
260  setcfg(OutputGPSTime, 0,
261  "if 0, output Y,M,D,H,M,S else: W,SoW in edit cmds (log uses "
262  "SatPass fmt)");
263  setcfg(OutputDeletes, 1,
264  "if non-zero, include delete commands in the output cmd list");
265 
266  // -------------------------------------------------------------------------
267  // advanced options - marked with * - ordinary user will most likely NOT
268  // change
269  setcfg(RawBiasLimit, 100,
270  "* change in raw R-Ph that triggers bias reset (m)");
271  // WL editing
272  setcfg(WLNSigmaDelete, 2,
273  "* delete segments with sig(WL) > this * WLSigma ()");
274  setcfg(
275  WLWindowWidth, 50,
276  "* sliding window width for WL slip detection = 10+this/dt) (points)");
277  setcfg(WLNWindows, 2.5,
278  "* minimum segment size for WL small slip search (WLWindowWidth)");
279  setcfg(WLobviousLimit, 3,
280  "* minimum delta(WL) that produces an obvious slip (WLSigma)");
281  setcfg(WLNSigmaStrip, 3.5,
282  "* delete points with WL > this * computed sigma ()");
283  setcfg(WLNptsOutlierStats, 200,
284  "* maximum segment size to use robust outlier detection (pts)");
285  setcfg(WLRobustWeightLimit, 0.35,
286  "* minimum good weight in robust outlier detection (0<wt<=1)");
287  // WL small slips
288  setcfg(
289  WLSlipEdge, 3,
290  "* minimum separating WL slips and end of segment, else edit (pts)");
291  setcfg(WLSlipSize, 0.9, "* minimum WL slip size (WL wavelengths)");
292  setcfg(WLSlipExcess, 0.1,
293  "* minimum amount WL slip must exceed noise (WL wavelengths)");
294  setcfg(WLSlipSeparation, 2.5,
295  "* minimum excess/noise ratio of WL slip ()");
296  // GF small slips
297  setcfg(GFSlipWidth, 5,
298  "* minimum segment length for GF small slip detection (pts)");
299  setcfg(
300  GFSlipEdge, 3,
301  "* minimum separating GF slips and end of segment, else edit (pts)");
302  setcfg(GFobviousLimit, 1,
303  "* minimum delta(GF) that produces an obvious slip (GFVariation)");
304  setcfg(GFSlipOutlier, 5, "* minimum GF outlier magnitude/noise ratio ()");
305  setcfg(GFSlipSize, 0.8, "* minimum GF slip size (5.4cm wavelengths)");
306  setcfg(GFSlipStepToNoise, 0.1, "* maximum GF slip step/noise ratio ()");
307  setcfg(GFSlipToStep, 3, "* minimum GF slip magnitude/step ratio ()");
308  setcfg(GFSlipToNoise, 3, "* minimum GF slip magnitude/noise ratio ()");
309  // GF fix
310  setcfg(GFFixNpts, 15,
311  "* maximum number of points on each side to fix GF slips ()");
312  setcfg(GFFixDegree, 3, "* degree of polynomial used to fix GF slips ()");
313  setcfg(
314  GFFixMaxRMS, 100,
315  "* limit on RMS fit residuals to fix GF slips, else delete (5.4cm)");
316  setcfg(GFSkipSmall, 1,
317  "* if non-zero, skip small GF slips unless there is a WL slip");
318  }
319  catch (Exception& e)
320  {
321  GNSSTK_RETHROW(e);
322  }
323  catch (std::exception& e)
324  {
325  Exception E("std except: " + string(e.what()));
326  GNSSTK_THROW(E);
327  }
328  catch (...)
329  {
330  Exception e("Unknown exception");
331  GNSSTK_THROW(e);
332  }
333 }
334 
335 //------------------------------------------------------------------------------------
336 //------------------------------------------------------------------------------------
337 /* class Segment - used internally only.
338  An object to hold information about segments = periods of continuous phase.
339  Keep a linked list of these objects, subdivide whenever a discontinuity is
340  detected, and join whenever one is fixed. */
341 class Segment
342 {
343  public:
344  // member data
345  unsigned int nbeg, nend; // array indexes of the first and last good points
346  // always maintain these so they point to good data
347  unsigned int npts; // number of good points in this Segment
348  int nseg; // segment number - used for data dumps only
349  double bias1; // bias subtracted from WLbias for WLStats - only
350  Stats<double> WLStats; // includes N,min,max,ave,sig
351  double bias2; // bias subtracted from GFP for polynomial fit - only
352  PolyFit<double> PF; // for fit to GF range
353  double RMSROF; // RMS residual of fit of polynomial (PF) to GFR
354  bool WLsweep; // WLstatSweep(this) was called, used by detectWLsmallSlips
355 
356  // member functions
357  Segment() : nbeg(0), nend(0), npts(0), nseg(0), bias1(0.0), bias2(0.0)
358  {
359  WLStats.Reset();
360  WLsweep = false;
361  }
362  Segment(const Segment& s) { *this = s; }
363  ~Segment() {}
365  {
366  if (this == &s)
367  {
368  return *this;
369  }
370  nbeg = s.nbeg;
371  nend = s.nend;
372  npts = s.npts;
373  nseg = s.nseg;
374  bias1 = s.bias1;
375  bias2 = s.bias2;
376  WLStats = s.WLStats;
377  PF = s.PF;
378  RMSROF = s.RMSROF;
379  WLsweep = s.WLsweep;
380  return *this;
381  }
382 
383 }; // end class Segment
384 
385 //------------------------------------------------------------------------------------
386 //------------------------------------------------------------------------------------
387 // class Slip - used internally only
388 class Slip
389 {
390  public:
391  int index; // index in arrays where this slip occurs
392  long NWL, N1; // slip fixes for WL (N1-N2) and GF (=N1)
393  string msg; // string to be output after '#' on edit cmds
394  explicit Slip(int in) : index(in), NWL(0), N1(0) {}
395  bool operator<(const Slip& rhs) const { return index < rhs.index; }
396 }; // end class Slip
397 
398 //------------------------------------------------------------------------------------
399 //------------------------------------------------------------------------------------
400 /* class GDCPass - inherit SatPass and GDConfiguration - use internally only
401  this object is used to implement the DC algorithm. */
402 class GDCPass : public SatPass, public GDCconfiguration
403 {
404  public:
405  static const unsigned short DETECT; // both WL and GF
406  static const unsigned short FIX; // both WL and GF
407  static const unsigned short WLDETECT;
408  static const unsigned short WLFIX;
409  static const unsigned short GFDETECT;
410  static const unsigned short GFFIX;
411 
412  explicit GDCPass(SatPass& sp, const GDCconfiguration& gdc);
413 
414  //~GDCPass() { };
415 
418  int preprocess();
419 
424  int linearCombinations();
425 
428  int detectWLslips();
429 
434  int detectObviousSlips(string which);
435 
440  int firstDifferences(string which);
441 
445  void WLcomputeStats(list<Segment>::iterator& it);
446 
450  void WLsigmaStrip(list<Segment>::iterator& it);
451 
456  int WLstatSweep(list<Segment>::iterator& it, int width);
457 
464  int detectWLsmallSlips();
465 
476  bool foundWLsmallSlip(list<Segment>::iterator& it, int i);
477 
481  int fixAllSlips(string which);
482 
486  void fixOneSlip(list<Segment>::iterator& kt, string which);
487 
490  void WLslipFix(list<Segment>::iterator& left,
491  list<Segment>::iterator& right);
492 
497  int prepareGFdata();
498 
501  int detectGFslips();
502 
507  int GFphaseResiduals(list<Segment>::iterator& it);
508 
513  int detectGFsmallSlips();
514 
522  bool foundGFoutlier(int i, int inew, Stats<double>& pastSt,
523  Stats<double>& futureSt);
524 
536  bool foundGFsmallSlip(int i, int nseg, int iend, int ibeg,
537  deque<int>& pastIn, deque<int>& futureIn,
538  Stats<double>& pastSt, Stats<double>& futureSt);
539 
542  void GFslipFix(list<Segment>::iterator& left,
543  list<Segment>::iterator& right);
544 
549  long EstimateGFslipFix(list<Segment>::iterator& left,
550  list<Segment>::iterator& right, unsigned int nb,
551  unsigned int ne, long n1);
552 
555  int WLconsistencyCheck();
556 
560  string finish(int iret, SatPass& svp, vector<string>& editCmds);
561 
567  list<Segment>::iterator createSegment(list<Segment>::iterator sit, int ibeg,
568  string msg = string());
569 
576  string dumpSegments(string msg, int level = 2, bool extra = false);
577 
581  void deleteSegment(list<Segment>::iterator& it, string msg = string());
582 
583  private:
587  double cfg_func(string a)
588  {
589  if (CFGdescription[a] == string())
590  {
591  Exception e("cfg(UNKNOWN LABEL) : " + a);
592  GNSSTK_THROW(e);
593  }
594  return CFG[a];
595  }
596 
599  list<Segment> SegList;
600 
602  list<Slip> SlipList;
603 
605  // vector<double> A1,A2;
606 
609 
612 
614  // 07202010 not used PolyFit<double> GFPassFit;
615 
618  map<string, int> learn;
619 
620 }; // end class GDCPass
621 
622 //------------------------------------------------------------------------------------
623 // conveniences...
624 #define cfg(a) cfg_func(#a)
625 #define log *(p_oflog)
626 static const int L1 = 0;
627 static const int L2 = 1;
628 static const int P1 = 2;
629 static const int P2 = 3;
630 static const int A1 = 4;
631 static const int A2 = 5;
632 vector<string>
633  DCobstypes; // indexes into both data and this vector are L1,L2,etc...
634 
635 //------------------------------------------------------------------------------------
636 // Return values (used by all routines within this module):
637 static const int GLOfailed = -6;
638 static const int BadInput = -5;
639 static const int NoData = -4;
640 static const int FatalProblem = -3;
641 static const int PrematureEnd = -2; // NB never used
642 static const int Singular = -1;
643 static const int ReturnOK = 0;
644 
645 //------------------------------------------------------------------------------------
646 /* these are used only to associate a unique number in the log file with each
647  pass */
648 static int GDCUnique = 0; // unique number for each call
649 static int GDCUniqueFix; // unique for each (WL,GF) fix
650 static string GDCtag = "GDC"; // begin each line of return message
651 
652 //------------------------------------------------------------------------------------
653 /* wavelength and other frequency-dependent quantities, determined early in DC()
654  constants used in linear combinations */
655 int GLOn;
656 double wl1, wl2, wlwl, wlgf; // wavelengths: L1,L2,widelane,narrowlane
657 double wl1r, wl2r, wl1p, wl2p; // coefficients in widelane linear combinations
658 double gf1r, gf2r, gf1p,
659  gf2p; // coefficients in geometry-free linear combinations
660 
661 /*------------------------------------------------------------------------------------
662  Flags - constants used to mark slips, etc. using the SatPass flag:
663  ------------------------------------------------------------------------------------
664  These are from SatPass.cpp
665  const unsigned short SatPass::BAD = 0; // used by caller and DC to mark bad
666  data const unsigned short SatPass::OK = 1; // good data, no discontinuity
667  const unsigned short SatPass::LL1 = 2; // good data, discontinuity on L1 only
668  const unsigned short SatPass::LL2 = 4; // good data, discontinuity on L2 only
669  const unsigned short SatPass::LL3 = 6; // good data, discontinuity on L1 and
670  L2 */
671 const unsigned short GDCPass::WLDETECT = 2;
672 const unsigned short GDCPass::GFDETECT = 4;
673 const unsigned short GDCPass::DETECT = 6; // = WLDETECT | GFDETECT
674 const unsigned short GDCPass::WLFIX = 8;
675 const unsigned short GDCPass::GFFIX = 16;
676 const unsigned short GDCPass::FIX = 24; // = WLFIX | GFFIX
677 
678 /* notes on the use of these flags:
679  if(flag & DETECT) is true for EITHER WL or GF or both
680  if(flag & FIX) is true for EITHER WL or GF or both
681  if((flag & WLDETECT) && (flag & GFDETECT)) is true only for both WL and GF
682 
683  NB typical slip will have flag = DETECT+OK+FIX = 31
684  typical unfixed slip flag = DETECT+OK = 7
685 
686  BAD is used either as flag == BAD (for bad data) or flag != BAD (for good
687  data), thus there are two gotcha's
688  - if a point is marked, but is later set BAD, that info is lost
689  - if a BAD point is marked, it becomes 'good'
690  To avoid this we have to use OK rather than BAD:
691  either !(flag & OK) or (flag ^ OK) for bad data, and (flag & OK) for good
692  data */
693 
694 //------------------------------------------------------------------------------------
695 // The discontinuity corrector function
696 //------------------------------------------------------------------------------------
697 // yes you need the gnsstk::
699  std::vector<std::string>& editCmds,
700  std::string& retMessage, int GLOn_in)
701 {
702  try
703  {
704  unsigned int i, j;
705  int iret;
706 
707  if (gdc.getParameter("ResetUnique") != 0)
708  {
709  GDCUnique = 0;
710  gdc.setParameter("ResetUnique=0");
711  }
712  GDCUnique++;
713 
714  // if(!retMessage.empty()) { GDCtag = retMessage; }
715  retMessage = "";
716 
717  // --------------------------------------------------------------------------
718  // require obstypes L1,L2,C1/P1,C2/P2, and add two auxiliary arrays
719  DCobstypes.clear();
720  DCobstypes.push_back("L1");
721  DCobstypes.push_back("L2");
722  DCobstypes.push_back((int(gdc.getParameter("useCA1"))) == 0 ? "P1"
723  : "C1");
724  DCobstypes.push_back((int(gdc.getParameter("useCA2"))) == 0 ? "P2"
725  : "C2");
726  DCobstypes.push_back("A1");
727  DCobstypes.push_back("A2");
728 
729  // --------------------------------------------------------------------------
730  // test input for (a) some data and (b) the required obs types
731  // L1,L2,C1/P1,P2
732  vector<double> newdata(6);
733  string found;
734  try
735  {
736  newdata[L1] = svp.data(0, DCobstypes[L1]);
737  found += " " + DCobstypes[L1];
738  newdata[L2] = svp.data(0, DCobstypes[L2]);
739  found += " " + DCobstypes[L2];
740  newdata[P1] = svp.data(0, DCobstypes[P1]);
741  found += " " + DCobstypes[P1];
742  newdata[P2] = svp.data(0, DCobstypes[P2]);
743  found += " " + DCobstypes[P2];
744  }
745  catch (Exception& e)
746  { // if obs type is not found in input
747  ostringstream oss;
748  oss << " Missing required obs types. Require";
749  for (i = 0; i < 4; i++)
750  {
751  oss << " " << DCobstypes[i];
752  }
753  oss << "; found only" << found;
754 
755  retMessage = oss.str();
756  return BadInput;
757  }
758 
759  // --------------------------------------------------------------------------
760  // create a SatPass using DCobstypes, and fill from input
761  RinexSatID sat(svp.getSat());
762  SatPass nsvp(sat, svp.getDT(), DCobstypes);
763 
764  // fill the new SatPass with the input data
765  nsvp.status() = svp.status();
766  vector<unsigned short> lli(6), ssi(6);
767  for (i = 0; i < static_cast<int>(svp.size()); i++)
768  {
769  for (j = 0; j < 6; j++)
770  {
771  newdata[j] = j < 4 ? svp.data(i, DCobstypes[j]) : 0.0;
772  lli[j] = j < 4 ? svp.LLI(i, DCobstypes[j]) : 0;
773  ssi[j] = j < 4 ? svp.SSI(i, DCobstypes[j]) : 0;
774  }
775  // return value must be 0
776  nsvp.addData(svp.time(i), DCobstypes, newdata, lli, ssi,
777  svp.getFlag(i));
778  }
779 
780  // --------------------------------------------------------------------------
781  // create a GDCPass from the input SatPass (modified) and GDC
782  // configuration
783  GDCPass gp(nsvp, gdc);
784 
785  // --------------------------------------------------------------------------
786  /* if the satellite is Glonass, compute the frequency channel, if
787  necessary, and define wavelengths and other constants for this
788  satellite */
789  GLOn = GLOn_in;
790  if (sat.system == SatelliteSystem::Glonass)
791  {
792 
793  // only compute it if it is out of range
794  if (GLOn < -7 || GLOn > 7)
795  {
796  string msg;
797  // call SatPass::getGLOchannel() to get channel from data
798  GLOn = 0;
799  if (gp.getGLOchannel(GLOn, msg))
800  {
801  // log << "Computed GLONASS frequency channel = " << GLOn
802  // << "\n (" << msg << ")" << endl;
803  }
804  else
805  {
806  ostringstream oss;
807  oss << GDCtag << " " << setw(3) << GDCUnique << " " << sat << " "
808  << printTime(svp.getFirstTime(), svp.outFormat)
809  << " is returning with error code: failed to find GLONASS "
810  "frequency\n"
811  << msg << endl;
812  retMessage = oss.str();
813  return GLOfailed;
814  }
815  }
816 
817  /* GLO Frequency(Hz) L1 is 1602.0e6 + n*562.5e3 Hz = 9 * (178 +
818  n*0.0625) MHz
819  L2 1246.0e6 + n*437.5e3 Hz = 7 * (178 +
820  n*0.0625) MHz
821  Note that L1/L2 is always 9/7 for freq, 7/9 for wavelength */
822  static const double GLOfreq0L1 = 1602.0e6;
823  static const double GLOdfreqL1 = 562.5e3;
824  static const double GLOfreq0L2 = 1246.0e6;
825  static const double GLOdfreqL2 = 437.5e3;
826  static const double F1oF2 = 9.0 / 7.0;
827  static const double F2oF1 = 7.0 / 9.0;
828 
829  wl1 = C_MPS / (GLOfreq0L1 + GLOn * GLOdfreqL1);
830  wl2 = C_MPS / (GLOfreq0L2 + GLOn * GLOdfreqL2);
831  wlwl = 1.0 / (1.0 / wl1 - 1.0 / wl2);
832  wlgf = wl2 - wl1;
833 
834  wl1r = 1.0 / (1.0 + F2oF1);
835  wl2r = 1.0 / (1.0 + F1oF2);
836  wl1p = wl1 / (1.0 - F2oF1);
837  wl2p = wl2 / (1.0 - F1oF2);
838 
839  gf1r = -1.0;
840  gf2r = 1.0;
841  gf1p = wl1;
842  gf2p = -wl2;
843  }
844  else
845  { // GPS satellite
846  static const double CFF = C_MPS / OSC_FREQ_GPS;
847  static const double wl1_GPS = CFF / L1_MULT_GPS; // 19.0cm
848  static const double wl2_GPS = CFF / L2_MULT_GPS; // 24.4cm
849  static const double wlwl_GPS =
850  CFF / (L1_MULT_GPS - L2_MULT_GPS); // 86.2cm
851  static const double wlgf_GPS = wl2_GPS - wl1_GPS; // 5.4cm
852  static const double F1oF2 = L1_MULT_GPS / L2_MULT_GPS; // 77/60
853  static const double F2oF1 = L2_MULT_GPS / L1_MULT_GPS; // 60/77
854 
855  wl1 = wl1_GPS;
856  wl2 = wl2_GPS;
857  wlwl = wlwl_GPS;
858  wlgf = wlgf_GPS;
859 
860  wl1r = 1.0 / (1.0 + F2oF1);
861  wl2r = 1.0 / (1.0 + F1oF2);
862  wl1p = wl1 / (1.0 - F2oF1);
863  wl2p = wl2 / (1.0 - F1oF2);
864 
865  gf1r = -1.0;
866  gf2r = 1.0;
867  gf1p = wl1;
868  gf2p = -wl2;
869  }
870 
871  // --------------------------------------------------------------------------
872  /* implement the DC algorithm using the GDCPass
873  NB search for 'change the arrays' for places where arrays are
874  re-defined NB search for 'change the data' for places where the data is
875  modified (! biases) NB search for 'change the bias' for places where
876  the bias is changed */
877  for (;;)
878  { // a convenience...
879  // preparation
880  if ((iret = gp.preprocess()))
881  {
882  break;
883  }
884  if ((iret = gp.linearCombinations()))
885  {
886  break;
887  }
888 
889  // WL
890  if ((iret = gp.detectWLslips()))
891  {
892  break;
893  }
894  if ((iret = gp.fixAllSlips("WL")))
895  {
896  break;
897  }
898 
899  // GF
900  if ((iret = gp.prepareGFdata()))
901  {
902  break;
903  }
904  if ((iret = gp.detectGFslips()))
905  {
906  break;
907  }
908  if ((iret = gp.WLconsistencyCheck()))
909  {
910  break;
911  }
912  if ((iret = gp.fixAllSlips("GF")))
913  {
914  break;
915  }
916 
917  break; // mandatory
918  }
919 
920  // --------------------------------------------------------------------------
921  /* generate editing commands for deleted (flagged) data and slips,
922  use editing command (slips and deletes) to modify the original SatPass
923  data and print ending summary */
924  retMessage = gp.finish(iret, svp, editCmds);
925 
926  return iret;
927  }
928  catch (Exception& e)
929  {
930  GNSSTK_RETHROW(e);
931  }
932  catch (std::exception& e)
933  {
934  Exception E("std except: " + string(e.what()));
935  GNSSTK_THROW(E);
936  }
937  catch (...)
938  {
939  Exception e("Unknown exception");
940  GNSSTK_THROW(e);
941  }
942 }
943 
944 //---------------------------------------------------------------------------------
945 //---------------------------------------------------------------------------------
946 // class GDCPass member functions
947 //---------------------------------------------------------------------------------
949  : SatPass(sp.getSat(), sp.getDT(), sp.getObsTypes())
950 {
951  int i, j;
952  Status = sp.status();
953  dt = sp.getDT();
954  sat = sp.getSat();
955  vector<string> ot = sp.getObsTypes();
956  for (i = 0; i < static_cast<int>(ot.size()); i++)
957  {
958  labelForIndex[i] = ot[i];
960  }
961 
962  vector<double> vdata;
963  vector<unsigned short> lli, ssi;
964  for (i = 0; i < static_cast<int>(sp.size()); i++)
965  {
966  vdata.clear();
967  lli.clear();
968  ssi.clear();
969  for (j = 0; j < static_cast<int>(ot.size()); j++)
970  {
971  vdata.push_back(sp.data(i, ot[j]));
972  lli.push_back(sp.LLI(i, ot[j]));
973  ssi.push_back(sp.SSI(i, ot[j]));
974  }
975  addData(sp.time(i), ot, vdata, lli, ssi, sp.getFlag(i));
976  }
977 
978  *((GDCconfiguration *)this) = gdc;
979 
980  learn.clear();
981 }
982 
983 //---------------------------------------------------------------------------------
985 {
986  try
987  {
988  int ilast;
989  unsigned int i, Ngood;
990  double biasL1, biasL2, dbias;
991  list<Segment>::iterator it;
992 
993  if (cfg(Debug) >= 2)
994  {
995  Epoch CurrentTime;
996  // CurrentTime.setLocalTime();
997  log << "\n======== Beg GNSSTK Discontinuity Corrector " << GDCUnique
998  << " ================================================\n";
999  log << "GNSSTK Discontinuity Corrector Ver. " << GDCVersion << " Run "
1000  << CurrentTime << endl;
1001  }
1002 
1003  // check input
1004  if (cfg(DT) <= 0)
1005  {
1006  log << "Error: data time interval is not set...Abort" << endl;
1007  return FatalProblem;
1008  }
1009 
1010  // 050109 some parameters should depend on DT
1011  CFG["WLWindowWidth"] = 10 + int(0.5 + CFG["WLWindowWidth"] / CFG["DT"]);
1012 
1013  // create the first segment
1014  SegList.clear();
1015  {
1016  Segment s;
1017  s.nseg = 1;
1018  SegList.push_back(s);
1019  }
1020  it = SegList.begin();
1021 
1022  // loop over points in the pass
1023  // editing obviously bad data and adding segments where necessary
1024  for (ilast = -1, i = 0; i < static_cast<int>(size()); i++)
1025  {
1026 
1027  // ignore data the caller has marked BAD
1028  if (!(spdvector[i].flag & OK))
1029  {
1030  continue;
1031  }
1032 
1033  // just in case the caller has set it to something else...
1034  spdvector[i].flag = OK;
1035 
1036  /* look for obvious outliers
1037  Don't do this - sometimes the pseudoranges get extreme values b/c
1038  the clock is allowed to run off for long times - perfectly normal
1039  if(spdvector[i].data[P1] < cfg(MinRange) ||
1040  spdvector[i].data[P1] > cfg(MaxRange) ||
1041  spdvector[i].data[P2] < cfg(MinRange) ||
1042  spdvector[i].data[P2] > cfg(MaxRange) )
1043  {
1044  spdvector[i].flag = BAD;
1045  learn["points deleted: obvious outlier"]++;
1046  if(cfg(Debug) > 6)
1047  log << "Obvious outlier " << GDCUnique << " " << sat
1048  << " at " << i << " " << printTime(time(i),outFormat) <<
1049  endl;
1050  continue;
1051  } */
1052 
1053  // note first good point
1054  if (ilast == -1)
1055  {
1056  ilast = it->nbeg = i;
1057  }
1058 
1059  /* is there a gap here? if yes, create a new segment
1060  TD? do this here? why not allow any gap in the WL, and look for gaps
1061  TD? only in the GF? */
1062  if (cfg(DT) * (i - ilast) > cfg(MaxGap))
1063  {
1064  it = createSegment(it, i, "initial gap");
1065  }
1066 
1067  // count good points
1068  it->npts++;
1069  ilast = i;
1070  }
1071 
1072  // note last good point
1073  if (ilast == -1)
1074  {
1075  ilast = it->nbeg;
1076  }
1077  it->nend = ilast;
1078 
1079  /* 'change the arrays' A1, A2 to be range minus phase for output
1080  do the same at the end ("AFT")
1081  loop over segments, counting the number of non-trivial ones */
1082  for (Ngood = 0, it = SegList.begin(); it != SegList.end(); it++)
1083  {
1084  biasL1 = biasL2 = 0.0;
1085 
1086  // loop over points in this segment
1087  for (i = it->nbeg; i <= it->nend; i++)
1088  {
1089  if (!(spdvector[i].flag & OK))
1090  {
1091  continue;
1092  }
1093 
1094  dbias = fabs(spdvector[i].data[P1] - wl1 * spdvector[i].data[L1] -
1095  biasL1);
1096  if (dbias > cfg(RawBiasLimit))
1097  {
1098  if (cfg(Debug) >= 2)
1099  {
1100  log << "BEFresetL1 " << GDCUnique << " " << sat << " "
1101  << printTime(time(i), outFormat) << " " << fixed
1102  << setprecision(3) << biasL1 << " "
1103  << spdvector[i].data[P1] - wl1 * spdvector[i].data[L1]
1104  << endl;
1105  }
1106  biasL1 = spdvector[i].data[P1] - wl1 * spdvector[i].data[L1];
1107  }
1108 
1109  dbias = fabs(spdvector[i].data[P2] - wl2 * spdvector[i].data[L2] -
1110  biasL2);
1111  if (dbias > cfg(RawBiasLimit))
1112  {
1113  if (cfg(Debug) >= 2)
1114  {
1115  log << "BEFresetL2 " << GDCUnique << " " << sat << " "
1116  << printTime(time(i), outFormat) << " " << fixed
1117  << setprecision(3) << biasL2 << " "
1118  << spdvector[i].data[P2] - wl2 * spdvector[i].data[L2]
1119  << endl;
1120  }
1121  biasL2 = spdvector[i].data[P2] - wl2 * spdvector[i].data[L2];
1122  }
1123 
1124  spdvector[i].data[A1] =
1125  spdvector[i].data[P1] - wl1 * spdvector[i].data[L1] - biasL1;
1126  spdvector[i].data[A2] =
1127  spdvector[i].data[P2] - wl2 * spdvector[i].data[L2] - biasL2;
1128 
1129  } // end loop over points in the segment
1130 
1131  // delete small segments
1132  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
1133  {
1134  deleteSegment(it, "insufficient data in segment");
1135  }
1136  else
1137  {
1138  Ngood++;
1139  }
1140  }
1141 
1142  if (cfg(Debug) >= 2)
1143  {
1144  dumpSegments("BEF", 2, true);
1145  }
1146 
1147  if (Ngood == 0)
1148  {
1149  return NoData;
1150  }
1151  return ReturnOK;
1152  }
1153  catch (Exception& e)
1154  {
1155  GNSSTK_RETHROW(e);
1156  }
1157  catch (std::exception& e)
1158  {
1159  Exception E("std except: " + string(e.what()));
1160  GNSSTK_THROW(E);
1161  }
1162  catch (...)
1163  {
1164  Exception e("Unknown exception");
1165  GNSSTK_THROW(e);
1166  }
1167 }
1168 
1169 //------------------------------------------------------------------------------------
1170 //------------------------------------------------------------------------------------
1172 {
1173  try
1174  {
1175  unsigned int i;
1176  double wlr, wlp, wlbias, gfr, gfp;
1177  list<Segment>::iterator it;
1178 
1179  // iterate over segments
1180  for (it = SegList.begin(); it != SegList.end(); it++)
1181  {
1182  it->npts = 0; // re-compute npts here
1183 
1184  // loop over points in this segment
1185  for (i = it->nbeg; i <= it->nend; i++)
1186  {
1187  if (!(spdvector[i].flag & OK))
1188  {
1189  continue;
1190  }
1191 
1192  // narrow lane range (m)
1193  wlr = wl1r * spdvector[i].data[P1] + wl2r * spdvector[i].data[P2];
1194  // wide lane phase (m)
1195  wlp = wl1p * spdvector[i].data[L1] + wl2p * spdvector[i].data[L2];
1196  // geometry-free range (m)
1197  gfr = spdvector[i].data[P1] - spdvector[i].data[P2];
1198  // geometry-free phase (m)
1199  gfp = gf1p * spdvector[i].data[L1] + gf2p * spdvector[i].data[L2];
1200  // wide lane bias (cycles)
1201  wlbias = (wlp - wlr) / wlwl;
1202 
1203  // change the bias
1204  if (it->npts == 0)
1205  { // first good point
1206  it->bias1 = wlbias; // WL bias (NWL)
1207  it->bias2 = gfp; // GFP bias
1208  }
1209 
1210  // change the arrays
1211  spdvector[i].data[L1] = gfp + gfr; // only used in GF
1212  spdvector[i].data[L2] = gfp;
1213  spdvector[i].data[P1] = wlbias;
1214  spdvector[i].data[P2] = -gfr;
1215 
1216  it->npts++;
1217  }
1218  }
1219 
1220  if (cfg(Debug) >= 2)
1221  {
1222  dumpSegments("LCD");
1223  }
1224 
1225  return ReturnOK;
1226  }
1227  catch (Exception& e)
1228  {
1229  GNSSTK_RETHROW(e);
1230  }
1231  catch (std::exception& e)
1232  {
1233  Exception E("std except: " + string(e.what()));
1234  GNSSTK_THROW(E);
1235  }
1236  catch (...)
1237  {
1238  Exception e("Unknown exception");
1239  GNSSTK_THROW(e);
1240  }
1241 }
1242 
1243 //------------------------------------------------------------------------------------
1244 //------------------------------------------------------------------------------------
1245 // detect slips in the wide lane bias
1247 {
1248  try
1249  {
1250  int iret;
1251  list<Segment>::iterator it;
1252 
1253  // look for obvious slips. this will break one segment into many
1254  if ((iret = detectObviousSlips("WL")))
1255  {
1256  return iret;
1257  }
1258 
1259  for (it = SegList.begin(); it != SegList.end(); it++)
1260  {
1261 
1262  // compute stats and delete segments that are too small
1263  WLcomputeStats(it);
1264 
1265  // sigma-strip the WL bias, and remove small segments
1266  if (it->npts > 0)
1267  {
1268  WLsigmaStrip(it);
1269  }
1270 
1271  // print this before deleting segments with large sigma
1272  if (cfg(Debug) >= 1 &&
1273  it->npts >= static_cast<unsigned int>(cfg(MinPts)))
1274  {
1275  log << "WLSIG " << GDCUnique << " " << sat << " " << it->nseg << " "
1276  << printTime(time(it->nbeg), outFormat) << fixed
1277  << setprecision(3) << " " << it->WLStats.StdDev() << " "
1278  << it->WLStats.Average() << " " << it->WLStats.Minimum() << " "
1279  << it->WLStats.Maximum() << " " << it->npts << " " << it->nbeg
1280  << " - " << it->nend << " " << it->bias1 << " " << it->bias2
1281  << endl;
1282  }
1283 
1284  // delete segments if sigma is too high...
1285  if (it->WLStats.StdDev() > cfg(WLNSigmaDelete) * cfg(WLSigma))
1286  {
1287  deleteSegment(it, "WL sigma too big");
1288  }
1289 
1290  /* if there are less than about 2.5*cfg(WLWindowWidth) good points,
1291  don't bother to use the sliding window method to look for slips;
1292  otherwise compute stats for each segment using the 'two-paned
1293  sliding stats window', store results in the temporary arrays */
1294  if (double(it->npts) >= cfg(WLNWindows) * int(cfg(WLWindowWidth)))
1295  {
1296  iret = WLstatSweep(it, int(cfg(WLWindowWidth)));
1297  if (iret)
1298  {
1299  return iret;
1300  }
1301  }
1302 
1303  } // end loop over segments
1304 
1305  /* use the temporary arrays filled by WLstatSweep to detect slips in the
1306  WL bias recompute WLstats, and break up the segments where slips are
1307  found */
1308  if ((iret = detectWLsmallSlips()))
1309  {
1310  return iret;
1311  }
1312 
1313  // delete all segments that are too small
1314  for (it = SegList.begin(); it != SegList.end(); it++)
1315  {
1316  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
1317  {
1318  deleteSegment(it, "insufficient data in segment");
1319  }
1320  }
1321 
1322  if (cfg(Debug) >= 4)
1323  {
1324  dumpSegments("WLD");
1325  }
1326 
1327  return ReturnOK;
1328  }
1329  catch (Exception& e)
1330  {
1331  GNSSTK_RETHROW(e);
1332  }
1333  catch (std::exception& e)
1334  {
1335  Exception E("std except: " + string(e.what()));
1336  GNSSTK_THROW(E);
1337  }
1338  catch (...)
1339  {
1340  Exception e("Unknown exception");
1341  GNSSTK_THROW(e);
1342  }
1343 }
1344 
1345 //------------------------------------------------------------------------------------
1346 /* detect obvious slips by computing the first difference (of either WL or GFP)
1347  and looking for outliers. create new segments where there are slips
1348  which is either 'WL' or 'GF'. */
1350 {
1351  try
1352  {
1353  // TD determine from range noise // ~ 2*range noise/wl2
1354  const double WLobviousNWLLimit = cfg(WLobviousLimit) * cfg(WLSigma);
1355  const double GFobviousNWLLimit =
1356  cfg(GFobviousLimit) * cfg(GFVariation) / wlgf;
1357  bool outlier, nogood;
1358  unsigned int i, j, ibad, igood, nok;
1359  int iret;
1360  double limit, wlbias;
1361  list<Segment>::iterator it;
1362 
1363  // compute 1st differences of (WL bias, GFP-GFR) as 'which' is (WL,GF)
1364  iret = firstDifferences(which);
1365  if (iret)
1366  {
1367  return iret;
1368  }
1369 
1370  if (cfg(Debug) >= 5)
1371  {
1372  dumpSegments(string("D") + which, 2, true); // DWL DGF
1373  }
1374 
1375  // scan the first differences, eliminate outliers and
1376  // break into segments where there are WL slips.
1377  limit = (which == string("WL") ? WLobviousNWLLimit : GFobviousNWLLimit);
1378  it = SegList.begin();
1379  nok = 0;
1380  nogood = true;
1381  outlier = false;
1382  for (i = 0; i < static_cast<int>(size()); i++)
1383  {
1384  if (i < it->nbeg)
1385  {
1386  outlier = false;
1387  continue;
1388  }
1389  if (i > it->nend)
1390  { // change segments
1391  if (outlier)
1392  {
1393  if (spdvector[ibad].flag & OK)
1394  {
1395  nok--;
1396  }
1397  spdvector[ibad].flag = BAD;
1398  learn[string("points deleted: ") + which +
1399  string(" slip outlier")]++;
1400  outlier = false;
1401  }
1402  it->npts = nok;
1403 
1404  // update nbeg and nend
1405  while (it->nbeg < it->nend && it->nbeg < static_cast<int>(size()) &&
1406  !(spdvector[it->nbeg].flag & OK))
1407  {
1408  it->nbeg++;
1409  }
1410 
1411  while (it->nend > it->nbeg && it->nend > 0 &&
1412  !(spdvector[it->nend].flag & OK))
1413  {
1414  it->nend--;
1415  }
1416  it++;
1417  if (it == SegList.end())
1418  {
1419  return ReturnOK;
1420  }
1421  nok = 0;
1422  }
1423 
1424  if (!(spdvector[i].flag & OK))
1425  {
1426  continue;
1427  }
1428  nok++; // nok = # good points in segment
1429 
1430  if (nogood)
1431  {
1432  igood = i;
1433  nogood = false;
1434  } // igood is index of last good point
1435 
1436  if (fabs(spdvector[i].data[A1]) > limit)
1437  { // found an outlier (1st diff, cycles)
1438  outlier = true;
1439  ibad = i; // ibad is index of last bad point
1440  }
1441  else if (outlier)
1442  { // this point good, but not past one(s)
1443  for (unsigned int j = igood + 1; j < ibad; j++)
1444  {
1445  if (spdvector[j].flag & OK)
1446  {
1447  nok--;
1448  }
1449  if (spdvector[j].flag & DETECT)
1450  {
1451  log << "Warning - found an obvious slip, "
1452  << "but marking BAD a point already marked with slip "
1453  << GDCUnique << " " << sat << " "
1454  << printTime(time(j), outFormat) << " " << j << endl;
1455  }
1456  spdvector[j].flag = BAD; // mark all points between as bad
1457  learn[string("points deleted: ") + which +
1458  string(" slip outlier")]++;
1459  }
1460 
1461  // create a new segment, starting at the last outlier
1462  it->npts = nok - 2;
1463  // WL slip gross OR GF slip gross
1464  it = createSegment(it, ibad, which + string(" slip gross"));
1465 
1466  // mark it
1467  spdvector[ibad].flag |=
1468  (which == string("WL") ? WLDETECT : GFDETECT);
1469 
1470  // change the bias in the new segment
1471  if (which == "WL")
1472  {
1473  wlbias = spdvector[ibad].data[P1];
1474  it->bias1 =
1475  long(wlbias + (wlbias > 0 ? 0.5 : -0.5)); // WL bias (NWL)
1476  }
1477  if (which == "GF")
1478  {
1479  it->bias2 = spdvector[ibad].data[L2]; // GFP bias
1480  }
1481 
1482  // prep for next point
1483  nok = 2;
1484  outlier = false;
1485  igood = ibad;
1486  }
1487  else
1488  {
1489  igood = i;
1490  }
1491  }
1492  it->npts = nok;
1493 
1494  return ReturnOK;
1495  }
1496  catch (Exception& e)
1497  {
1498  GNSSTK_RETHROW(e);
1499  }
1500  catch (std::exception& e)
1501  {
1502  Exception E("std except: " + string(e.what()));
1503  GNSSTK_THROW(E);
1504  }
1505  catch (...)
1506  {
1507  Exception e("Unknown exception");
1508  GNSSTK_THROW(e);
1509  }
1510 }
1511 
1512 //------------------------------------------------------------------------------------
1513 /* compute first differences of data array(s) for WL and GF gross slip
1514  detection. for WL difference the WLbias (P1); for GF, the GFP (L2) and the
1515  GFR (P2) Store results in A1, and for GF put the range difference in A2 */
1516 int GDCPass::firstDifferences(string which)
1517 {
1518  try
1519  {
1520  // if(A1.size() != size()) return FatalProblem;
1521 
1522  int i, iprev = -1;
1523 
1524  for (i = 0; i < static_cast<int>(size()); i++)
1525  {
1526  // ignore bad data
1527  if (!(spdvector[i].flag & OK))
1528  {
1529  spdvector[i].data[A1] = spdvector[i].data[A2] = 0.0;
1530  continue;
1531  }
1532 
1533  // compute first differences - 'change the arrays' A1 and A2
1534  if (which == string("WL"))
1535  {
1536  if (iprev == -1)
1537  {
1538  spdvector[i].data[A1] = 0.0;
1539  }
1540  else
1541  {
1542  spdvector[i].data[A1] =
1543  (spdvector[i].data[P1] - spdvector[iprev].data[P1]);
1544  }
1545  }
1546  else if (which == string("GF"))
1547  {
1548  if (iprev == -1) // first difference not defined at first point
1549  {
1550  spdvector[i].data[A1] = spdvector[i].data[A2] = 0.0;
1551  }
1552  else
1553  {
1554  // compute first difference of L1 = raw residual GFP-GFR
1555  spdvector[i].data[A1] =
1556  (spdvector[i].data[L1] - spdvector[iprev].data[L1]);
1557  // compute first difference of L2 = GFP
1558  spdvector[i].data[A2] =
1559  (spdvector[i].data[L2] - spdvector[iprev].data[L2]);
1560  }
1561  }
1562 
1563  // go to next point
1564  iprev = i;
1565  }
1566 
1567  return ReturnOK;
1568  }
1569  catch (Exception& e)
1570  {
1571  GNSSTK_RETHROW(e);
1572  }
1573  catch (std::exception& e)
1574  {
1575  Exception E("std except: " + string(e.what()));
1576  GNSSTK_THROW(E);
1577  }
1578  catch (...)
1579  {
1580  Exception e("Unknown exception");
1581  GNSSTK_THROW(e);
1582  }
1583 }
1584 
1585 //------------------------------------------------------------------------------------
1586 /* for one segment, compute conventional statistics on the
1587  WL bias and count the number of good points */
1588 void GDCPass::WLcomputeStats(list<Segment>::iterator& it)
1589 {
1590  try
1591  {
1592  // compute WLStats
1593  it->WLStats.Reset();
1594  it->npts = 0;
1595 
1596  // loop over data, adding to Stats, and counting good points
1597  for (unsigned int i = it->nbeg; i <= it->nend; i++)
1598  {
1599  if (!(spdvector[i].flag & OK))
1600  {
1601  continue;
1602  }
1603  it->WLStats.Add(spdvector[i].data[P1] - it->bias1);
1604  it->npts++;
1605  }
1606 
1607  // eliminate segments with too few points
1608  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
1609  {
1610  deleteSegment(it, "insufficient data in segment");
1611  }
1612  }
1613  catch (Exception& e)
1614  {
1615  GNSSTK_RETHROW(e);
1616  }
1617  catch (std::exception& e)
1618  {
1619  Exception E("std except: " + string(e.what()));
1620  GNSSTK_THROW(E);
1621  }
1622  catch (...)
1623  {
1624  Exception e("Unknown exception");
1625  GNSSTK_THROW(e);
1626  }
1627 }
1628 
1629 //------------------------------------------------------------------------------------
1630 /* for one segment, compute conventional statistics on the
1631  WL bias, remove small segments, and mark bad points that lie outside N*sigma */
1632 void GDCPass::WLsigmaStrip(list<Segment>::iterator& it)
1633 {
1634  try
1635  {
1636  bool outlier, haveslip;
1637  unsigned short slip;
1638  int slipindex;
1639  unsigned int i, j, k;
1640  double wlbias, nsigma, ave;
1641 
1642  // use robust stats on small segments, for big ones stick with
1643  // conventional
1644 
1645  if (it->npts < cfg(WLNptsOutlierStats))
1646  { // robust
1647  /* 'change the arrays' A1 and A2; they will be overwritten by
1648  WLstatSweep but then dumped as DSCWLF... use temp vectors so they
1649  can be passed to Robust::MAD and Robust::MEstimate */
1650  double median, mad;
1651  vector<double> vecA1, vecA2; // use these temp, for Robust:: calls
1652 
1653  // put wlbias in vecA1, but without gaps: let j index good points only
1654  // from nbeg
1655  for (j = i = it->nbeg; i <= it->nend; i++)
1656  {
1657  if (!(spdvector[i].flag & OK))
1658  {
1659  continue;
1660  }
1661  wlbias = spdvector[i].data[P1] - it->bias1;
1662  vecA1.push_back(wlbias);
1663  vecA2.push_back(0.0);
1664  j++;
1665  }
1666 
1667  mad = Robust::MAD(&(vecA1[0]), j - it->nbeg, median, true);
1668  nsigma = cfg(WLNSigmaStrip) * mad;
1669  ave = Robust::MEstimate(&(vecA1[0]), j - it->nbeg, median, mad,
1670  &(vecA2[0]));
1671 
1672  // change the array : A1 is wlbias, A2 (output) will contain the
1673  // weights copy temps out into A1 and A2
1674  for (k = 0, i = it->nbeg; i < j; k++, i++)
1675  {
1676  spdvector[i].data[A1] = vecA1[k];
1677  spdvector[i].data[A2] = vecA2[k];
1678  }
1679 
1680  haveslip = false;
1681  for (j = i = it->nbeg; i <= it->nend; i++)
1682  {
1683  if (!(spdvector[i].flag & OK))
1684  {
1685  continue;
1686  }
1687 
1688  wlbias = spdvector[i].data[P1] - it->bias1;
1689 
1690  if (fabs(wlbias - ave) > nsigma ||
1691  spdvector[j].data[A2] < cfg(WLRobustWeightLimit))
1692  {
1693  outlier = true;
1694  }
1695  else
1696  {
1697  outlier = false;
1698  }
1699 
1700  // remove points by sigma stripping
1701  if (outlier)
1702  {
1703  if (spdvector[i].flag & DETECT || i == it->nbeg)
1704  {
1705  haveslip = true;
1706  slipindex = i; // mark
1707  slip = spdvector[i].flag; // save to put on first good point
1708  }
1709  spdvector[i].flag = BAD;
1710  learn["points deleted: WL sigma stripping"]++;
1711  it->npts--;
1712  it->WLStats.Subtract(wlbias);
1713  }
1714  else if (haveslip)
1715  {
1716  spdvector[i].flag = slip;
1717  haveslip = false;
1718  }
1719 
1720  if (cfg(Debug) >= 6)
1721  {
1722  log << "DSCWLR " << GDCUnique << " " << sat << " " << it->nseg
1723  << " " << printTime(time(i), outFormat) << fixed
1724  << setprecision(3) << " " << setw(3) << spdvector[i].flag
1725  << " " << setw(13) << spdvector[j].data[A1] // wlbias
1726  << " " << setw(13) << fabs(wlbias - ave) << " " << setw(5)
1727  << spdvector[j].data[A2] // 0 <= weight <= 1
1728  << " " << setw(3) << i << (outlier ? " outlier" : "");
1729  if (i == it->nbeg)
1730  {
1731  log << " " << setw(13) << it->bias1 << " " << setw(13)
1732  << it->bias2;
1733  }
1734  log << endl;
1735  }
1736 
1737  j++;
1738  }
1739  }
1740  else
1741  { // conventional
1742 
1743  // nsigma = WLsigmaStrippingNsigmaLimit * it->WLStats.StdDev();
1744  nsigma = cfg(WLNSigmaStrip) * it->WLStats.StdDev();
1745 
1746  haveslip = false;
1747  ave = it->WLStats.Average();
1748  for (i = it->nbeg; i <= it->nend; i++)
1749  {
1750  if (!(spdvector[i].flag & OK))
1751  {
1752  continue;
1753  }
1754 
1755  wlbias = spdvector[i].data[P1] - it->bias1;
1756 
1757  // remove points by sigma stripping
1758  if (fabs(wlbias - ave) > nsigma)
1759  { // TD add absolute limit?
1760  if (spdvector[i].flag & DETECT)
1761  {
1762  haveslip = true;
1763  slipindex = i; // mark
1764  slip = spdvector[i].flag; // save to put on first good point
1765  }
1766  spdvector[i].flag = BAD;
1767  learn["points deleted: WL sigma stripping"]++;
1768  it->npts--;
1769  it->WLStats.Subtract(wlbias);
1770  }
1771  else if (haveslip)
1772  {
1773  spdvector[i].flag = slip;
1774  haveslip = false;
1775  }
1776 
1777  } // loop over points in segment
1778  }
1779 
1780  // change nbeg, but don't change the bias
1781  if (haveslip)
1782  {
1783  it->nbeg = slipindex;
1784  }
1785 
1786  // again
1787  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
1788  {
1789  deleteSegment(it, "WL sigma stripping");
1790  }
1791  else
1792  {
1793  // update nbeg and nend // TD add limit 0 size()
1794  while (it->nbeg < it->nend && !(spdvector[it->nbeg].flag & OK))
1795  {
1796  it->nbeg++;
1797  }
1798  while (it->nend > it->nbeg && !(spdvector[it->nend].flag & OK))
1799  {
1800  it->nend--;
1801  }
1802  }
1803  }
1804  catch (Exception& e)
1805  {
1806  GNSSTK_RETHROW(e);
1807  }
1808  catch (std::exception& e)
1809  {
1810  Exception E("std except: " + string(e.what()));
1811  GNSSTK_THROW(E);
1812  }
1813  catch (...)
1814  {
1815  Exception e("Unknown exception");
1816  GNSSTK_THROW(e);
1817  }
1818 }
1819 
1820 //------------------------------------------------------------------------------------
1821 /* in the given segment, compute statistics on the WL bias using a
1822  'two-paned sliding window', each pane of width 'width' good points.
1823  store the results in the parallel (to SatPass::data) arrays A1,A2. */
1824 int GDCPass::WLstatSweep(list<Segment>::iterator& it, int width)
1825 {
1826  try
1827  {
1828  unsigned int iminus, i, iplus, uwidth(width);
1829  double wlbias, test, limit;
1830  Stats<double> pastStats, futureStats;
1831 
1832  // ignore empty segments
1833  if (it->npts == 0)
1834  {
1835  return ReturnOK;
1836  }
1837  it->WLsweep = true;
1838 
1839  /* Cartoon of the 'two-pane moving window'
1840  windows: 'past window' 'future window'
1841  stats : --- pastStats---- ----futureStats--
1842  data : (x x x x x x x x x)(x x x x x x x x x) x ...
1843  | | | |
1844  indexes: iminus i-1 i iplus
1845 
1846  start with the window 'squashed' to one point - the first one */
1847  iminus = i = iplus = it->nbeg;
1848 
1849  /* fill up the future window to size 'width', but don't go beyond the
1850  segment */
1851  while (futureStats.N() < uwidth && iplus <= it->nend)
1852  {
1853  if (spdvector[iplus].flag & OK)
1854  { // add only good data
1855  futureStats.Add(spdvector[iplus].data[P1] - it->bias1);
1856  }
1857  iplus++;
1858  }
1859 
1860  // now loop over all points in the segment
1861  for (i = it->nbeg; i <= it->nend; i++)
1862  {
1863  if (!(spdvector[i].flag & OK)) // add only good data
1864  {
1865  continue;
1866  }
1867 
1868  // compute test and limit
1869  test = 0;
1870  if (pastStats.N() > 0 && futureStats.N() > 0)
1871  {
1872  test = fabs(futureStats.Average() - pastStats.Average());
1873  }
1874  limit = ::sqrt(futureStats.Variance() + pastStats.Variance());
1875  // 'change the arrays' A1 and A2
1876  spdvector[i].data[A1] = test;
1877  spdvector[i].data[A2] = limit;
1878 
1879  wlbias = spdvector[i].data[P1] - it->bias1; // debiased WLbias
1880 
1881  // dump the stats
1882  if (cfg(Debug) >= 6)
1883  {
1884  log << "WLS " << GDCUnique << " " << sat << " " << it->nseg << " "
1885  << printTime(time(i), outFormat) << fixed << setprecision(3)
1886  << " " << setw(3) << pastStats.N() << " " << setw(7)
1887  << pastStats.Average() << " " << setw(7) << pastStats.StdDev()
1888  << " " << setw(3) << futureStats.N() << " " << setw(7)
1889  << futureStats.Average() << " " << setw(7)
1890  << futureStats.StdDev() << " " << setw(9)
1891  << spdvector[i].data[A1] << " " << setw(9)
1892  << spdvector[i].data[A2] << " " << setw(9) << wlbias << " "
1893  << setw(3) << i << endl;
1894  }
1895 
1896  // update stats :
1897  // move point i from future to past, ...
1898  futureStats.Subtract(wlbias);
1899  pastStats.Add(wlbias);
1900  // ... and move iplus up by one (good) point, ...
1901  while (futureStats.N() < uwidth && iplus <= it->nend)
1902  {
1903  if (spdvector[iplus].flag & OK)
1904  {
1905  futureStats.Add(spdvector[iplus].data[P1] - it->bias1);
1906  }
1907  iplus++;
1908  }
1909  // ... and move iminus up by one good point
1910  while (static_cast<int>(pastStats.N()) > uwidth && iminus <= it->nend)
1911  {
1912  if (spdvector[iminus].flag & OK)
1913  {
1914  pastStats.Subtract(spdvector[iminus].data[P1] - it->bias1);
1915  }
1916  iminus++;
1917  }
1918 
1919  } // end loop over i=all points in segment
1920 
1921  return ReturnOK;
1922  }
1923  catch (Exception& e)
1924  {
1925  GNSSTK_RETHROW(e);
1926  }
1927  catch (std::exception& e)
1928  {
1929  Exception E("std except: " + string(e.what()));
1930  GNSSTK_THROW(E);
1931  }
1932  catch (...)
1933  {
1934  Exception e("Unknown exception");
1935  GNSSTK_THROW(e);
1936  }
1937 }
1938 
1939 //------------------------------------------------------------------------------------
1940 /* look for slips in the WL using the results of WLstatSweep
1941  if slip is close to either end (< window width), just chop off the small
1942  segment recompute WLstats; when a slip is found, create a new segment */
1944 {
1945  try
1946  {
1947  unsigned int k, nok;
1948  double wlbias;
1949  list<Segment>::iterator it;
1950 
1951  // find first segment for which WLstatSweep was called
1952  it = SegList.begin();
1953  while (!it->WLsweep)
1954  {
1955  it++;
1956  if (it == SegList.end())
1957  {
1958  return ReturnOK;
1959  }
1960  }
1961  it->WLStats.Reset();
1962 
1963  // loop over the data arrays - all segments
1964  unsigned int i = it->nbeg;
1965  nok = 0;
1966  unsigned int halfwidth = static_cast<unsigned int>(cfg(WLSlipEdge));
1967  while (i < size())
1968  {
1969  // must skip segments for which WLstatSweep was not called
1970  while (i > it->nend || !it->WLsweep)
1971  {
1972  if (i > it->nend)
1973  {
1974  it->npts = nok;
1975  nok = 0;
1976  }
1977  it++;
1978  if (it == SegList.end())
1979  {
1980  return ReturnOK;
1981  }
1982  i = it->nbeg;
1983  if (it->WLsweep)
1984  {
1985  it->WLStats.Reset();
1986  }
1987  }
1988 
1989  if (spdvector[i].flag & OK)
1990  {
1991  nok++; // nok = # good points in segment
1992 
1993  if (nok == 1)
1994  { // change the bias, as WLStats reset
1995  wlbias = spdvector[i].data[P1];
1996  it->bias1 = long(wlbias + (wlbias > 0 ? 0.5 : -0.5));
1997  }
1998 
1999  // condition 3 - near ends of segment?
2000  if (nok < halfwidth || (it->npts - nok) < halfwidth)
2001  {
2002  // failed test 3 - near ends of segment
2003  // consider chopping off this end of segment - large limit?
2004  // TD must do something here ...
2005  if (cfg(Debug) >= 6)
2006  {
2007  log << "too near end " << GDCUnique << " " << i << " " << nok
2008  << " " << it->npts - nok << " "
2009  << printTime(time(i), outFormat) << " "
2010  << spdvector[i].data[A1] << " " << spdvector[i].data[A2]
2011  << endl;
2012  }
2013  }
2014  else if (foundWLsmallSlip(it, i))
2015  { // met condition 3
2016  // create new segment
2017  // TD what if nok < MinPts? -- cf detectGFsmallSlips
2018  k = it->npts;
2019  it->npts = nok;
2020  // log << "create new segment at i = " << i << " " << nok <<
2021  // "pts\n";
2022  it = createSegment(it, i, "WL slip small");
2023 
2024  // mark it
2025  spdvector[i].flag |= WLDETECT;
2026 
2027  // prep for next segment
2028  // biases remain the same in the new segment
2029  it->npts = k - nok;
2030  nok = 0;
2031  it->WLStats.Reset();
2032  wlbias =
2033  spdvector[i].data[P1]; // change the bias, as WLStats reset
2034  it->bias1 = long(wlbias + (wlbias > 0 ? 0.5 : -0.5));
2035  }
2036 
2037  it->WLStats.Add(spdvector[i].data[P1] - it->bias1);
2038 
2039  } // end if good data
2040 
2041  i++;
2042 
2043  } // end loop over points in the pass
2044  it->npts = nok;
2045 
2046  return ReturnOK;
2047  }
2048  catch (Exception& e)
2049  {
2050  GNSSTK_RETHROW(e);
2051  }
2052  catch (std::exception& e)
2053  {
2054  Exception E("std except: " + string(e.what()));
2055  GNSSTK_THROW(E);
2056  }
2057  catch (...)
2058  {
2059  Exception e("Unknown exception");
2060  GNSSTK_THROW(e);
2061  }
2062 }
2063 
2064 //------------------------------------------------------------------------------------
2065 /* determine if a slip has been found at index i, in segment it
2066  A1 = test = fabs(futureStats.Average()-pastStats.Average()) ~ step in ave WL
2067  A2 = limit = sqrt(futureStats.Variance()+pastStats.Variance()) ~ noise in WL
2068  ALL CONDITIONs needed for a slip to be detected:
2069  1. test must be > WLSlipSize (cycles)
2070  2. test-limit must be > (WLSlipExcess) // TD keep this?
2071  3. slip must be far (>1/2 window) from either end - handled in
2072  detectWLsmallSlips
2073  4. test must be at a local maximum within ~ window width
2074  5. limit must be at a local minimum within ~ window width
2075  6. (test-limit)/limit > (WLSlipSeparation = 2.5) // this is critical
2076  test large limit (esp near end of a pass) means too much noise */
2077 bool GDCPass::foundWLsmallSlip(list<Segment>::iterator& it, int i)
2078 {
2079  try
2080  {
2081  const unsigned int minMaxWidth = int(cfg(WLSlipEdge));
2082  unsigned int j, jp, jm, pass4, pass5, Pass;
2083  /* A1 = step = fabs(futureStats.Average() - pastStats.Average());
2084  A2 = limit = ::sqrt(futureStats.Variance() + pastStats.Variance());
2085  all units WL cycles */
2086  double step = spdvector[i].data[A1];
2087  double lim = spdvector[i].data[A2];
2088 
2089  // 050109 if Debug=6, print only possible slips, if 7 print all
2090  bool isSlip = false, halfCycle = false;
2091  ostringstream oss;
2092 
2093  // Debug print - NB '>' is always pass, '<=' is fail....
2094  if (cfg(Debug) >= 6)
2095  {
2096  oss << "WLslip " << GDCUnique << " " << sat << " " << setw(2)
2097  << it->nseg << " " << setw(3) << i << " "
2098  << printTime(time(i), outFormat)
2099  //<< " " << it->npts << "pt"
2100  << fixed << setprecision(2) << " step=" << step << " lim=" << lim
2101  << " (1)" << spdvector[i].data[A1]
2102  << (spdvector[i].data[A1] > cfg(WLSlipSize) ? ">" : "<=")
2103  << cfg(WLSlipSize) << " (2)"
2104  << spdvector[i].data[A1] - spdvector[i].data[A2]
2105  << (spdvector[i].data[A1] - spdvector[i].data[A2] >
2106  cfg(WLSlipExcess)
2107  ? ">"
2108  : "<=")
2109  << cfg(WLSlipExcess); // no endl
2110  }
2111 
2112  Pass = 0; // 111312 count all tests passed
2113 
2114  // CONDITION 1
2115  if (step > cfg(WLSlipSize))
2116  {
2117  Pass++;
2118  }
2119  else if (step > 0.45)
2120  {
2121  halfCycle = true;
2122  }
2123  // CONDITION 2 should be step-lim <= fraction of lim ~~ disc > frac *
2124  // sigma (6!)
2125  if (step - lim > cfg(WLSlipExcess))
2126  {
2127  Pass++;
2128  }
2129 
2130  // CONDITION 6 - 111312 put 6 here, its more important
2131  double ratio = (step - lim) / lim;
2132  if (cfg(Debug) >= 6)
2133  {
2134  oss << " (6)" << ratio << (ratio > cfg(WLSlipSeparation) ? ">" : "<=")
2135  << cfg(WLSlipSeparation);
2136  }
2137  if (ratio > cfg(WLSlipSeparation))
2138  {
2139  Pass++;
2140  }
2141 
2142  /* CONDITIONs 4 and 5
2143  x
2144  x x
2145  x x
2146  x x
2147  x x
2148  x x
2149  ------------------------
2150  jp=012345 jp==0 is i, the current point
2151  do for minMaxWidth pts on each side of point; best score is
2152  pass=2*minMaxWidth why is minMaxWidth used here? */
2153  double slope = (step - lim) / (8.0 * minMaxWidth);
2154  j = pass4 = pass5 = 0;
2155  jp = jm = i;
2156  do
2157  {
2158  // find next good point in future
2159  do
2160  {
2161  jp++;
2162  } while (jp < it->nend && !(spdvector[jp].flag & OK));
2163 
2164  if (jp >= it->nend)
2165  {
2166  break;
2167  }
2168 
2169  // CONDITION 4: test(A1) is a local maximum
2170  if (spdvector[i].data[A1] - spdvector[jp].data[A1] > j * slope)
2171  {
2172  pass4++;
2173  }
2174 
2175  // CONDITION 5: limit(A2) is a local minimum
2176  if (spdvector[i].data[A2] - spdvector[jp].data[A2] < -(j * slope))
2177  {
2178  pass5++;
2179  }
2180 
2181  // find next good point in past
2182  do
2183  {
2184  jm--;
2185  } while (jm > it->nbeg && !(spdvector[jm].flag & OK));
2186 
2187  if (jm <= it->nbeg)
2188  {
2189  break;
2190  }
2191  // CONDITION 4: test(A1) is a local maximum
2192  if (spdvector[i].data[A1] - spdvector[jm].data[A1] > j * slope)
2193  {
2194  pass4++;
2195  }
2196  // CONDITION 5: limit(A2) is a local minimum
2197  if (spdvector[i].data[A2] - spdvector[jm].data[A2] < -(j * slope))
2198  {
2199  pass5++;
2200  }
2201 
2202  } while (++j < minMaxWidth);
2203 
2204  // perfect = 2*minMaxWidth; allow 1 miss..
2205  if (pass4 >= 2 * minMaxWidth - 1)
2206  {
2207  Pass++;
2208  }
2209  if (cfg(Debug) >= 6)
2210  {
2211  oss << " (4)" << pass4 << (pass4 >= 2 * minMaxWidth - 1 ? ">" : "<=")
2212  << 2 * minMaxWidth - 2;
2213  }
2214 
2215  if (pass5 >= 2 * minMaxWidth - 1)
2216  {
2217  Pass++;
2218  }
2219 
2220  if (cfg(Debug) >= 6)
2221  {
2222  oss << " (5)" << pass5 << (pass5 >= 2 * minMaxWidth - 1 ? ">" : "<=")
2223  << 2 * minMaxWidth - 2;
2224  }
2225 
2226  if (Pass == 5)
2227  {
2228  if (cfg(Debug) >= 6)
2229  {
2230  oss << " possible WL slip";
2231  }
2232  isSlip = true;
2233  }
2234 
2235  // half-cycles - warning only - TD detect in GF, and fix
2236  j = 1;
2237  if (!halfCycle)
2238  { // look for half-cycle-slip > 1
2239  j = 2 * step - int(2 * step + (step > 0.0 ? 0.5 : -0.5));
2240  slope = ::fabs(2 * step - int(2 * step)); // slope is a dummy here
2241  if (j % 2 || slope < 3 * lim)
2242  {
2243  halfCycle = true;
2244  }
2245  }
2246  if (Pass >= 4 && halfCycle && j != 0)
2247  {
2248  log << "WLslip " << GDCUnique << " " << sat << " " << setw(2)
2249  << it->nseg << " " << setw(3) << i << " "
2250  << printTime(time(i), outFormat)
2251  << " Warning - possible half-cycle slip of " << j
2252  << " WL half-cycles\n";
2253  }
2254 
2255  if (cfg(Debug) >= 6)
2256  {
2257  log << oss.str() << endl;
2258  }
2259  return isSlip;
2260  }
2261  catch (Exception& e)
2262  {
2263  GNSSTK_RETHROW(e);
2264  }
2265  catch (std::exception& e)
2266  {
2267  Exception E("std except: " + string(e.what()));
2268  GNSSTK_THROW(E);
2269  }
2270  catch (...)
2271  {
2272  Exception e("Unknown exception");
2273  GNSSTK_THROW(e);
2274  }
2275 }
2276 
2277 //------------------------------------------------------------------------------------
2278 //------------------------------------------------------------------------------------
2279 /* estimate slips and adjust biases appropriately - ie fix slips - for both WL
2280  and GF merge all data into one segment */
2281 int GDCPass::fixAllSlips(string which)
2282 {
2283  try
2284  {
2285  /* find the largest segment and start there, always combine the largest
2286  with its largest neighbor */
2287  unsigned int i, nmax;
2288  list<Segment>::iterator it, kt;
2289 
2290  // loop over all segments, erasing empty ones
2291  it = SegList.begin();
2292  while (it != SegList.end())
2293  {
2294  if (it->npts <= 0)
2295  {
2296  it = SegList.erase(it);
2297  }
2298  else
2299  {
2300  it++;
2301  }
2302  }
2303 
2304  if (SegList.empty())
2305  {
2306  return NoData;
2307  }
2308 
2309  // find the largest segment
2310  for (kt = SegList.end(), nmax = 0, it = SegList.begin();
2311  it != SegList.end(); it++)
2312  {
2313  if (it->npts > nmax)
2314  {
2315  nmax = it->npts;
2316  kt = it;
2317  }
2318  }
2319 
2320  // fix all the slips, starting with the largest segment
2321  // this will merge all segments into one
2322  GDCUniqueFix = 0;
2323  while (kt != SegList.end())
2324  {
2325  fixOneSlip(kt, which);
2326  }
2327 
2328  // TD here to return should be a separate call...
2329 
2330  // now compute stats for the WL for the (single segment) whole pass
2331  kt = SegList.begin();
2332  if (which == string("WL"))
2333  { // WL
2334  WLPassStats.Reset();
2335  for (i = kt->nbeg; i <= kt->nend; i++)
2336  {
2337  if (!(spdvector[i].flag & OK))
2338  {
2339  continue;
2340  }
2341  WLPassStats.Add(spdvector[i].data[P1] - kt->bias1);
2342  }
2343  }
2344  // change the biases - reset the GFP bias so that it matches the GFR
2345  else
2346  { // GF
2347  // dumpSegments("GFFbefRebias",2,true); //temp
2348  bool first(true);
2349  for (i = kt->nbeg; i <= kt->nend; i++)
2350  {
2351  if (!(spdvector[i].flag & OK))
2352  {
2353  continue;
2354  }
2355  if (first)
2356  {
2357  first = false;
2358  kt->bias2 = spdvector[i].data[L2] + spdvector[i].data[P2];
2359  kt->bias1 = spdvector[i].data[P1];
2360  }
2361  // change the data - recompute GFR-GFP so it has one consistent bias
2362  spdvector[i].data[L1] =
2363  spdvector[i].data[L2] + spdvector[i].data[P2];
2364  }
2365  }
2366 
2367  if (cfg(Debug) >= 3)
2368  {
2369  dumpSegments(which + string("F"), 2, true); // DSCWLF DSCGFF
2370  }
2371 
2372  return ReturnOK;
2373  }
2374  catch (Exception& e)
2375  {
2376  GNSSTK_RETHROW(e);
2377  }
2378  catch (std::exception& e)
2379  {
2380  Exception E("std except: " + string(e.what()));
2381  GNSSTK_THROW(E);
2382  }
2383  catch (...)
2384  {
2385  Exception e("Unknown exception");
2386  GNSSTK_THROW(e);
2387  }
2388 }
2389 
2390 //------------------------------------------------------------------------------------
2391 /* called by fixAllSlips
2392  assume there are no empty segments in the list */
2393 void GDCPass::fixOneSlip(list<Segment>::iterator& kt, string which)
2394 {
2395  try
2396  {
2397  if (kt->npts == 0)
2398  {
2399  kt++;
2400  return;
2401  }
2402 
2403  list<Segment>::iterator left, right;
2404 
2405  /* kt points to the biggest segment
2406  define left and right to be the two segments on each side of the slip
2407  to be fixed; assume there are no empty segments in the list */
2408  right = left = kt;
2409 
2410  // choose the next segment on the right of kt
2411  right++;
2412 
2413  // choose the next segment on the left of kt
2414  if (kt != SegList.begin())
2415  {
2416  left--;
2417  }
2418  else
2419  {
2420  left = SegList.end(); // nothing on the left
2421  }
2422 
2423  // no segment left of kt and no segment right of kt - nothing to do
2424  if (left == SegList.end() && right == SegList.end())
2425  {
2426  kt = SegList.end();
2427  return;
2428  }
2429 
2430  // Always define kt to == left, as it will be returned and right will be
2431  // erased.
2432  if (left == SegList.end())
2433  { // no segment on left
2434  left = kt;
2435  }
2436  else if (right == SegList.end() // no segment on right
2437  || left->npts >= right->npts)
2438  { // or left is the bigger segment
2439  right = kt;
2440  kt = left; // fix between left and kt
2441  }
2442  else
2443  { // left and right exist, and right is bigger
2444  left = kt; // fix between kt and right
2445  }
2446 
2447  // fix the slip between left and right, making data in 'right' part of
2448  // 'left'
2449  if (which == string("WL"))
2450  {
2451  WLslipFix(left, right);
2452  }
2453  else
2454  {
2455  GFslipFix(left, right);
2456  }
2457 
2458  left->npts += right->npts;
2459  left->nend = right->nend;
2460 
2461  // always delete right, otherwise on return kt(==left) will be invalid
2462  // (ignore return value = iterator to first element after the one erased)
2463  SegList.erase(right);
2464 
2465  return;
2466  }
2467  catch (Exception& e)
2468  {
2469  GNSSTK_RETHROW(e);
2470  }
2471  catch (std::exception& e)
2472  {
2473  Exception E("std except: " + string(e.what()));
2474  GNSSTK_THROW(E);
2475  }
2476  catch (...)
2477  {
2478  Exception e("Unknown exception");
2479  GNSSTK_THROW(e);
2480  }
2481 }
2482 
2483 //------------------------------------------------------------------------------------
2484 // called by fixOneSlip
2485 void GDCPass::WLslipFix(list<Segment>::iterator& left,
2486  list<Segment>::iterator& right)
2487 {
2488  try
2489  {
2490  unsigned int i;
2491 
2492  GDCUniqueFix++;
2493 
2494  // full slip
2495  double dwl = right->bias1 + right->WLStats.Average() -
2496  (left->bias1 + left->WLStats.Average());
2497  long nwl = long(dwl + (dwl > 0 ? 0.5 : -0.5));
2498 
2499  if (cfg(Debug) >= 6)
2500  {
2501  log << "Fix " << GDCUnique << " " << sat << " " << GDCUniqueFix
2502  << " WL " << printTime(time(right->nbeg), outFormat) << " "
2503  << nwl // put integer fix after time, all 'Fix'
2504  << " " << left->nseg << "-" << right->nseg << fixed
2505  << setprecision(2) << " right: " << right->bias1 << " + "
2506  << right->WLStats.Average() << " - left: " << left->bias1 << " + "
2507  << left->WLStats.Average() << " = " << dwl << " " << nwl << endl;
2508  }
2509 
2510  /* now do the fixing - change the data in the right segment to match
2511  left's */
2512  for (i = right->nbeg; i <= right->nend; i++)
2513  {
2514  /* if(!(spdvector[i].flag & OK)) continue;
2515  'change the data' */
2516  spdvector[i].data[P1] -= nwl; // WLbias
2517  spdvector[i].data[L2] -= nwl * wl2; // GFP
2518  }
2519 
2520  /* fix the slips beyond the 'right' segment.
2521  change the data in the GFP, and change both the data and the bias in
2522  the WL. this way, WLStats is still valid, but if we change the GF bias,
2523  we will lose that information before the GF slips get fixed. */
2524  list<Segment>::iterator it = right;
2525  for (it++; it != SegList.end(); it++)
2526  {
2527  /* Use real, not int, nwl b/c rounding error in a pass with many slips
2528  can build up and produce errors. */
2529  it->bias1 -= dwl;
2530  for (i = it->nbeg; i <= it->nend; i++)
2531  {
2532  spdvector[i].data[P1] -= nwl; // WLbias
2533  spdvector[i].data[L2] -= nwl * wl2; // GFP
2534  }
2535  }
2536 
2537  // Add to slip list
2538  Slip newSlip(right->nbeg);
2539  newSlip.NWL = nwl;
2540  newSlip.msg = "WL";
2541  SlipList.push_back(newSlip);
2542 
2543  // mark it
2544  spdvector[right->nbeg].flag |= WLFIX;
2545 
2546  return;
2547  }
2548  catch (Exception& e)
2549  {
2550  GNSSTK_RETHROW(e);
2551  }
2552  catch (std::exception& e)
2553  {
2554  Exception E("std except: " + string(e.what()));
2555  GNSSTK_THROW(E);
2556  }
2557  catch (...)
2558  {
2559  Exception e("Unknown exception");
2560  GNSSTK_THROW(e);
2561  }
2562 }
2563 
2564 //------------------------------------------------------------------------------------
2565 /* fix one slip in the geometry-free phase
2566  called by fixOneSlip */
2567 void GDCPass::GFslipFix(list<Segment>::iterator& left,
2568  list<Segment>::iterator& right)
2569 {
2570  try
2571  {
2572  // use this number of data points on each side of slip
2573  const unsigned int Npts = static_cast<unsigned int>(cfg(GFFixNpts));
2574  unsigned int i, nb, ne, nl, nr;
2575  int ilast;
2576  long n1, nadj; // slip magnitude (cycles)
2577  double dn1, dnGFR;
2578  Stats<double> Lstats, Rstats;
2579 
2580  GDCUniqueFix++;
2581 
2582  // find Npts points on each side of slip
2583  nb = left->nend;
2584  i = 1;
2585  nl = 0;
2586  ilast = -1; // ilast is last good point before slip
2587  while (nb > left->nbeg && i < Npts)
2588  {
2589  if (spdvector[nb].flag & OK)
2590  {
2591  if (ilast == -1)
2592  {
2593  ilast = nb;
2594  }
2595  i++;
2596  nl++;
2597  Lstats.Add(spdvector[nb].data[L1] - left->bias2);
2598  // log << "LDATA " << nb << " " <<
2599  // spdvector[nb].data[L1]-left->bias2 << endl;
2600  }
2601  nb--;
2602  }
2603  ne = right->nbeg;
2604  i = 1;
2605  nr = 0;
2606  while (ne < right->nend && i < Npts)
2607  {
2608  if (spdvector[ne].flag & OK)
2609  {
2610  i++;
2611  nr++;
2612  Rstats.Add(spdvector[ne].data[L1] - right->bias2);
2613  // log << "RDATA " << ne << " " <<
2614  // spdvector[ne].data[L1]-right->bias2 <<endl;
2615  }
2616  ne++;
2617  }
2618 
2619  /* first estimate of n1, without biases
2620  need to use the GFR-GFP estimate here, and limit |nadj| to be well
2621  within sigmas on the stats, b/c when ionosphere is very active, GFP and
2622  GFR will both vary sharply, and fitting a polynomial to GFP is a BAD
2623  thing to do.... ultimately, GFR-GFP is accurate but noisy. rms rof
2624  should tell you how much weight to put on rof larger rof -> smaller
2625  npts and larger degree */
2626  dn1 = spdvector[right->nbeg].data[L2] - right->bias2 -
2627  (spdvector[ilast].data[L2] - left->bias2);
2628  n1 = long(dn1 + (dn1 > 0 ? 0.5 : -0.5));
2629 
2630  // estimate the slip using polynomial fits - this prints GFE data
2631  nadj = EstimateGFslipFix(left, right, nb, ne, n1);
2632 
2633  /* adjust the adjustment if it is not consistent with Lstats vs Rstats
2634  dn1+nadj - a. current best estimate
2635  Rstats.Averge()-Lstats.Average - b. estimate from stats on GFR-GFP
2636  across slip difference should be consistent with R/Lstats.StdDev if
2637  not, replace nadj with b. - dn1 */
2638  dnGFR = Rstats.Average() - Lstats.Average();
2639  if (fabs(n1 + nadj - dnGFR) > 10. * (Rstats.StdDev() + Lstats.StdDev()))
2640  {
2641  if (cfg(Debug) >= 6)
2642  {
2643  log << "GFRadjust " << GDCUnique << " " << sat << " "
2644  << GDCUniqueFix << " GF "
2645  << printTime(time(right->nbeg), outFormat) << fixed
2646  << setprecision(2) << " dbias(GFR): " << dnGFR
2647  << " n1+nadj: " << n1 + nadj;
2648  }
2649 
2650  nadj = long(dnGFR + (dnGFR > 0 ? 0.5 : -0.5)) - n1;
2651 
2652  if (cfg(Debug) >= 6)
2653  {
2654  log << " new n1+nadj: " << n1 + nadj << endl;
2655  }
2656  }
2657 
2658  // output result
2659  if (cfg(Debug) >= 6)
2660  {
2661  log << "Fix " << GDCUnique << " " << sat << " " << GDCUniqueFix
2662  << " GF " << printTime(time(right->nbeg), outFormat) << " "
2663  << nadj // put integer fix after time, all 'Fix'
2664  << fixed << setprecision(2)
2665  << " dbias: " << right->bias2 - left->bias2 << ", dn1: " << dn1
2666  << ", n1: " << n1 << ", adj: " << nadj << " indexes " << nb << " "
2667  << ne << " " << nl << " " << nr << " segs " << left->nseg << " "
2668  << right->nseg << " GFR-GFP:L: " << Lstats.N() << " "
2669  << Lstats.Average() << " " << Lstats.StdDev()
2670  << " R: " << Rstats.N() << " " << Rstats.Average() << " "
2671  << Rstats.StdDev() << " tests " << n1 + nadj - dnGFR << " "
2672  << Rstats.StdDev() + Lstats.StdDev() << endl;
2673  }
2674 
2675  // full slip, including biases
2676  dn1 += right->bias2 - left->bias2;
2677  n1 = long(dn1 + (dn1 > 0 ? 0.5 : -0.5));
2678  n1 += nadj;
2679 
2680  /* now do the fixing : 'change the data' within right segment
2681  and through the end of the pass, to fix the slip */
2682  for (i = right->nbeg; i < static_cast<int>(size()); i++)
2683  {
2684  spdvector[i].data[L2] -= n1; // GFP
2685  spdvector[i].data[L1] -= n1; // GFR+GFP
2686  }
2687 
2688  /* 'change the bias' for all segments in the future (although right to be
2689  deleted) */
2690  list<Segment>::iterator kt;
2691  for (kt = right; kt != SegList.end(); kt++)
2692  kt->bias2 -= n1;
2693 
2694  // Add to slip list, but if one exists with same time tag, use it instead
2695  list<Slip>::iterator jt;
2696  for (jt = SlipList.begin(); jt != SlipList.end(); jt++)
2697  if (jt->index == right->nbeg)
2698  {
2699  break;
2700  }
2701 
2702  if (jt == SlipList.end())
2703  {
2704  Slip newSlip(right->nbeg);
2705  newSlip.N1 = -n1;
2706  newSlip.msg = "GF only";
2707  SlipList.push_back(newSlip);
2708  }
2709  else
2710  {
2711  jt->N1 = -n1;
2712  jt->msg += string(" GF");
2713  }
2714 
2715  // mark it
2716  spdvector[right->nbeg].flag |= GFFIX;
2717 
2718  return;
2719  }
2720  catch (Exception& e)
2721  {
2722  GNSSTK_RETHROW(e);
2723  }
2724  catch (std::exception& e)
2725  {
2726  Exception E("std except: " + string(e.what()));
2727  GNSSTK_THROW(E);
2728  }
2729  catch (...)
2730  {
2731  Exception e("Unknown exception");
2732  GNSSTK_THROW(e);
2733  }
2734 }
2735 
2736 //------------------------------------------------------------------------------------
2737 /* called by GFslipFix
2738  estimate GF slip using polynomial fit to data around it */
2739 long GDCPass::EstimateGFslipFix(list<Segment>::iterator& left,
2740  list<Segment>::iterator& right, unsigned int nb,
2741  unsigned int ne, long n1)
2742 {
2743  try
2744  {
2745  bool quit;
2746  unsigned int i, k, in[3];
2747  double rof, rmsrof[3];
2748  PolyFit<double> PF[3];
2749 
2750  // start at zero and limit |nadj| to ...TD
2751  long nadj(0);
2752 
2753  // use a little indirect indexing array to avoid having to copy PolyFit
2754  // objects....
2755  for (k = 0; k < 3; k++)
2756  {
2757  in[k] = k;
2758  PF[in[k]].Reset(int(cfg(GFFixDegree)));
2759  }
2760 
2761  while (1)
2762  {
2763  // compute 3 polynomial fits to this data, with slips of
2764  // (nadj-1, nadj and nadj+1) wavelengths added to left segment
2765  for (k = 0; k < 3; k++)
2766  {
2767  if (PF[in[k]].N() > 0)
2768  {
2769  continue;
2770  }
2771 
2772  // add all the data
2773  for (i = nb; i <= ne; i++)
2774  {
2775  if (!(spdvector[i].flag & OK))
2776  {
2777  continue;
2778  }
2779  PF[in[k]].Add(
2780  // data
2781  spdvector[i].data[L2]
2782  // - (either left bias - poss. slip : right
2783  // bias)
2784  - (i < right->nbeg ? left->bias2 - n1 - (nadj + k - 1)
2785  : right->bias2),
2786  // use a debiased count
2787  spdvector[i].ndt - spdvector[nb].ndt);
2788  }
2789 
2790  // TD check that it not singular
2791 
2792  // compute RMS residual of fit
2793  rmsrof[in[k]] = 0.0;
2794  for (i = nb; i <= ne; i++)
2795  {
2796  if (!(spdvector[i].flag & OK))
2797  {
2798  continue;
2799  }
2800  rof = // data minus fit
2801  spdvector[i].data[L2] -
2802  (i < right->nbeg ? left->bias2 - n1 - (nadj + k - 1)
2803  : right->bias2) -
2804  PF[in[k]].Evaluate(spdvector[i].ndt - spdvector[nb].ndt);
2805  rmsrof[in[k]] += rof * rof;
2806  }
2807  rmsrof[in[k]] = ::sqrt(rmsrof[in[k]]);
2808 
2809  } // end loop over fits
2810 
2811  // the value of this is questionable, b/c with active ionosphere the
2812  // real GFP is NOT smooth
2813  for (quit = false, k = 0; k < 3; k++)
2814  if (rmsrof[in[k]] > cfg(GFFixMaxRMS))
2815  {
2816  log << "Warning - large RMS ROF in GF slip fix at in,k = "
2817  << in[k] << " " << k << " " << rmsrof[in[k]] << " abort.\n";
2818  quit = true;
2819  }
2820  if (quit)
2821  {
2822  break;
2823  }
2824 
2825  /* three cases: (TD - exceptions?) :
2826  rmsrof: 0 > 1 < 2 good
2827  0 > 1 > 2 shift 0,1,2 to 1,2,3
2828  0 < 1 < 2 shift 0,1,2 to -1,0,1
2829  0 < 1 > 2 local max! - ?? */
2830  if (rmsrof[in[0]] > rmsrof[in[1]])
2831  {
2832  if (rmsrof[in[1]] < rmsrof[in[2]])
2833  { // local min - done
2834  // if(cfg(Debug) >= 6) log << " done." << endl;
2835  break;
2836  }
2837  else
2838  { // shift 0,1,2 to 1,2,3
2839  k = in[0];
2840  in[0] = in[1];
2841  in[1] = in[2];
2842  in[2] = k;
2843  PF[in[2]].Reset();
2844  nadj += 1;
2845  // if(cfg(Debug) >= 6) log << " shift left" << endl;
2846  }
2847  }
2848  else
2849  {
2850  if (rmsrof[in[1]] < rmsrof[in[2]])
2851  { // shift 0,1,2 to -1,0,1
2852  k = in[2];
2853  in[2] = in[1];
2854  in[1] = in[0];
2855  in[0] = k;
2856  PF[in[0]].Reset();
2857  nadj -= 1;
2858  // if(cfg(Debug) >= 6) log << " shift right" << endl;
2859  }
2860  else
2861  { // local max
2862  log << "Warning - local maximum in RMS residuals in "
2863  "EstimateGFslipFix"
2864  << endl;
2865  // TD do something
2866  break;
2867  }
2868  }
2869 
2870  } // end while loop
2871 
2872  // dump the raw data with all the fits
2873  if (cfg(Debug) >= 4)
2874  {
2875  log << "EstimateGFslipFix dump " << endl;
2876  for (i = nb; i <= ne; i++)
2877  {
2878  if (!(spdvector[i].flag & OK))
2879  {
2880  continue;
2881  }
2882  log << "GFE " << GDCUnique << " " << sat << " " << GDCUniqueFix
2883  << " " << printTime(time(i), outFormat) << " " << setw(2)
2884  << spdvector[i].flag << fixed << setprecision(3);
2885  for (k = 0; k < 3; k++)
2886  log << " "
2887  << spdvector[i].data[L2] -
2888  (i < right->nbeg ? left->bias2 - n1 - (nadj + k - 1)
2889  : right->bias2)
2890  << " "
2891  << PF[in[k]].Evaluate(spdvector[i].ndt - spdvector[nb].ndt);
2892  log << " " << setw(3) << spdvector[i].ndt << endl;
2893  }
2894  }
2895 
2896  return nadj;
2897  }
2898  catch (Exception& e)
2899  {
2900  GNSSTK_RETHROW(e);
2901  }
2902  catch (std::exception& e)
2903  {
2904  Exception E("std except: " + string(e.what()));
2905  GNSSTK_THROW(E);
2906  }
2907  catch (...)
2908  {
2909  Exception e("Unknown exception");
2910  GNSSTK_THROW(e);
2911  }
2912 }
2913 
2914 //------------------------------------------------------------------------------------
2915 //------------------------------------------------------------------------------------
2916 /* 07202010 not used fit a polynomial to the GF range,
2917  change the units of -gfr(P2) and gfp(L2) to cycles of wlgf (=5.4cm) */
2919 {
2920  try
2921  {
2922  bool first;
2923  int i, nbeg, nend;
2924 
2925  // decide on the degree of fit
2926  nbeg = SegList.begin()->nbeg;
2927  nend = SegList.begin()->nend;
2928 
2929  for (first = true, i = nbeg; i <= nend; i++)
2930  {
2931  if (!(spdvector[i].flag & OK))
2932  {
2933  continue;
2934  }
2935 
2936  /* 'change the bias' (initial bias only) in the GFP by changing units,
2937  also slip fixing in the WL may have changed the values of GFP */
2938  if (first)
2939  {
2940  SegList.begin()->bias2 /= wlgf;
2941  first = false;
2942  }
2943 
2944  /* 'change the arrays'
2945  change units on the GFP and the GFR */
2946  spdvector[i].data[P2] /= wlgf; // -gfr (cycles of wlgf)
2947  spdvector[i].data[L2] /= wlgf; // gfp (cycles of wlgf)
2948 
2949  /* 'change the data'
2950  save in L1 // gfp+gfr residual (cycles of
2951  wlgf) */
2952  spdvector[i].data[L1] = spdvector[i].data[L2] - spdvector[i].data[P2];
2953  }
2954 
2955  return ReturnOK;
2956  }
2957  catch (Exception& e)
2958  {
2959  GNSSTK_RETHROW(e);
2960  }
2961  catch (std::exception& e)
2962  {
2963  Exception E("std except: " + string(e.what()));
2964  GNSSTK_THROW(E);
2965  }
2966  catch (...)
2967  {
2968  Exception e("Unknown exception");
2969  GNSSTK_THROW(e);
2970  }
2971 }
2972 
2973 //------------------------------------------------------------------------------------
2974 //------------------------------------------------------------------------------------
2975 // detect slips in the geometry-free phase
2977 {
2978  try
2979  {
2980  unsigned int i;
2981  int iret;
2982  list<Segment>::iterator it;
2983 
2984  // places first difference of GF in A1 - 'change the arrays' A1
2985  if ((iret = detectObviousSlips("GF")))
2986  {
2987  return iret;
2988  }
2989 
2990  GFPassStats.Reset();
2991  for (it = SegList.begin(); it != SegList.end(); it++)
2992  {
2993  // compute stats on dGF/dt
2994  for (i = it->nbeg; i <= it->nend; i++)
2995  {
2996  if (!(spdvector[i].flag & OK))
2997  {
2998  continue;
2999  }
3000 
3001  /* compute first-diff stats in meters
3002  skip the first point in a segment - it is an obvious GF slip */
3003  if (i > it->nbeg)
3004  {
3006  }
3007 
3008  } // end loop over data in segment it
3009 
3010  // check number of good points
3011  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
3012  {
3013  deleteSegment(it, "insufficient data in segment");
3014  continue;
3015  }
3016 
3017  /* fit polynomial to GFR in each segment
3018  compute (1stD of) fit residual GFP-fit(GFR) -> A1 - 'change the
3019  arrays' A1 delete segment if polynomial is singular - probably due
3020  to too little data */
3021  if ((iret = GFphaseResiduals(it)))
3022  {
3023  deleteSegment(it, "polynomial fit to GF residual failed");
3024  continue;
3025  }
3026  }
3027 
3028  /* 'change the arrays'
3029  at this point:
3030  L1 = GFP+GFR in cycles, by prepareGFdata()
3031  L2 = GFP in cycles, by prepareGFdata()
3032  P1 = wlbias
3033  P2 = -GFR in cycles, by prepareGFdata()
3034  A1 = GFP-(local fit) OR its 1stD, by GFphaseResiduals()
3035  (was 1stD of GFP+GFR (in L1), by firstDifferences())
3036  A2 = 1stD of GFP (in L2), by firstDifferences() */
3037  if ((iret = detectGFsmallSlips()))
3038  {
3039  return iret;
3040  }
3041 
3042  // delete all segments that are too small
3043  for (it = SegList.begin(); it != SegList.end(); it++)
3044  {
3045  if (it->npts < static_cast<unsigned int>(cfg(MinPts)))
3046  {
3047  deleteSegment(it, "insufficient data in segment");
3048  }
3049  }
3050 
3051  if (cfg(Debug) >= 4)
3052  {
3053  dumpSegments("GFD", 2, true);
3054  }
3055 
3056  return ReturnOK;
3057  }
3058  catch (Exception& e)
3059  {
3060  GNSSTK_RETHROW(e);
3061  }
3062  catch (std::exception& e)
3063  {
3064  Exception E("std except: " + string(e.what()));
3065  GNSSTK_THROW(E);
3066  }
3067  catch (...)
3068  {
3069  Exception e("Unknown exception");
3070  GNSSTK_THROW(e);
3071  }
3072 }
3073 
3074 //------------------------------------------------------------------------------------
3075 /* for each segment, fit a polynomial to the gfr, then compute and store the
3076  residual of fit */
3077 int GDCPass::GFphaseResiduals(list<Segment>::iterator& it)
3078 {
3079  try
3080  {
3081  unsigned int i;
3082  int ndeg, nprev;
3083  double fit, rbias, prev, tmp;
3084  Stats<double> rofStats;
3085 
3086  // decide on the degree of fit
3087  ndeg = 2 + int(0.5 + (it->nend - it->nbeg + 1) * cfg(DT) / 3000.0);
3088  // if(ndeg > int(cfg(GFPolyMaxDegree))) ndeg = int(cfg(GFPolyMaxDegree));
3089  if (ndeg > 6)
3090  {
3091  ndeg = 6;
3092  }
3093  if (ndeg < 2)
3094  {
3095  ndeg = 2;
3096  }
3097 
3098  it->PF.Reset(ndeg); // for fit to GF range
3099 
3100  for (i = it->nbeg; i <= it->nend; i++)
3101  {
3102  if (!(spdvector[i].flag & OK))
3103  {
3104  continue;
3105  }
3106  it->PF.Add(spdvector[i].data[P2], spdvector[i].ndt);
3107  }
3108 
3109  if (it->PF.isSingular())
3110  { // this should never happen
3111  log << "Polynomial fit to GF range is singular in segment " << it->nseg
3112  << "! .. abort." << endl;
3113  return Singular;
3114  }
3115 
3116  // now compute the residual of fit
3117  rbias = prev = 0.0;
3118  rofStats.Reset();
3119  for (i = it->nbeg; i <= it->nend; i++)
3120  {
3121  // skip bad data
3122  if (!(spdvector[i].flag & OK))
3123  {
3124  continue;
3125  }
3126 
3127  fit = it->PF.Evaluate(spdvector[i].ndt);
3128 
3129  /* all (fit, resid, gfr and gfp) are in cycles of wlgf (5.4cm)
3130 
3131  compute gfp-(fit to gfr), store in A1 - 'change the arrays' A1 and
3132  A2 OR let's try first difference of residual of fit
3133  residual = phase - fit to
3134  range */
3135  spdvector[i].data[A1] = spdvector[i].data[L2] - it->bias2 - fit;
3136  if (rbias == 0.0)
3137  {
3138  rbias = spdvector[i].data[A1];
3139  nprev = spdvector[i].ndt - 1;
3140  }
3141  spdvector[i].data[A1] -= rbias; // debias residual for plots
3142 
3143  // compute stats on residual of fit
3144  rofStats.Add(spdvector[i].data[A1]);
3145 
3146  if (1)
3147  { // 1stD of residual - remember A1 has just been debiased
3148  tmp = spdvector[i].data[A1];
3149  spdvector[i].data[A1] -= prev; // diff with previous epoch's
3150  // 040809 should this be divided by delta n?
3151  // spdvector[i].data[A1] /= (spdvector[i].ndt - nprev);
3152  prev = tmp; // store residual for next point
3153  nprev = spdvector[i].ndt;
3154  }
3155  }
3156 
3157  return ReturnOK;
3158  }
3159  catch (Exception& e)
3160  {
3161  GNSSTK_RETHROW(e);
3162  }
3163  catch (std::exception& e)
3164  {
3165  Exception E("std except: " + string(e.what()));
3166  GNSSTK_THROW(E);
3167  }
3168  catch (...)
3169  {
3170  Exception e("Unknown exception");
3171  GNSSTK_THROW(e);
3172  }
3173 }
3174 
3175 //------------------------------------------------------------------------------------
3176 /* detect small slips in the geometry-free phase
3177  TD outliers at the beginning or end of the segment.... */
3179 {
3180  try
3181  {
3182  const unsigned int width = static_cast<unsigned int>(cfg(GFSlipWidth));
3183  int i, j, iplus, inew, ifirst, nok;
3184  list<Segment>::iterator it;
3185  Stats<double> pastStats, futureStats;
3186 
3187  // loop over segments
3188  for (it = SegList.begin(); it != SegList.end(); it++)
3189  {
3190 
3191  if (it->npts < 2 * width + 1)
3192  {
3193  continue;
3194  }
3195 
3196  /* Cartoon of the GF 'two-pane moving window'
3197  point of interest:|
3198  windows: 'past window' | 'future window'
3199  stats : pastStats | futureStats (5 pts in each window)
3200  data : ... x (x x x x x) x (x x x x x) x ...
3201  | | |
3202  indexes: j i iplus */
3203 
3204  deque<int> pastIndex, futureIndex;
3205  pastStats.Reset();
3206  futureStats.Reset();
3207  i = inew = ifirst = -1;
3208  nok = 0; // recount
3209 
3210  // loop over points in the segment
3211  for (iplus = static_cast<int>(it->nbeg);
3212  iplus <= static_cast<int>(it->nend + width); iplus++)
3213  {
3214  // ignore bad points
3215  if (iplus <= static_cast<int>(it->nend) &&
3216  !(spdvector[iplus].flag & OK))
3217  {
3218  continue;
3219  }
3220  if (ifirst == -1)
3221  {
3222  ifirst = iplus;
3223  }
3224 
3225  // pop the new i from the future
3226  if (static_cast<int>(futureIndex.size()) == width ||
3227  iplus > static_cast<int>(it->nend))
3228  {
3229  inew = futureIndex.front();
3230  futureIndex.pop_front();
3231  futureStats.Subtract(spdvector[inew].data[A1]);
3232  nok++;
3233  }
3234 
3235  // put iplus into the future deque
3236  if (iplus <= static_cast<int>(it->nend))
3237  {
3238  futureIndex.push_back(iplus);
3239  futureStats.Add(spdvector[iplus].data[A1]);
3240  }
3241  else
3242  {
3243  futureIndex.push_back(-1);
3244  }
3245 
3246  /* check for outliers
3247  we now have:
3248  ( past ) ( future )
3249  data : ... x (x x x x x) x x (x x x x x) x ...
3250  | | |
3251  indexes: i inew iplus
3252  outlier if: (i,inew) = opposite signs but ~= large magnitude
3253  if found, mark i bad and replace A1(inew) = A1(inew)+A1(i) */
3254  if (foundGFoutlier(i, inew, pastStats, futureStats))
3255  {
3256  /* check that i was not marked a slip in the last iteration
3257  if so, let inew be the slip and i the outlier */
3258  if (spdvector[i].flag & DETECT)
3259  {
3260  /* log << "Warning - marking a slip point BAD in GF detect
3261  small "
3262  << GDCUnique << " " << sat
3263  << " " << printTime(time(i),outFormat) << " " << i <<
3264  endl; */
3265  spdvector[inew].flag = spdvector[i].flag;
3266  it->nbeg = inew;
3267  }
3268  spdvector[i].flag = BAD;
3269  spdvector[inew].data[A1] += spdvector[i].data[A1];
3270  learn["points deleted: GF outlier"]++;
3271  i = inew;
3272  nok--;
3273  }
3274 
3275  // pop last from past
3276  if (static_cast<int>(pastIndex.size()) == width)
3277  {
3278  j = pastIndex.front();
3279  pastIndex.pop_front();
3280  pastStats.Subtract(spdvector[j].data[A1]);
3281  }
3282 
3283  // move i into the past
3284  if (i > -1)
3285  {
3286  pastIndex.push_back(i);
3287  pastStats.Add(spdvector[i].data[A1]);
3288  }
3289 
3290  // return to original state
3291  i = inew;
3292 
3293  // test for slip .. foundGF...prints to log
3294  if (foundGFsmallSlip(i, it->nseg, it->nend, it->nbeg, pastIndex,
3295  futureIndex, pastStats, futureStats))
3296  {
3297 
3298  // create a new segment
3299  it->npts = nok - 1;
3300  it = createSegment(it, i, "GF slip small");
3301  nok = 1;
3302 
3303  // mark it
3304  spdvector[i].flag |= GFDETECT;
3305  }
3306 
3307  } // end loop over points in the pass
3308  it->npts = nok;
3309 
3310  } // end loop over segments
3311 
3312  return ReturnOK;
3313  }
3314  catch (Exception& e)
3315  {
3316  GNSSTK_RETHROW(e);
3317  }
3318  catch (std::exception& e)
3319  {
3320  Exception E("std except: " + string(e.what()));
3321  GNSSTK_THROW(E);
3322  }
3323  catch (...)
3324  {
3325  Exception e("Unknown exception");
3326  GNSSTK_THROW(e);
3327  }
3328 }
3329 
3330 //------------------------------------------------------------------------------------
3331 bool GDCPass::foundGFoutlier(int i, int inew, Stats<double>& pastSt,
3332  Stats<double>& futureSt)
3333 {
3334  try
3335  {
3336  if (i < 0 || inew < 0)
3337  {
3338  return false;
3339  }
3340  bool ok;
3341  double pmag = spdvector[i].data[A1]; // -pastSt.Average();
3342  double fmag = spdvector[inew].data[A1]; // -futureSt.Average();
3343  double var = ::sqrt(pastSt.Variance() + futureSt.Variance());
3344 
3345  ostringstream oss;
3346  if (cfg(Debug) >= 6)
3347  {
3348  oss << "GFoutlier " << GDCUnique << " " << sat << " " << setw(3)
3349  << inew << " " << printTime(time(inew), outFormat) << fixed
3350  << setprecision(3) << " p,fave=" << fabs(pmag) << "," << fabs(fmag)
3351  << " var=" << var << " snr=" << fabs(pmag) / var << ","
3352  << fabs(fmag) / var;
3353  }
3354 
3355  bool isOut = true;
3356  for (;;)
3357  {
3358 
3359  // 1. signs must be opposite
3360  if (pmag * fmag >= 0)
3361  {
3362  isOut = false;
3363  }
3364  if (cfg(Debug) >= 6)
3365  {
3366  oss << " (1)" << (isOut ? "ok" : "no");
3367  }
3368  if (!isOut)
3369  {
3370  break;
3371  }
3372 
3373  // 2. magnitudes must be large compared to noise
3374  double noise = cfg(GFSlipOutlier) * var;
3375  if (fabs(pmag) < noise || fabs(fmag) < noise)
3376  {
3377  isOut = false;
3378  }
3379  if (cfg(Debug) >= 6)
3380  {
3381  oss << " (2)" << fabs(pmag) / var << "or" << fabs(fmag) / var
3382  << (isOut ? ">=" : "<") << cfg(GFSlipOutlier);
3383  }
3384  if (!isOut)
3385  {
3386  break;
3387  }
3388 
3389  if (cfg(Debug) >= 6)
3390  {
3391  oss << " possible GF outlier";
3392  }
3393 
3394  break;
3395  } // end for(;;)
3396 
3397  if (cfg(Debug) >= 6)
3398  {
3399  log << oss.str() << endl;
3400  }
3401 
3402  return isOut;
3403  }
3404  catch (Exception& e)
3405  {
3406  GNSSTK_RETHROW(e);
3407  }
3408  catch (std::exception& e)
3409  {
3410  Exception E("std except: " + string(e.what()));
3411  GNSSTK_THROW(E);
3412  }
3413  catch (...)
3414  {
3415  Exception e("Unknown exception");
3416  GNSSTK_THROW(e);
3417  }
3418 }
3419 
3420 //------------------------------------------------------------------------------------
3421 /* Better to find too many small ones than to miss them, since the fixing
3422  algorithm will most likely refuse to act on the questionable ones. */
3423 bool GDCPass::foundGFsmallSlip(int i, int nseg, int iend, int ibeg,
3424  deque<int>& pastIn, deque<int>& futureIn,
3425  Stats<double>& pastSt, Stats<double>& futureSt)
3426 {
3427  try
3428  {
3429  if (i < 0)
3430  {
3431  return false;
3432  }
3433 
3434  int j, k;
3435  double mag, pmag, fmag, pvar, fvar;
3436 
3437  pmag = fmag = pvar = fvar = 0.0;
3438  // note when past.N == 1, this is first good point, which has 1stD==0
3439  // TD be very careful when N is small
3440  if (pastSt.N() > 0)
3441  {
3442  pmag = spdvector[i].data[A1] - pastSt.Average();
3443  }
3444  if (futureSt.N() > 0)
3445  {
3446  fmag = spdvector[i].data[A1] - futureSt.Average();
3447  }
3448  if (pastSt.N() > 1)
3449  {
3450  pvar = pastSt.Variance();
3451  }
3452  if (futureSt.N() > 1)
3453  {
3454  fvar = futureSt.Variance();
3455  }
3456  mag = (pmag + fmag) / 2.0;
3457 
3458  if (cfg(Debug) >= 6)
3459  {
3460  log << "GFS " << GDCUnique << " " << sat << " " << nseg << " "
3461  << printTime(time(i), outFormat)
3462  //<< " P( " << setw(3) << pastIn[0] // don't print
3463  //this...
3464  //<< " " << setw(3) << pastIn[1]
3465  //<< " " << setw(3) << pastIn[2]
3466  //<< " " << setw(3) << pastIn[3]
3467  //<< " " << setw(3) << pastIn[4]
3468  //<< ") " << setw(3) << i
3469  //<< " F( " << setw(3) << futureIn[0]
3470  //<< " " << setw(3) << futureIn[1]
3471  //<< " " << setw(3) << futureIn[2]
3472  //<< " " << setw(3) << futureIn[3]
3473  //<< " " << setw(3) << futureIn[4] << ")" // ...to here
3474  << fixed << setprecision(3) << " " << setw(3) << pastSt.N() << " "
3475  << setw(7) << pastSt.Average() << " " << setw(7) << pastSt.StdDev()
3476  << " " << setw(3) << futureSt.N() << " " << setw(7)
3477  << futureSt.Average() << " " << setw(7) << futureSt.StdDev() << " "
3478  << setw(7) << mag << " " << setw(7) << ::sqrt(pvar + fvar) << " "
3479  << setw(9) << spdvector[i].data[A1] << " " << setw(7) << pmag
3480  << " " << setw(7) << pvar << " " << setw(7) << fmag << " "
3481  << setw(7) << fvar << " " << setw(3) << i << endl;
3482  }
3483 
3484  /* x -- mag
3485 
3486  x x x x - step
3487  x x x x --- */
3488  const double minMag = cfg(GFSlipSize); // minimum slip magnitude
3489  const double STN =
3490  cfg(GFSlipStepToNoise); // step (past->future) to noise ratio
3491  const double MTS = cfg(GFSlipToStep); // magnitude to step ratio
3492  const double MTN = cfg(GFSlipToNoise); // magnitude to noise ratio
3493  const int Edge = int(cfg(GFSlipEdge)); // number of points before edge
3494  const double RangeCheckLimit = 2 * cfg(WLSigma) / (0.83 * wlgf);
3495  // 2 * range noise in units of wlgf
3496  const double snr = fabs(pmag - fmag) / ::sqrt(pvar + fvar);
3497  // slip to noise ratio
3498 
3499  // 050109 if Debug=6, print only possible slips, if 7 print all
3500  bool isSlip = true;
3501  ostringstream oss;
3502 
3503  for (;;)
3504  {
3505  // NB last printed test is a failure unless it says possible GF slip
3506  if (cfg(Debug) >= 6)
3507  {
3508  oss << "GFslip " << GDCUnique << " " << sat << " " << nseg << " "
3509  << setw(3) << i << " " << printTime(time(i), outFormat) << fixed
3510  << setprecision(3) << " mag=" << mag
3511  << " snr=" << snr; // no endl
3512  }
3513 
3514  // 0. if WL slip here - ...?
3515 
3516  // 1. slip must be non-trivial
3517  if (fabs(mag) <= minMag)
3518  {
3519  isSlip = false;
3520  }
3521  if (cfg(Debug) >= 6)
3522  {
3523  oss << " (1)|" << mag << (isSlip ? "|>" : "|<=") << minMag;
3524  }
3525  if (!isSlip)
3526  {
3527  break;
3528  }
3529 
3530  // 2. change in average is larger than noise
3531  if (snr <= STN)
3532  {
3533  isSlip = false;
3534  }
3535  if (cfg(Debug) >= 6)
3536  {
3537  oss << " (2)" << snr << (isSlip ? ">" : "<=") << STN;
3538  }
3539  if (!isSlip)
3540  {
3541  break;
3542  }
3543 
3544  // 3. slip is large compared to change in average
3545  if (fabs(mag) <= MTS * fabs(pmag - fmag))
3546  {
3547  isSlip = false;
3548  }
3549  if (cfg(Debug) >= 6)
3550  {
3551  oss << " (3)" << fabs(mag / (pmag - fmag)) << (isSlip ? ">" : "<=")
3552  << MTS;
3553  }
3554  if (!isSlip)
3555  {
3556  break;
3557  }
3558 
3559  // 4. magnitude is large compared to noise: a 3-sigma slip
3560  if (fabs(mag) <= MTN * ::sqrt(pvar + fvar))
3561  {
3562  isSlip = false;
3563  }
3564  if (cfg(Debug) >= 6)
3565  {
3566  oss << " (4)" << fabs(mag) / ::sqrt(pvar + fvar)
3567  << (isSlip ? ">" : "<=") << MTN;
3568  }
3569  if (!isSlip)
3570  {
3571  break;
3572  }
3573 
3574  // 5. if very close to edge, declare it an outlier
3575  if (static_cast<int>(pastSt.N()) < Edge ||
3576  static_cast<int>(futureSt.N()) < Edge + 1)
3577  {
3578  isSlip = false;
3579  }
3580  if (cfg(Debug) >= 6)
3581  {
3582  oss << " (5)" << pastSt.N() << "," << futureSt.N()
3583  << (isSlip ? ">" : "<") << Edge;
3584  }
3585  if (!isSlip)
3586  {
3587  break;
3588  }
3589 
3590  // 6. large slips (compared to range noise): check the GFR-GFP for
3591  // consistency
3592  if (fabs(mag) > RangeCheckLimit)
3593  {
3594  double magGFR, mtnGFR;
3595  Stats<double> pGFRmPh, fGFRmPh;
3596  for (j = 0; j < static_cast<int>(pastIn.size()); j++)
3597  {
3598  if (pastIn[j] > -1)
3599  {
3600  pGFRmPh.Add(spdvector[pastIn[j]].data[L1]);
3601  }
3602  if (futureIn[j] > -1)
3603  {
3604  fGFRmPh.Add(spdvector[futureIn[j]].data[L1]);
3605  }
3606  }
3607  magGFR = fGFRmPh.Average() - pGFRmPh.Average();
3608  mtnGFR =
3609  fabs(magGFR) / ::sqrt(pGFRmPh.Variance() + fGFRmPh.Variance());
3610 
3611  if (cfg(Debug) >= 6)
3612  {
3613  oss << "; GFR-GFP has mag: " << magGFR
3614  << ", |dmag|: " << fabs(mag - magGFR) << " and mag/noise "
3615  << mtnGFR;
3616  }
3617 
3618  if (fabs(mag - magGFR) > fabs(magGFR))
3619  {
3620  isSlip = false;
3621  }
3622  if (cfg(Debug) >= 6)
3623  {
3624  oss << " (6a)" << fabs(mag - magGFR) << (isSlip ? "<=" : ">")
3625  << fabs(magGFR);
3626  }
3627  if (!isSlip)
3628  {
3629  break;
3630  }
3631 
3632  if (mtnGFR < 3)
3633  {
3634  isSlip = false;
3635  }
3636  if (cfg(Debug) >= 6)
3637  {
3638  oss << " (6b)" << mtnGFR << "><3:can" << (isSlip ? "" : "not")
3639  << "_see_in_GFR";
3640  }
3641  if (!isSlip)
3642  {
3643  break;
3644  }
3645  }
3646 
3647  // 7. small slips (compared to variations in dGF): extra careful
3648  // TD beware of small slips in the presence of noise >~ 1
3649  else
3650  { // if(fabs(mag) <= RangeCheckLimit)
3651  double magFD;
3652  Stats<double> fdStats;
3653  j = i - 1;
3654  k = 0;
3655  while (j >= ibeg && k < 15)
3656  {
3657  if (spdvector[j].flag & OK)
3658  {
3659  fdStats.Add(spdvector[j].data[A2]);
3660  k++;
3661  }
3662  j--;
3663  }
3664  j = i + 1;
3665  k = 0;
3666  while (j <= iend && k < 15)
3667  {
3668  if (spdvector[j].flag & OK)
3669  {
3670  fdStats.Add(spdvector[j].data[A2]);
3671  k++;
3672  }
3673  j++;
3674  }
3675  magFD = spdvector[i].data[A2] - fdStats.Average();
3676 
3677  if (cfg(Debug) >= 6)
3678  {
3679  oss << " (7)1stD(GFP)mag=" << magFD
3680  << ",noise=" << fdStats.StdDev()
3681  << ",snr=" << fabs(magFD) / fdStats.StdDev()
3682  << ",maxima=" << fdStats.Minimum() << ","
3683  << fdStats.Maximum();
3684  }
3685  }
3686 
3687  // 8. if switch is on and there is no WL slip here - skip
3688  if (cfg(GFSkipSmall) && !(spdvector[i].flag & WLDETECT))
3689  {
3690  if (cfg(Debug) >= 6)
3691  {
3692  oss << " (8)skipGFsmall";
3693  }
3694  isSlip = false;
3695  }
3696 
3697  break;
3698  } // end for(;;)
3699 
3700  if (isSlip)
3701  {
3702  oss << " possible GF slip";
3703  }
3704  else
3705  {
3706  oss << " not a GF slip";
3707  }
3708  if (cfg(Debug) >= 6)
3709  {
3710  log << oss.str() << endl;
3711  }
3712 
3713  return isSlip;
3714  }
3715  catch (Exception& e)
3716  {
3717  GNSSTK_RETHROW(e);
3718  }
3719  catch (std::exception& e)
3720  {
3721  Exception E("std except: " + string(e.what()));
3722  GNSSTK_THROW(E);
3723  }
3724  catch (...)
3725  {
3726  Exception e("Unknown exception");
3727  GNSSTK_THROW(e);
3728  }
3729 }
3730 
3731 //------------------------------------------------------------------------------------
3732 //------------------------------------------------------------------------------------
3733 /* check the consistency of WL slips where a GF slip, but not a WL slip, was
3734  detected. */
3736 {
3737  try
3738  {
3739  int i, k;
3740  const int N = 2 * int(cfg(WLWindowWidth));
3741  double mag, absmag, factor = wl2 / wlgf;
3742 
3743  // loop over the data and look for points with GFDETECT but not WLDETECT
3744  // or WLFIX
3745  for (i = 0; i < static_cast<int>(size()); i++)
3746  {
3747 
3748  if (!(spdvector[i].flag & OK))
3749  {
3750  continue; // bad
3751  }
3752  if (!(spdvector[i].flag & DETECT))
3753  {
3754  continue; // no slips
3755  }
3756  if (spdvector[i].flag & WLDETECT)
3757  {
3758  continue; // WL was detected
3759  }
3760 
3761  // GF only slip - compute WL stats on both sides
3762  Stats<double> futureStats, pastStats;
3763  k = i;
3764  // fill future
3765  while (k < static_cast<int>(size()) &&
3766  static_cast<int>(futureStats.N()) < N)
3767  {
3768  if (spdvector[k].flag & OK) // data is good
3769  {
3770  futureStats.Add(spdvector[k].data[P1]); // wlbias
3771  }
3772  k++;
3773  }
3774  // fill past
3775  k = i - 1;
3776  while (k >= 0 && static_cast<int>(pastStats.N()) < N)
3777  {
3778  if (spdvector[k].flag & OK) // data is good
3779  {
3780  pastStats.Add(spdvector[k].data[P1]); // wlbias
3781  }
3782  k--;
3783  }
3784 
3785  /* is there a WL slip here?
3786  1. magnitude of slip > 0.75
3787  2. magnitude is > stddev on both sides
3788  3. N() > 10 on both sides TD?? */
3789  mag = futureStats.Average() - pastStats.Average();
3790  absmag = fabs(mag);
3791 
3792  if (absmag > cfg(WLSlipSize) && absmag > pastStats.StdDev() &&
3793  absmag > futureStats.StdDev())
3794  {
3795  long nwl;
3796  nwl = long(mag + (mag > 0 ? 0.5 : -0.5));
3797 
3798  if (nwl == 0)
3799  {
3800  continue;
3801  }
3802 
3803  // now do the fixing - change the data to the future of the slip
3804  for (k = i; k < static_cast<int>(size()); k++)
3805  {
3806  /* if(!(spdvector[i].flag & OK)) continue;
3807  'change the data' */
3808  spdvector[k].data[P1] -= nwl; // WLbias
3809  spdvector[k].data[L2] -= nwl * factor; // GFP
3810  }
3811 
3812  // Add to slip list
3813  Slip newSlip(i);
3814  newSlip.NWL = nwl;
3815  newSlip.msg = "WL";
3816  SlipList.push_back(newSlip);
3817 
3818  // mark it
3819  spdvector[i].flag |= (WLDETECT + WLFIX);
3820 
3821  if (cfg(Debug) >= 7)
3822  {
3823  log << "CHECK " << GDCUnique << " " << sat << " " << i << " "
3824  << printTime(time(i), outFormat) << fixed << setprecision(3)
3825  << " "
3826  << pastStats.N()
3827  //<< " " << pastStats.Average()
3828  << " " << pastStats.StdDev() << " "
3829  << futureStats.N()
3830  //<< " " << futureStats.Average()
3831  << " " << futureStats.StdDev() << " "
3832  << futureStats.Average() - pastStats.Average() << " " << nwl
3833  << endl;
3834  }
3835  }
3836  }
3837 
3838  return ReturnOK;
3839  }
3840  catch (Exception& e)
3841  {
3842  GNSSTK_RETHROW(e);
3843  }
3844  catch (std::exception& e)
3845  {
3846  Exception E("std except: " + string(e.what()));
3847  GNSSTK_THROW(E);
3848  }
3849  catch (...)
3850  {
3851  Exception e("Unknown exception");
3852  GNSSTK_THROW(e);
3853  }
3854 }
3855 
3856 //------------------------------------------------------------------------------------
3857 //------------------------------------------------------------------------------------
3858 /* last call before returning:
3859  generate editing commands for deleted (flagged) data,
3860  use editing command (slips and deletes) to modify the original SatPass data
3861  print ending summary, and also return it as a string */
3862 string GDCPass::finish(int iret, SatPass& svp, vector<string>& editCmds)
3863 {
3864  try
3865  {
3866  bool ok;
3867  int i, ifirst, ilast, npts;
3868  long N1, N2, prevN1, prevN2;
3869  double slipL1, slipL2, WLbias, GFbias;
3870  // SatPassData spd;
3871  list<Slip>::iterator jt;
3872  string retMessage;
3873 
3874  // ---------------------------------------------------------
3875  // sort the slips in time
3876  SlipList.sort();
3877 
3878  /* ---------------------------------------------------------
3879  merge *this GDCPass and the input SatPass...
3880  use this->flag to generate edit commands for data marked bad
3881  use the SlipList to fix slips
3882  'change the arrays' A1 and A2 - fill with range minus phase for output */
3883  npts = 0;
3884  ilast = -1; // ilast is the index of the last good point
3885  ifirst = -1; // ifirst is the index of the first good point
3886  WLbias = GFbias = slipL1 = slipL2 = 0.0;
3887  prevN1 = prevN2 = 0L;
3888  jt = SlipList.begin();
3889  for (i = 0; i < static_cast<int>(size()); i++)
3890  {
3891 
3892  // is this point bad?
3893  if (!(spdvector[i].flag & OK))
3894  { // data is bad
3895  ok = false;
3896  if (i == static_cast<int>(size()) - 1)
3897  { // but this is the last point
3898  i++;
3899  ok = true;
3900  }
3901  }
3902  else
3903  {
3904  ok = true; // data is good
3905  }
3906 
3907  if (ok)
3908  {
3909  if (ifirst == -1)
3910  {
3911  ifirst = i;
3912  }
3913 
3914  // generate edit commands: delete from ilast+1 to i-1
3915  if (i - ilast > 2 && cfg(OutputDeletes) != 0)
3916  {
3917  // delete 2, or a range of, points
3918  // -DS+<sat>,<time>
3919  ostringstream stst1;
3920  stst1 << "-DS";
3921  if (i - ilast > 3)
3922  {
3923  stst1 << "+";
3924  }
3925  stst1 << sat << ",";
3926  if (cfg(OutputGPSTime))
3927  {
3928  stst1 << printTime(time(ilast + 1), "%F,%.3g");
3929  }
3930  else
3931  {
3932  stst1 << printTime(time(ilast + 1), "%Y,%m,%d,%H,%M,%f");
3933  }
3934  if (i - ilast > 3)
3935  {
3936  stst1 << " # begin delete of " << asString(i + 1 - ilast)
3937  << " points";
3938  }
3939  editCmds.push_back(stst1.str());
3940 
3941  // -DS-<sat>,<time>
3942  ostringstream stst2;
3943  stst2 << "-DS";
3944  if (i - ilast > 3)
3945  {
3946  stst2 << "-";
3947  }
3948  stst2 << sat << ",";
3949  if (cfg(OutputGPSTime))
3950  {
3951  stst2 << printTime(time(i - 1), "%F,%.3g");
3952  }
3953  else
3954  {
3955  stst2 << printTime(time(i - 1), "%Y,%m,%d,%H,%M,%f");
3956  }
3957  if (i - ilast > 3)
3958  {
3959  stst2 << " # end delete of " << asString(i + 1 - ilast)
3960  << " points";
3961  }
3962  editCmds.push_back(stst2.str());
3963  }
3964  else if (i - ilast > 1 && cfg(OutputDeletes) != 0)
3965  {
3966  // delete a single isolated point
3967  ostringstream stst;
3968  stst << "-DS" << sat << ",";
3969  if (cfg(OutputGPSTime))
3970  {
3971  stst << printTime(time(i - 1), "%F,%.3g");
3972  }
3973  else
3974  {
3975  stst << printTime(time(i - 1), "%Y,%m,%d,%H,%M,%f");
3976  }
3977  editCmds.push_back(stst.str());
3978  }
3979 
3980  ilast = i;
3981  npts++;
3982  }
3983 
3984  // keep track of net slip fix
3985  if (jt != SlipList.end() && i == jt->index)
3986  { // there is a slip here
3987  // fix the slip by changing the bias added to phase
3988  N1 = jt->N1;
3989  N2 = jt->N1 - jt->NWL;
3990  slipL1 += double(N1);
3991  slipL2 += double(N2);
3992 
3993  // generate edit commands for slips
3994  if (N1 - prevN1 != 0)
3995  {
3996  ostringstream stst;
3997  stst << "-BD+" << sat << ",L1,";
3998  if (cfg(OutputGPSTime))
3999  {
4000  stst << printTime(time(jt->index), "%F,%.3g");
4001  }
4002  else
4003  {
4004  stst << printTime(time(jt->index), "%Y,%m,%d,%H,%M,%f");
4005  }
4006  stst << "," << N1 - prevN1;
4007  if (!jt->msg.empty())
4008  {
4009  stst << " # " << jt->msg;
4010  }
4011  // stst << " # WL: " << jt->NWL << " N1: " << jt->N1; //temp
4012  editCmds.push_back(stst.str());
4013  }
4014  if (N2 - prevN2 != 0)
4015  {
4016  ostringstream stst;
4017  stst << "-BD+" << sat << ",L2,";
4018  if (cfg(OutputGPSTime))
4019  {
4020  stst << printTime(time(jt->index), "%F,%.3g");
4021  }
4022  else
4023  {
4024  stst << printTime(time(jt->index), "%Y,%m,%d,%H,%M,%f");
4025  }
4026  stst << "," << N2 - prevN2;
4027  if (!jt->msg.empty())
4028  {
4029  stst << " # " << jt->msg;
4030  }
4031  editCmds.push_back(stst.str());
4032  }
4033 
4034  prevN1 = N1;
4035  prevN2 = N2;
4036  jt++;
4037  }
4038 
4039  if (i >= static_cast<int>(size()))
4040  {
4041  break;
4042  }
4043 
4044  // 'change the data' for the last time
4045  spdvector[i].data[L1] = svp.data(i, DCobstypes[L1]) - slipL1;
4046  spdvector[i].data[L2] = svp.data(i, DCobstypes[L2]) - slipL2;
4047  spdvector[i].data[P1] = svp.data(i, DCobstypes[P1]);
4048  spdvector[i].data[P2] = svp.data(i, DCobstypes[P2]);
4049 
4050  // compute range minus phase for output
4051  // do the same at the beginning ("BEG")
4052 
4053  // compute WL and GFP
4054  // narrow lane range (m)
4055  double wlr =
4056  wl1r * spdvector[i].data[P1] + wl2r * spdvector[i].data[P2];
4057  // wide lane phase (m)
4058  double wlp =
4059  wl1p * spdvector[i].data[L1] + wl2p * spdvector[i].data[L2];
4060  // geo-free range (m)
4061  double gfr =
4062  gf1r * spdvector[i].data[P1] + gf2r * spdvector[i].data[P2];
4063  // geo-free phase (m)
4064  double gfp =
4065  gf1p * spdvector[i].data[L1] + gf2p * spdvector[i].data[L2];
4066  if (i == ifirst)
4067  {
4068  WLbias = (wlp - wlr) / wlwl;
4069  GFbias = gfp;
4070  }
4071  spdvector[i].data[A1] =
4072  (wlp - wlr) / wlwl - WLbias; // wide lane bias (cyc)
4073  spdvector[i].data[A2] = gfp - GFbias; // geo-free phase (m)
4074  // spdvector[i].data[A2] = gfr - gfp; // geo-free range -
4075  // phase (m)
4076 
4077  } // end loop over all data
4078 
4079  // first fix the segment for dump - TD? is this necessary?
4080  if (SegList.begin() != SegList.end())
4081  {
4082  SegList.begin()->bias1 = SegList.begin()->bias2 = 0; // not necessary..
4083  SegList.begin()->nbeg = 0;
4084  SegList.begin()->nend = static_cast<int>(size()) - 1;
4085  SegList.begin()->npts = npts;
4086  }
4087  // dump the corrected data
4088  if (cfg(Debug) >= 2)
4089  {
4090  dumpSegments("AFT", 2, true);
4091  }
4092 
4093  // dump the edit commands to log
4094  for (i = 0; i < static_cast<int>(editCmds.size()); i++)
4095  if (cfg(Debug) >= 2)
4096  {
4097  log << "EditCmd: " << GDCUnique << " " << editCmds[i] << endl;
4098  }
4099 
4100  // ---------------------------------------------------------
4101  // copy corrected data into original SatPass, without disturbing other obs
4102  // types
4103  for (i = 0; i < static_cast<int>(size()); i++)
4104  {
4105  svp.data(i, DCobstypes[L1]) = spdvector[i].data[L1];
4106  svp.data(i, DCobstypes[L2]) = spdvector[i].data[L2];
4107  svp.data(i, DCobstypes[P1]) = spdvector[i].data[P1];
4108  svp.data(i, DCobstypes[P2]) = spdvector[i].data[P2];
4109 
4110  /* change the flag for use by SatPass
4111  const unsigned short SatPass::OK = 1; good data
4112  const unsigned short SatPass::BAD = 0; used by caller and DC to mark
4113  bad data const unsigned short SatPass::LL1 = 2; discontinuity on L1
4114  only const unsigned short SatPass::LL2 = 4; discontinuity on L2 only
4115  const unsigned short SatPass::LL3 = 6; discontinuity on L1 and L2
4116  const unsigned short GDCPass::DETECT = 6; // = WLDETECT |
4117  GFDETECT const unsigned short GDCPass::FIX = 24; // = WLFIX |
4118  GFFIX */
4119  if (spdvector[i].flag & OK)
4120  {
4121  if (((spdvector[i].flag & DETECT) == 0 &&
4122  (spdvector[i].flag & FIX) != 0) ||
4123  i == ifirst)
4124  {
4125  spdvector[i].flag = LL3 + OK;
4126  }
4127  else
4128  {
4129  spdvector[i].flag = OK;
4130  }
4131  }
4132  else
4133  {
4134  spdvector[i].flag = BAD;
4135  }
4136 
4137  svp.LLI(i, DCobstypes[L1]) = (spdvector[i].flag & LL1) ? 1 : 0;
4138  svp.LLI(i, DCobstypes[L2]) = (spdvector[i].flag & LL2) ? 1 : 0;
4139  svp.setFlag(i, spdvector[i].flag);
4140  }
4141 
4142  // ---------------------------------------------------------
4143  // make up string to return
4144  ilast = -1; // last good point
4145  ostringstream oss;
4146  for (list<Segment>::iterator it = SegList.begin(); it != SegList.end();
4147  it++)
4148  {
4149  i = (it->nend - it->nbeg + 1); // total number of points
4150  oss << GDCtag << " " << GDCUnique << " " << sat << " #" << setw(2)
4151  << it->nseg << ": " << setw(4) << it->npts << "/" << setw(4) << i
4152  << " pts, # " << setw(4) << it->nbeg << "-" << setw(4) << it->nend
4153  << " (" << printTime(time(it->nbeg), outFormat) << " - "
4154  << printTime(time(it->nend), outFormat) << ")";
4155  if (it->npts > 0)
4156  {
4157  oss << fixed << setprecision(3) << " bias(wl)=" << setw(13)
4158  << it->bias1 // biaswl
4159  << " bias(gf)=" << setw(13) << it->bias2; // biasgf;
4160  if (ilast > -1)
4161  {
4162  ifirst = static_cast<int>(it->nbeg);
4163  while (ifirst <= static_cast<int>(it->nend) &&
4164  !(spdvector[ifirst].flag & OK))
4165  {
4166  ifirst++;
4167  }
4168  i = spdvector[ifirst].ndt - spdvector[ilast].ndt;
4169  oss << " gap_segs " << setprecision(1) << setw(5) << cfg(DT) * i
4170  << " s = " << i << " pts.";
4171  }
4172  ilast = static_cast<int>(it->nend);
4173  while (ilast >= static_cast<int>(it->nbeg) &&
4174  !(spdvector[ilast].flag & OK))
4175  {
4176  ilast--;
4177  }
4178  }
4179  oss << endl;
4180  }
4181 
4182  // print the channel number (GLO) and wavelengths in cm
4183  oss << GDCtag << " " << GDCUnique << " " << sat << fixed
4184  << setprecision(2) << " DT " << fixed << setprecision(2) << cfg(DT)
4185  << " wavelengths " << wl1 * 100.0 << " " << wl2 * 100.0 << " "
4186  << wlwl * 100.0 << " " << wlgf * 100.0;
4187  if (sat.system == SatelliteSystem::Glonass)
4188  {
4189  oss << " GLOn " << GLOn;
4190  }
4191  oss << endl;
4192 
4193  // print WL & GF stats for whole pass
4194  if (WLPassStats.N() > 2)
4195  {
4196  oss << GDCtag << " " << GDCUnique << " " << sat << " " << fixed
4197  << setprecision(3) << WLPassStats.StdDev() << " WL sigma in cycles"
4198  << " N=" << WLPassStats.N() << " Min=" << WLPassStats.Minimum()
4199  << " Max=" << WLPassStats.Maximum()
4200  << " Ave=" << WLPassStats.Average();
4201  if (WLPassStats.StdDev() > cfg(WLSigma))
4202  {
4203  oss << " Warning - WL sigma > input (" << cfg(WLSigma) << ")";
4204  }
4205  oss << endl;
4206  }
4207 
4208  if (GFPassStats.N() > 2)
4209  {
4210  oss << GDCtag << " " << GDCUnique << " " << sat << " " << fixed
4211  << setprecision(3) << GFPassStats.StdDev()
4212  << " sigma GF variation in meters per DT"
4213  << " N=" << GFPassStats.N() << " Min=" << GFPassStats.Minimum()
4214  << " Max=" << GFPassStats.Maximum()
4215  << " Ave=" << GFPassStats.Average() << endl;
4216  oss << GDCtag << " " << GDCUnique << " " << sat << " " << fixed
4217  << setprecision(3)
4218  << (fabs(GFPassStats.Minimum()) > fabs(GFPassStats.Maximum())
4219  ? fabs(GFPassStats.Minimum())
4220  : fabs(GFPassStats.Maximum()))
4221  << " maximum GF variation in meters per DT"
4222  << " N=" << GFPassStats.N() << " Ave=" << GFPassStats.Average()
4223  << " Std=" << GFPassStats.StdDev() << endl;
4224  }
4225 
4226  // print 'learn' summary
4227  map<string, int>::const_iterator kt;
4228  for (kt = learn.begin(); kt != learn.end(); kt++)
4229  oss << GDCtag << " " << GDCUnique << " " << sat << " " << setw(3)
4230  << kt->second << " " << kt->first << endl;
4231  // if(sat.system == SatelliteSystem::Glonass)
4232  // oss << GDCtag << " " << GDCUnique << " " << sat
4233  // << " " << GLOn << string(" GLONASS frequency channel") << endl;
4234 
4235  int n = int((lastTime - firstTime) / cfg(DT)) + 1;
4236  double percent = 100.0 * double(ngood) / n;
4237  if (cfg(Debug) > 0)
4238  {
4239  oss << GDCtag << "# " << setw(3) << GDCUnique << ", SAT " << sat
4240  << ", Pts: " << setw(4) << n << " total " << setw(4) << ngood
4241  << " good " << fixed << setprecision(1) << setw(5) << percent
4242  << "%"
4243  << ", start " << printTime(firstTime, outFormat) << endl;
4244  }
4245 
4246  if (iret)
4247  {
4248  oss << GDCtag << " " << setw(3) << GDCUnique << " " << sat << " "
4250  << " is returning with error code: "
4251  << (iret == NoData
4252  ? "insufficient data"
4253  : (iret == BadInput
4254  ? "required obs types L1,L2,P1/C1,P2 not found"
4255  : (iret == Singular
4256  ? "singularity in polynomial fit"
4257  : (iret == FatalProblem
4258  ? "time interval DT was not set"
4259  : (iret == PrematureEnd
4260  ? "premature end"
4261  : "unknown problem")))))
4262  << endl;
4263  }
4264 
4265  retMessage = oss.str();
4266 
4267  if (cfg(Debug) >= 2)
4268  {
4269  log << "======== End GNSSTK Discontinuity Corrector " << GDCUnique
4270  << " ================================================\n";
4271  }
4272 
4273  stripTrailing(retMessage, '\n');
4274  return retMessage;
4275  }
4276  catch (Exception& e)
4277  {
4278  GNSSTK_RETHROW(e);
4279  }
4280  catch (std::exception& e)
4281  {
4282  Exception E("std except: " + string(e.what()));
4283  GNSSTK_THROW(E);
4284  }
4285  catch (...)
4286  {
4287  Exception e("Unknown exception");
4288  GNSSTK_THROW(e);
4289  }
4290 }
4291 
4292 //------------------------------------------------------------------------------------
4293 // create, delete and dump Segments
4294 //------------------------------------------------------------------------------------
4295 /* create a new segment from the given one, starting at index ibeg,
4296  and insert it after the given iterator.
4297  Return an iterator pointing to the new segment. String msg is for debug
4298  output */
4299 list<Segment>::iterator GDCPass::createSegment(list<Segment>::iterator sit,
4300  int ibeg, string msg)
4301 {
4302  try
4303  {
4304  Segment s;
4305  s = *sit;
4306  s.nbeg = ibeg;
4307  s.nend = sit->nend;
4308  sit->nend = ibeg - 1;
4309 
4310  // 'trim' beg and end indexes
4311  while (s.nend > s.nbeg && !(spdvector[s.nend].flag & OK))
4312  {
4313  s.nend--;
4314  }
4315  while (sit->nend > sit->nbeg && !(spdvector[sit->nend].flag & OK))
4316  {
4317  sit->nend--;
4318  }
4319 
4320  // recompute npts // TD is this done somewhere else?
4321  unsigned int i;
4322  s.npts = sit->npts = 0;
4323  for (i = s.nbeg; i <= s.nend; i++)
4324  if (spdvector[i].flag & OK)
4325  {
4326  s.npts++;
4327  }
4328  for (i = sit->nbeg; i <= sit->nend; i++)
4329  if (spdvector[i].flag & OK)
4330  {
4331  sit->npts++;
4332  }
4333 
4334  // get the segment number right
4335  s.nseg++;
4336  list<Segment>::iterator skt = sit;
4337  for (skt++; skt != SegList.end(); skt++)
4338  skt->nseg++;
4339 
4340  if (cfg(Debug) >= 6)
4341  {
4342  log << "SEG " << GDCUnique << " " << sat << " " << msg << " "
4343  << printTime(time(ibeg), outFormat) << " " << s.nbeg << " - "
4344  << s.nend << " biases " << fixed << setprecision(3) << s.bias1
4345  << " " << s.bias2 << endl;
4346  }
4347 
4348  learn["breaks found: " + msg]++;
4349 
4350  return SegList.insert(++sit, s); // insert puts s before ++sit
4351  }
4352  catch (Exception& e)
4353  {
4354  GNSSTK_RETHROW(e);
4355  }
4356  catch (std::exception& e)
4357  {
4358  Exception E("std except: " + string(e.what()));
4359  GNSSTK_THROW(E);
4360  }
4361  catch (...)
4362  {
4363  Exception e("Unknown exception");
4364  GNSSTK_THROW(e);
4365  }
4366 }
4367 
4368 //------------------------------------------------------------------------------------
4369 /* dump a list of the segments
4370  level=0 one line summary (number of segments)
4371  level=1 one per line list of segments
4372  level=2 dump all data, including (if extra) temporary arrays
4373  return level 1 output as string */
4374 string GDCPass::dumpSegments(string label, int level, bool extra)
4375 {
4376  try
4377  {
4378  unsigned int i, ifirst;
4379  int ilast;
4380  list<Segment>::iterator it;
4381  string msg;
4382  ostringstream oss;
4383 
4384  // summary of SegList
4385  oss << label << " " << GDCUnique << " list of Segments ("
4386  << SegList.size() << "):" << endl;
4387 
4388  if (level < 1)
4389  {
4390  msg = oss.str();
4391  log << msg;
4392  return msg;
4393  }
4394 
4395  // one line per segment
4396  ilast = -1; // last good point
4397  for (it = SegList.begin(); it != SegList.end(); it++)
4398  {
4399  i = (it->nend - it->nbeg + 1); // total number of points
4400 
4401  oss << label << " " << GDCUnique << " " << sat << " #" << setw(2)
4402  << it->nseg << ": " << setw(4) << it->npts << "/" << setw(4) << i
4403  << " pts, # " << setw(4) << it->nbeg << "-" << setw(4) << it->nend
4404  << " (" << printTime(time(it->nbeg), outFormat) << " - "
4405  << printTime(time(it->nend), outFormat) << ")";
4406 
4407  if (it->npts > 0)
4408  {
4409  oss << fixed << setprecision(3) << " bias(wl)=" << setw(13)
4410  << it->bias1 // biaswl
4411  << " bias(gf)=" << setw(13) << it->bias2; // biasgf;
4412  if (ilast > -1)
4413  {
4414  ifirst = it->nbeg;
4415  while (ifirst <= it->nend && !(spdvector[ifirst].flag & OK))
4416  {
4417  ifirst++;
4418  }
4419  i = spdvector[ifirst].ndt - spdvector[ilast].ndt;
4420  oss << " Gap " << setprecision(1) << setw(5) << cfg(DT) * i
4421  << " s = " << i << " pts.";
4422  }
4423  ilast = it->nend;
4424  while (ilast >= static_cast<int>(it->nbeg) &&
4425  !(spdvector[ilast].flag & OK))
4426  {
4427  ilast--;
4428  }
4429  }
4430 
4431  oss << endl;
4432  }
4433 
4434  if (level < 2)
4435  {
4436  msg = oss.str();
4437  log << msg;
4438  return msg;
4439  }
4440 
4441  // dump the data
4442  for (it = SegList.begin(); it != SegList.end(); it++)
4443  {
4444  for (i = it->nbeg; i <= it->nend; i++)
4445  {
4446 
4447  oss << "DSC" << label << " " << GDCUnique << " " << sat << " "
4448  << it->nseg << " " << printTime(time(i), outFormat) << " "
4449  << setw(3) << spdvector[i].flag << fixed << setprecision(3)
4450  << " " << setw(13)
4451  << spdvector[i].data[L1] - it->bias2 // biasgf //temp
4452  << " " << setw(13)
4453  << spdvector[i].data[L2] - it->bias2 // biasgf
4454  << " " << setw(13)
4455  << spdvector[i].data[P1] - it->bias1 // biaswl
4456  << " " << setw(13) << spdvector[i].data[P2];
4457  if (extra)
4458  {
4459  oss << " " << setw(13) << spdvector[i].data[A1] << " "
4460  << setw(13) << spdvector[i].data[A2];
4461  }
4462  oss << " " << setw(4) << i;
4463  if (i == it->nbeg)
4464  {
4465  oss << " " << setw(13) << it->bias1 // biaswl
4466  << " " << setw(13) << it->bias2; // biasgf;
4467  }
4468  oss << endl;
4469  }
4470  }
4471 
4472  msg = oss.str();
4473  log << msg;
4474  return msg;
4475  }
4476  catch (Exception& e)
4477  {
4478  GNSSTK_RETHROW(e);
4479  }
4480  catch (std::exception& e)
4481  {
4482  Exception E("std except: " + string(e.what()));
4483  GNSSTK_THROW(E);
4484  }
4485  catch (...)
4486  {
4487  Exception e("Unknown exception");
4488  GNSSTK_THROW(e);
4489  }
4490 }
4491 
4492 //------------------------------------------------------------------------------------
4493 void GDCPass::deleteSegment(list<Segment>::iterator& it, string msg)
4494 {
4495  try
4496  {
4497  unsigned int i;
4498 
4499  if (cfg(Debug) >= 6)
4500  {
4501  log << "Delete segment " << GDCUnique << " " << sat << " " << it->nseg
4502  << " pts " << it->npts << " indexes " << it->nbeg << " - "
4503  << it->nend << " start " << printTime(firstTime, outFormat)
4504  << " : " << msg << endl;
4505  }
4506 
4507  it->npts = 0;
4508  for (i = it->nbeg; i <= it->nend; i++)
4509  if (spdvector[i].flag & OK)
4510  {
4511  // count these : learn
4512  learn["points deleted: " + msg]++;
4513  spdvector[i].flag = BAD;
4514  }
4515 
4516  learn["segments deleted: " + msg]++;
4517  }
4518  catch (Exception& e)
4519  {
4520  GNSSTK_RETHROW(e);
4521  }
4522  catch (std::exception& e)
4523  {
4524  Exception E("std except: " + string(e.what()));
4525  GNSSTK_THROW(E);
4526  }
4527  catch (...)
4528  {
4529  Exception e("Unknown exception");
4530  GNSSTK_THROW(e);
4531  }
4532 }
4533 
4534 //------------------------------------------------------------------------------------
4535 //------------------------------------------------------------------------------------
gnsstk::SatPass::labelForIndex
std::map< unsigned int, std::string > labelForIndex
Definition: SatPass.hpp:170
Segment::~Segment
~Segment()
Definition: DiscCorr.cpp:363
GDCPass::detectGFsmallSlips
int detectGFsmallSlips()
Definition: DiscCorr.cpp:3178
GDCPass::firstDifferences
int firstDifferences(string which)
Definition: DiscCorr.cpp:1516
A2
static const int A2
Definition: DiscCorr.cpp:631
GDCPass::GFPassStats
Stats< double > GFPassStats
stats on the first difference of GF after detectObviousSlips(GF)
Definition: DiscCorr.cpp:611
GDCPass::GFDETECT
static const unsigned short GFDETECT
Definition: DiscCorr.cpp:409
GDCPass::detectGFslips
int detectGFslips()
Definition: DiscCorr.cpp:2976
gnsstk::DiscontinuityCorrector
int DiscontinuityCorrector(SatPass &SP, GDCconfiguration &config, std::vector< std::string > &EditCmds, std::string &retMsg, int GLOn=-99)
Definition: DiscCorr.cpp:698
gnsstk::SatPass::addData
int addData(const Epoch &tt, std::vector< std::string > &obstypes, std::vector< double > &data)
Definition: SatPass.cpp:134
GDCPass::detectObviousSlips
int detectObviousSlips(string which)
Definition: DiscCorr.cpp:1349
gnsstk::SatPass::data
double & data(unsigned int i, const std::string &type)
Definition: SatPass.cpp:882
gnsstk::PolyFit::Add
void Add(T d, T t, T w=T(1))
Add a single (optional: weighted) datum to the estimation.
Definition: PolyFit.hpp:110
GDCPass::GFFIX
static const unsigned short GFFIX
Definition: DiscCorr.cpp:410
Slip::msg
string msg
Definition: DiscCorr.cpp:393
gnsstk::SatPass::ngood
unsigned int ngood
number of timetags with good data in the data arrays.
Definition: SatPass.hpp:182
gnsstk::Stats::Subtract
void Subtract(const T &x)
Definition: Stats.hpp:178
GDCPass::EstimateGFslipFix
long EstimateGFslipFix(list< Segment >::iterator &left, list< Segment >::iterator &right, unsigned int nb, unsigned int ne, long n1)
Definition: DiscCorr.cpp:2739
Segment::nseg
int nseg
Definition: DiscCorr.cpp:348
wl2r
double wl2r
Definition: DiscCorr.cpp:657
Segment::RMSROF
double RMSROF
Definition: DiscCorr.cpp:353
P1
static const int P1
Definition: DiscCorr.cpp:628
GDCPass::fixOneSlip
void fixOneSlip(list< Segment >::iterator &kt, string which)
Definition: DiscCorr.cpp:2393
gnsstk::SatPass::indexForLabel
std::map< std::string, unsigned int > indexForLabel
Definition: SatPass.hpp:169
StringUtils.hpp
GDCPass::learn
map< string, int > learn
polynomial fit to the geometry-free range for the whole pass
Definition: DiscCorr.cpp:618
gnsstk::Stats::Variance
T Variance(void) const
return computed variance
Definition: Stats.hpp:338
gnsstk::GDCconfiguration
Definition: DiscCorr.hpp:72
cfg
#define cfg(a)
Definition: DiscCorr.cpp:624
GDCPass::WLPassStats
Stats< double > WLPassStats
temporary storage arrays, parallel to SatPass::data
Definition: DiscCorr.cpp:608
Segment::bias1
double bias1
Definition: DiscCorr.cpp:349
gnsstk::Stats::Minimum
T Minimum(void) const
return minimum value
Definition: Stats.hpp:321
Segment::operator=
Segment & operator=(const Segment &s)
Definition: DiscCorr.cpp:364
GDCPass::WLcomputeStats
void WLcomputeStats(list< Segment >::iterator &it)
Definition: DiscCorr.cpp:1588
gf1r
double gf1r
Definition: DiscCorr.cpp:658
gnsstk::Stats::StdDev
T StdDev(void) const
return computed standard deviation
Definition: Stats.hpp:347
GDCPass::detectWLsmallSlips
int detectWLsmallSlips()
Definition: DiscCorr.cpp:1943
gnsstk::SatPass::getFirstTime
Epoch getFirstTime() const
Definition: SatPass.cpp:1012
GDCPass::WLslipFix
void WLslipFix(list< Segment >::iterator &left, list< Segment >::iterator &right)
Definition: DiscCorr.cpp:2485
gf2p
double gf2p
Definition: DiscCorr.cpp:659
gnsstk::Stats::Reset
void Reset(void)
reset, i.e. ignore earlier data and restart sampling
Definition: Stats.hpp:146
gnsstk::PolyFit::Evaluate
T Evaluate(T t)
Definition: PolyFit.hpp:177
Segment::nbeg
unsigned int nbeg
Definition: DiscCorr.cpp:345
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
gnsstk::gdc::getParameter
double getParameter(std::string label)
Definition: gdc.hpp:354
gnsstk::SatPass::LL3
static const GNSSTK_EXPORT unsigned short LL3
Definition: SatPass.hpp:883
Slip::N1
long N1
Definition: DiscCorr.cpp:392
GDCPass::foundGFsmallSlip
bool foundGFsmallSlip(int i, int nseg, int iend, int ibeg, deque< int > &pastIn, deque< int > &futureIn, Stats< double > &pastSt, Stats< double > &futureSt)
Definition: DiscCorr.cpp:3423
gnsstk::SatPass::BAD
static const GNSSTK_EXPORT unsigned short BAD
flag indicating bad data
Definition: SatPass.hpp:854
gnsstk::SatPass
Definition: SatPass.hpp:71
GDCPass::GFphaseResiduals
int GFphaseResiduals(list< Segment >::iterator &it)
Definition: DiscCorr.cpp:3077
Segment::bias2
double bias2
Definition: DiscCorr.cpp:351
GDCPass::FIX
static const unsigned short FIX
Definition: DiscCorr.cpp:406
gnsstk::SatPass::OK
static const GNSSTK_EXPORT unsigned short OK
Definition: SatPass.hpp:862
GDCUnique
static int GDCUnique
Definition: DiscCorr.cpp:648
GNSSconstants.hpp
ReturnOK
static const int ReturnOK
Definition: DiscCorr.cpp:643
L2
static const int L2
Definition: DiscCorr.cpp:627
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
Segment
Definition: DiscCorr.cpp:341
gnsstk::Stats< double >
Segment::npts
unsigned int npts
Definition: DiscCorr.cpp:347
GDCPass::WLDETECT
static const unsigned short WLDETECT
Definition: DiscCorr.cpp:407
gnsstk::SatPass::dt
double dt
Nominal time spacing of the data; determined on input or by decimate()
Definition: SatPass.hpp:160
Stats.hpp
gnsstk::SatPass::firstTime
Epoch firstTime
Definition: SatPass.hpp:179
gnsstk::Exception
Definition: Exception.hpp:151
gf1p
double gf1p
Definition: DiscCorr.cpp:658
DCobstypes
vector< string > DCobstypes
Definition: DiscCorr.cpp:633
gnsstk::StringUtils::stripTrailing
std::string & stripTrailing(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1453
gnsstk::SatPass::LLI
unsigned short & LLI(unsigned int i, const std::string &type)
Definition: SatPass.cpp:908
initialize
int initialize(string &errors)
Definition: RinEdit.cpp:513
gnsstk::PolyFit< double >
GDCPass::cfg_func
double cfg_func(string a)
Definition: DiscCorr.cpp:587
GDCPass::SlipList
list< Slip > SlipList
list of Slips found; used to generate the editing commands on output
Definition: DiscCorr.cpp:602
GDCPass::WLFIX
static const unsigned short WLFIX
Definition: DiscCorr.cpp:408
Segment::nend
unsigned int nend
Definition: DiscCorr.cpp:345
GDCPass::GFslipFix
void GFslipFix(list< Segment >::iterator &left, list< Segment >::iterator &right)
Definition: DiscCorr.cpp:2567
gnsstk::C_MPS
const double C_MPS
m/s, speed of light; this value defined by GPS but applies to GAL and GLO.
Definition: GNSSconstants.hpp:74
GDCPass::WLstatSweep
int WLstatSweep(list< Segment >::iterator &it, int width)
Definition: DiscCorr.cpp:1824
Slip::Slip
Slip(int in)
Definition: DiscCorr.cpp:394
gnsstk::SatPass::gdc
friend class gdc
class gdc is used to detect and correct cycleslips
Definition: SatPass.hpp:210
Slip::NWL
long NWL
Definition: DiscCorr.cpp:392
GDCPass::finish
string finish(int iret, SatPass &svp, vector< string > &editCmds)
Definition: DiscCorr.cpp:3862
gnsstk::SatPass::getFlag
unsigned short getFlag(unsigned int i) const
Definition: SatPass.cpp:977
GDCPass::prepareGFdata
int prepareGFdata()
Definition: DiscCorr.cpp:2918
Slip::operator<
bool operator<(const Slip &rhs) const
Definition: DiscCorr.cpp:395
gnsstk::Stats::Maximum
T Maximum(void) const
return maximum value
Definition: Stats.hpp:325
log
#define log
Definition: DiscCorr.cpp:625
Slip::index
int index
Definition: DiscCorr.cpp:391
nl
int nl
Definition: IERS1996NutationData.hpp:44
gnsstk::L1_MULT_GPS
const double L1_MULT_GPS
GPS L1 frequency in units of oscillator frequency.
Definition: GNSSconstants.hpp:96
gnsstk::SatPass::getDT
double getDT() const
Definition: SatPass.hpp:515
gnsstk::SatPass::status
int & status()
Access the status; l-value may be assigned SP.status() = 1;.
Definition: SatPass.hpp:344
gnsstk::OSC_FREQ_GPS
const double OSC_FREQ_GPS
Hz, GPS Oscillator or chip frequency.
Definition: GNSSconstants.hpp:88
wl1
double wl1
Definition: DiscCorr.cpp:656
gnsstk::SatPass::outFormat
static GNSSTK_EXPORT std::string outFormat
Definition: SatPass.hpp:896
DiscCorr.hpp
gnsstk::SatPass::LL2
static const GNSSTK_EXPORT unsigned short LL2
Definition: SatPass.hpp:876
GDCtag
static string GDCtag
Definition: DiscCorr.cpp:650
gnsstk::GDCconfiguration::CFG
std::map< std::string, double > CFG
map containing configuration labels and their values
Definition: DiscCorr.hpp:135
gnsstk::StringUtils::asDouble
double asDouble(const std::string &s)
Definition: StringUtils.hpp:705
gf2r
double gf2r
Definition: DiscCorr.cpp:658
GDCPass::fixAllSlips
int fixAllSlips(string which)
Definition: DiscCorr.cpp:2281
wl1r
double wl1r
Definition: DiscCorr.cpp:657
wl2
double wl2
Definition: DiscCorr.cpp:656
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
Segment::Segment
Segment()
Definition: DiscCorr.cpp:357
example4.pos
pos
Definition: example4.py:125
GDCPass::WLconsistencyCheck
int WLconsistencyCheck()
Definition: DiscCorr.cpp:3735
PrematureEnd
static const int PrematureEnd
Definition: DiscCorr.cpp:641
gnsstk::SatPass::getGLOchannel
bool getGLOchannel(int &n, std::string &msg)
Definition: SatPass.cpp:309
gnsstk::SatID::system
SatelliteSystem system
System for this satellite.
Definition: SatID.hpp:156
wl1p
double wl1p
Definition: DiscCorr.cpp:657
GDCPass::detectWLslips
int detectWLslips()
Definition: DiscCorr.cpp:1246
gnsstk::GDCconfiguration::GDCVersion
static const GNSSTK_EXPORT std::string GDCVersion
Definition: DiscCorr.hpp:146
GDCPass::foundGFoutlier
bool foundGFoutlier(int i, int inew, Stats< double > &pastSt, Stats< double > &futureSt)
Definition: DiscCorr.cpp:3331
RobustStats.hpp
Segment::Segment
Segment(const Segment &s)
Definition: DiscCorr.cpp:362
example6.ssi
ssi
Definition: example6.py:124
gnsstk::SatPass::spdvector
std::vector< SatPassData > spdvector
ALL data in the pass, stored in SatPassData objects, in time order.
Definition: SatPass.hpp:185
GDCPass::SegList
list< Segment > SegList
Definition: DiscCorr.cpp:599
Singular
static const int Singular
Definition: DiscCorr.cpp:642
GDCPass::GDCPass
GDCPass(SatPass &sp, const GDCconfiguration &gdc)
Definition: DiscCorr.cpp:948
GDCPass::DETECT
static const unsigned short DETECT
Definition: DiscCorr.cpp:405
GDCPass::preprocess
int preprocess()
Definition: DiscCorr.cpp:984
gnsstk::printTime
std::string printTime(const CommonTime &t, const std::string &fmt)
Definition: TimeString.cpp:64
A1
static const int A1
Definition: DiscCorr.cpp:630
gnsstk::RinexSatID
Definition: RinexSatID.hpp:63
GDCPass::createSegment
list< Segment >::iterator createSegment(list< Segment >::iterator sit, int ibeg, string msg=string())
Definition: DiscCorr.cpp:4299
gnsstk::SatPass::lastTime
Epoch lastTime
Definition: SatPass.hpp:179
GDCPass::deleteSegment
void deleteSegment(list< Segment >::iterator &it, string msg=string())
Definition: DiscCorr.cpp:4493
std
Definition: Angle.hpp:142
GDCPass::foundWLsmallSlip
bool foundWLsmallSlip(list< Segment >::iterator &it, int i)
Definition: DiscCorr.cpp:2077
gnsstk::gdc
Definition: gdc.hpp:319
L1
static const int L1
Definition: DiscCorr.cpp:626
Segment::PF
PolyFit< double > PF
Definition: DiscCorr.cpp:352
gnsstk::SatPass::LL1
static const GNSSTK_EXPORT unsigned short LL1
Definition: SatPass.hpp:869
gnsstk::Stats::Average
T Average(void) const
return the average
Definition: Stats.hpp:329
BadInput
static const int BadInput
Definition: DiscCorr.cpp:638
gnsstk::Stats::Add
void Add(const T &x)
Definition: Stats.hpp:158
NoData
static const int NoData
Definition: DiscCorr.cpp:639
gnsstk::Epoch
Definition: Epoch.hpp:123
FatalProblem
static const int FatalProblem
Definition: DiscCorr.cpp:640
P2
static const int P2
Definition: DiscCorr.cpp:629
GDCUniqueFix
static int GDCUniqueFix
Definition: DiscCorr.cpp:649
gnsstk::StringUtils::leftJustify
std::string & leftJustify(std::string &s, const std::string::size_type length, const char pad=' ')
Definition: StringUtils.hpp:1582
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::SatPass::sat
RinexSatID sat
Satellite identifier for this data.
Definition: SatPass.hpp:163
gnsstk::SatPass::time
Epoch time(unsigned int i) const
Definition: SatPass.cpp:1097
gnsstk::gdc::setParameter
bool setParameter(std::string cmd)
Definition: gdc.cpp:1894
wlgf
double wlgf
Definition: DiscCorr.cpp:656
gnsstk::SatPass::Status
int Status
Definition: SatPass.hpp:157
setcfg
#define setcfg(a, b, c)
Definition: DiscCorr.cpp:230
gnsstk::median
T median(const Vector< T > &v)
Compute the median of a gnsstk::Vector.
Definition: Stats.hpp:59
example6.lli
lli
Definition: example6.py:123
Slip
Definition: DiscCorr.cpp:388
gnsstk::SatPass::SSI
unsigned short & SSI(unsigned int i, const std::string &type)
Definition: SatPass.cpp:924
GDCPass::linearCombinations
int linearCombinations()
Definition: DiscCorr.cpp:1171
GDCPass::dumpSegments
string dumpSegments(string msg, int level=2, bool extra=false)
Definition: DiscCorr.cpp:4374
GLOn
int GLOn
Definition: DiscCorr.cpp:655
gnsstk::Robust::MAD
T MAD(T *xd, int nd, T &M, bool save_flag=true)
Definition: RobustStats.hpp:520
Segment::WLsweep
bool WLsweep
Definition: DiscCorr.cpp:354
gnsstk::Robust::MEstimate
T MEstimate(const T *xd, int nd, const T &M, const T &MAD, T *w=NULL)
Definition: RobustStats.hpp:541
gnsstk::SatPass::getSat
RinexSatID getSat() const
Definition: SatPass.hpp:509
PolyFit.hpp
gnsstk::mad
T mad(const gnsstk::Vector< T > &v)
median absolute deviation of a gnsstk::Vector
Definition: Stats.hpp:85
gnsstk::SatPass::setFlag
void setFlag(unsigned int i, unsigned short flag)
Definition: SatPass.cpp:942
GDCPass::WLsigmaStrip
void WLsigmaStrip(list< Segment >::iterator &it)
Definition: DiscCorr.cpp:1632
wlwl
double wlwl
Definition: DiscCorr.cpp:656
gnsstk::SatPass::size
unsigned int size() const
Definition: SatPass.hpp:527
GLOfailed
static const int GLOfailed
Definition: DiscCorr.cpp:637
GDCPass
Definition: DiscCorr.cpp:402
gnsstk::Stats::N
unsigned int N(void) const
return the sample size
Definition: Stats.hpp:318
Segment::WLStats
Stats< double > WLStats
Definition: DiscCorr.cpp:350
gnsstk::PolyFit::Reset
void Reset(unsigned int n=0)
Definition: PolyFit.hpp:91
wl2p
double wl2p
Definition: DiscCorr.cpp:657
sp
double sp
Definition: IERS1996NutationData.hpp:46
gnsstk::L2_MULT_GPS
const double L2_MULT_GPS
GPS L2 frequency in units of oscillator frequency.
Definition: GNSSconstants.hpp:98


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:38