RobustStats.hpp
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 #ifndef GNSSTK_ROBUSTSTATS_HPP
47 #define GNSSTK_ROBUSTSTATS_HPP
48 
49 //------------------------------------------------------------------------------------
50 // system includes
51 #include <cmath>
52 #include <string>
53 
54 // GNSSTk
55 #include "Exception.hpp"
56 
57 namespace gnsstk
58 {
59 //------------------------------------------------------------------------------------
60 #define ABSOLUTE(x) ((x) < T() ? -(x) : (x))
61 
63 #define RobustTuningT (1.5) // or 1.345
64 
66 #define RobustTuningA (0.778) // or 0.67
67 
69 #define RobustTuningE (0.6745) // so MAD of a std normal dist is StdDev
70 
71  //---------------------------------------------------------------------------------
73 
74 
75  //--------------------------------------------------------------------------------
76  // quick sort, for use by robust statistics routines
77 
86  template <typename T> int Qsort_compare(const T& a, const T& b)
87  {
88  if (a > b)
89  {
90  return 1;
91  }
92  else if (a < b)
93  {
94  return -1;
95  }
96  else
97  {
98  return 0;
99  }
100  }
101 
110  template <typename T>
111  void insert(T *sa, int na,
112  int (*comp)(const T& , const T& ) = gnsstk::Qsort_compare)
113  {
114  int i, j;
115  T stemp;
116  for (i = 1; i < na; i = i + 1)
117  { // insert the i-th element into the sorted array
118  stemp = sa[i];
119  j = i - 1; // find where it goes
120  while ((j >= 0) && (comp(stemp, sa[j]) < 0))
121  {
122  sa[j + 1] = sa[j];
123  j = j - 1;
124  }
125  sa[j + 1] = stemp;
126  }
127  } // end insert sort
128 
138  template <typename T>
139  void QSort(T *sa, int na,
140  int (*comp)(const T& , const T& ) = gnsstk::Qsort_compare)
141  {
142  int i, j, nr;
143  T stemp, spart;
144  while (1)
145  {
146  if (na < 8)
147  { // use insert sort for small arrays
148  insert(sa, na, comp);
149  return;
150  }
151  spart = sa[na / 2]; // pick middle element as pivot
152  i = -1;
153  j = na;
154  while (1)
155  {
156  do
157  { // find first element to move right
158  i = i + 1;
159  } while (comp(sa[i], spart) < 0);
160  do
161  { // find first element to move left
162  j = j - 1;
163  } while (comp(sa[j], spart) > 0);
164  // if the boundaries have met,
165  // through paritioning,
166  if (i >= j)
167  {
168  break;
169  }
170  // swap i and j elements
171  stemp = sa[i];
172  sa[i] = sa[j];
173  sa[j] = stemp;
174  }
175  nr = na - i;
176  if (i < (na / 2))
177  { // now sort each partition
178  QSort(sa, i, comp); // sort left side
179  sa = &sa[i]; // sort right side here
180  na = nr; // memsort(&(sa[i]),nr,comp);
181  }
182  else
183  {
184  QSort(&(sa[i]), nr, comp); // sort right side
185  na = i;
186  }
187  }
188  } // end QSort
189 
197  template <typename T, typename S>
198  void insert(T *sa, S *pa, int na,
199  int (*comp)(const T& , const T& ) = gnsstk::Qsort_compare)
200  {
201  int i, j;
202  T stemp;
203  S ptemp;
204  for (i = 1; i < na; i = i + 1)
205  { // insert the i-th element into the sorted array
206  stemp = sa[i];
207  ptemp = pa[i];
208  j = i - 1; // find where it goes
209  while ((j >= 0) && (comp(stemp, sa[j]) < 0))
210  {
211  sa[j + 1] = sa[j];
212  pa[j + 1] = pa[j];
213  j = j - 1;
214  }
215  sa[j + 1] = stemp;
216  pa[j + 1] = ptemp;
217  }
218  } // end insert sort
219 
228  template <typename T, typename S>
229  void QSort(T *sa, S *pa, int na,
230  int (*comp)(const T& , const T& ) = gnsstk::Qsort_compare)
231  {
232  int i, j, nr;
233  T stemp, spart;
234  S ptemp;
235  while (1)
236  {
237  if (na < 8)
238  { // use insert sort for small arrays
239  insert(sa, pa, na, comp);
240  return;
241  }
242  spart = sa[na / 2]; // pick middle element as pivot
243  i = -1;
244  j = na;
245  while (1)
246  {
247  do
248  { // find first element to move right
249  i = i + 1;
250  } while (comp(sa[i], spart) < 0);
251  do
252  { // find first element to move left
253  j = j - 1;
254  } while (comp(sa[j], spart) > 0);
255  // if the boundaries have met,
256  // through paritioning,
257  if (i >= j)
258  {
259  break;
260  }
261  // swap i and j elements
262  stemp = sa[i];
263  ptemp = pa[i];
264  sa[i] = sa[j];
265  pa[i] = pa[j];
266  sa[j] = stemp;
267  pa[j] = ptemp;
268  }
269  nr = na - i;
270  if (i < (na / 2))
271  { // now sort each partition
272  QSort(sa, pa, i, comp); // sort left side
273  sa = &sa[i]; // sort right side here
274  pa = &pa[i];
275  na = nr; // memsort(&(sa[i]),nr,comp);
276  }
277  else
278  {
279  QSort(&(sa[i]), &(pa[i]), nr, comp); // sort right side
280  na = i;
281  }
282  }
283  } // end QSort
284 
292  template <typename T> T errfc(T x)
293  {
294  T t, z, ret;
295  z = ::fabs(x);
296  t = T(1) / (T(1) + z / T(2));
297  ret =
298  t *
299  ::exp(-z * z - 1.26551223 +
300  t * (1.00002368 +
301  t * (0.37409196 +
302  t * (0.09678418 +
303  t * (-0.18628806 +
304  t * (0.27886807 +
305  t * (-1.13520398 +
306  t * (1.48851587 +
307  t * (-0.82215223 +
308  t * 0.17087277)))))))));
309  return (x >= T(0) ? ret : T(2) - ret);
310  } // end errfc
311 
321  template <typename T> T normalCDF(T m, T s, T x)
322  {
323  if (s == T(0))
324  {
325  return T(0);
326  }
327  T arg = (x - m) / (::sqrt(T(2.0)) * s);
328  return (T(1) - errfc<T>(arg) / T(2));
329  } // end normal CDF
330 
345  double ADtest(double *xd, const int nd, double m, double s,
346  bool save_flag = true);
347 
348  //--------------------------------------------------------------------------------
350  namespace Robust
351  {
361  template <typename T> T Median(T *xd, const int nd, bool save_flag = true)
362  {
363  if (!xd || nd < 2)
364  {
365  Exception e("Invalid input");
366  GNSSTK_THROW(e);
367  }
368 
369  try
370  {
371  int i;
372  T med, *save = NULL;
373 
374  if (save_flag)
375  {
376  save = new T[nd];
377  if (!save)
378  {
379  Exception e("Could not allocate temporary array");
380  GNSSTK_THROW(e);
381  }
382  for (i = 0; i < nd; i++)
383  save[i] = xd[i];
384  }
385 
386  QSort(xd, nd);
387 
388  if (nd % 2)
389  {
390  med = xd[(nd + 1) / 2 - 1];
391  }
392  else
393  {
394  med = (xd[nd / 2 - 1] + xd[nd / 2]) / T(2);
395  }
396 
397  // restore original data from temporary
398  if (save_flag)
399  {
400  for (i = 0; i < nd; i++)
401  xd[i] = save[i];
402  delete[] save;
403  }
404 
405  return med;
406  }
407  catch (Exception &e)
408  {
409  GNSSTK_RETHROW(e);
410  }
411 
412  } // end Median
413 
424  template <typename T>
425  void Quartiles(const T *xd, const int nd, T& Q1, T& Q3)
426  {
427  if (!xd || nd < 2)
428  {
429  Exception e("Invalid input");
430  GNSSTK_THROW(e);
431  }
432 
433  int q;
434  if (nd % 2)
435  {
436  q = (nd + 1) / 2;
437  }
438  else
439  {
440  q = nd / 2;
441  }
442 
443  if (q % 2)
444  {
445  Q1 = xd[(q + 1) / 2 - 1];
446  Q3 = xd[nd - (q + 1) / 2];
447  }
448  else
449  {
450  Q1 = (xd[q / 2 - 1] + xd[q / 2]) / T(2);
451  Q3 = (xd[nd - q / 2] + xd[nd - q / 2 - 1]) / T(2);
452  }
453  } // end Quartiles
454 
466  template <typename T>
467  T MedianAbsoluteDeviation(T *xd, int nd, T& M, bool save_flag = true)
468  {
469  int i;
470  T mad, *save;
471 
472  if (!xd || nd < 2)
473  {
474  Exception e("Invalid input");
475  GNSSTK_THROW(e);
476  }
477 
478  // store data in a temporary array
479  if (save_flag)
480  {
481  save = new T[nd];
482  if (!save)
483  {
484  Exception e("Could not allocate temporary array");
485  GNSSTK_THROW(e);
486  }
487  for (i = 0; i < nd; i++)
488  save[i] = xd[i];
489  }
490 
491  // get the median (don't care if xd gets sorted...)
492  M = Median(xd, nd, false);
493 
494  // compute xd=abs(xd-M)
495  for (i = 0; i < nd; i++)
496  xd[i] = ABSOLUTE(xd[i] - M);
497 
498  // sort xd in ascending order
499  QSort(xd, nd);
500 
501  // find median and normalize to get mad
502  mad = Median(xd, nd, false) / T(RobustTuningE);
503 
504  // restore original data from temporary
505  if (save_flag)
506  {
507  for (i = 0; i < nd; i++)
508  xd[i] = save[i];
509  delete[] save;
510  }
511 
512  return mad;
513 
514  } // end MedianAbsoluteDeviation
515 
520  template <typename T> T MAD(T *xd, int nd, T& M, bool save_flag = true)
521  {
522  return MedianAbsoluteDeviation(xd, nd, M, save_flag);
523  }
524 
539  // TD return a sigma - just form RMS(xd-mest)
540  template <typename T>
541  T MEstimate(const T *xd, int nd, const T& M, const T& MAD, T *w = NULL)
542  {
543  try
544  {
545  T tv, m, mold, sum, sumw, *wt, weight;
546  T tol = 0.000001;
547  int i, n, N = 10; // N is the max number of iterations
548 
549  if (!xd || nd < 2)
550  {
551  Exception e("Invalid input");
552  GNSSTK_THROW(e);
553  }
554 
555  tv = T(RobustTuningT) * MAD;
556  n = 0;
557  m = M;
558  do
559  {
560  mold = m;
561  n++;
562  sum = sumw = T();
563  for (i = 0; i < nd; i++)
564  {
565  if (w)
566  {
567  wt = &w[i];
568  }
569  else
570  {
571  wt = &weight;
572  }
573  *wt = T(1);
574  if (xd[i] < m - tv)
575  {
576  *wt = -tv / (xd[i] - m);
577  }
578  else if (xd[i] > m + tv)
579  {
580  *wt = tv / (xd[i] - m);
581  }
582  sumw += (*wt);
583  sum += (*wt) * xd[i];
584  }
585  m = sum / sumw;
586 
587  } while (T(ABSOLUTE((m - mold) / m)) > tol && n < N);
588 
589  return m;
590  }
591  catch (Exception& e)
592  {
593  GNSSTK_RETHROW(e);
594  }
595 
596  } // end MEstimate
597 
621  int RobustPolyFit(double *xd, const double *td, int nd, int n, double *c,
622  double *w = NULL);
623 
634  void StemLeafPlot(std::ostream& os, double *xd, long nd,
635  const std::string& msg = std::string(""));
636 
647  void Quantiles(double *xd, long nd);
648 
649  } // namespace Robust
650 
652 
653 } // end namespace gnsstk
654 
655 #undef ABSOLUTE
656 
657 #endif
gnsstk::ADtest
double ADtest(double *xd, const int nd, double m, double s, bool save_flag=true)
Definition: RobustStats.cpp:561
gnsstk::Robust::Quantiles
void Quantiles(double *xd, long nd)
Definition: RobustStats.cpp:350
gnsstk::Robust::Median
T Median(T *xd, const int nd, bool save_flag=true)
Definition: RobustStats.hpp:361
gnsstk::normalCDF
T normalCDF(T m, T s, T x)
Definition: RobustStats.hpp:321
gnsstk::sum
T sum(const ConstVectorBase< T, BaseClass > &l)
Definition: VectorBaseOperators.hpp:84
NULL
#define NULL
Definition: getopt1.c:64
gnsstk::errfc
T errfc(T x)
Definition: RobustStats.hpp:292
gnsstk::Robust::Quartiles
void Quartiles(const T *xd, const int nd, T &Q1, T &Q3)
Definition: RobustStats.hpp:425
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::Exception
Definition: Exception.hpp:151
nd
int nd
Definition: IERS1996NutationData.hpp:44
arg
double arg
Definition: IERS1996UT1mUTCData.hpp:48
gnsstk::insert
void insert(T *sa, int na, int(*comp)(const T &, const T &)=gnsstk::Qsort_compare)
Definition: RobustStats.hpp:111
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
RobustTuningT
#define RobustTuningT
tuning constant used in M-estimate and Robust least squares (SRIFilter.cpp)
Definition: RobustStats.hpp:63
Exception.hpp
gnsstk::QSort
void QSort(T *sa, int na, int(*comp)(const T &, const T &)=gnsstk::Qsort_compare)
Definition: RobustStats.hpp:139
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
RobustTuningE
#define RobustTuningE
tuning constant used in MAD
Definition: RobustStats.hpp:69
gnsstk::Robust::RobustPolyFit
int RobustPolyFit(double *xd, const double *td, int nd, int n, double *c, double *w=NULL)
Definition: RobustStats.cpp:368
ABSOLUTE
#define ABSOLUTE(x)
Definition: RobustStats.hpp:60
gnsstk::Robust::MAD
T MAD(T *xd, int nd, T &M, bool save_flag=true)
Definition: RobustStats.hpp:520
gnsstk::Robust::MEstimate
T MEstimate(const T *xd, int nd, const T &M, const T &MAD, T *w=NULL)
Definition: RobustStats.hpp:541
gnsstk::mad
T mad(const gnsstk::Vector< T > &v)
median absolute deviation of a gnsstk::Vector
Definition: Stats.hpp:85
gnsstk::Qsort_compare
int Qsort_compare(const T &a, const T &b)
Definition: RobustStats.hpp:86
gnsstk::Robust::StemLeafPlot
void StemLeafPlot(std::ostream &os, double *xd, long nd, const std::string &msg=std::string(""))
Definition: RobustStats.cpp:70
gnsstk::Robust::MedianAbsoluteDeviation
T MedianAbsoluteDeviation(T *xd, int nd, T &M, bool save_flag=true)
Definition: RobustStats.hpp:467


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