SRI.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 
49 // -----------------------------------------------------------------------------------
50 // system
51 #include <algorithm>
52 #include <ostream>
53 #include <string>
54 #include <vector>
55 // geomatics
56 #include "Namelist.hpp"
57 #include "SRI.hpp"
58 // GNSSTk
59 #include "StringUtils.hpp"
60 
61 using namespace std;
62 
63 namespace gnsstk
64 {
65  using namespace StringUtils;
66 
67  // -----------------------------------------------------------------------------
68  // used to mark optional input
71 
72  //---------------------------------------------------------------------------------
73  // constructor given the dimension N.
74  SRI::SRI(const unsigned int N)
75  {
76  R = Matrix<double>(N, N, 0.0);
77  Z = Vector<double>(N, 0.0);
78  names = Namelist(N);
79  }
80 
81  // -----------------------------------------------------------------------------
82  // constructor given a Namelist, its dimension determines the SRI dimension.
83  SRI::SRI(const Namelist& nl)
84  {
85  if (nl.size() <= 0)
86  {
87  return;
88  }
89  R = Matrix<double>(nl.size(), nl.size(), 0.0);
90  Z = Vector<double>(nl.size(), 0.0);
91  names = nl;
92  }
93 
94  // -----------------------------------------------------------------------------
95  // explicit constructor - throw if the dimensions are inconsistent.
96  SRI::SRI(const Matrix<double>& r, const Vector<double>& z,
97  const Namelist& nl)
98  {
99  if (r.rows() != r.cols() || r.rows() != z.size() || r.rows() != nl.size())
100  {
101  MatrixException me(
102  "Invalid dimensions in explicit SRI constructor:\n R is " +
103  asString<int>(r.rows()) + "x" + asString<int>(r.cols()) +
104  ", Z has length " + asString<int>(z.size()) +
105  " and NL has length " + asString<int>(nl.size()));
106  GNSSTK_THROW(me);
107  }
108  if (r.rows() <= 0)
109  {
110  return;
111  }
112  R = r;
113  Z = z;
114  names = nl;
115  }
116 
117  // -----------------------------------------------------------------------------
118  // define from covariance and state
119  void SRI::setFromCovState(const Matrix<double>& Cov,
120  const Vector<double>& State, const Namelist& NL)
121  {
122  if (Cov.rows() != Cov.cols() || Cov.rows() != State.size() ||
123  Cov.rows() != NL.size())
124  {
125  MatrixException me(
126  "Invalid dimensions in SRI constructor from Cov,State:\n"
127  " Cov is " +
128  asString<int>(Cov.rows()) + "x" + asString<int>(Cov.cols()) +
129  ", State has length " + asString<int>(State.size()) +
130  " and NL has length " + asString<int>(NL.size()));
131  GNSSTK_THROW(me);
132  }
133  R = inverseUT(upperCholesky(Cov));
134  Z = R * State;
135  names = NL;
136  }
137 
138  // -----------------------------------------------------------------------------
139  // copy constructor
140  SRI::SRI(const SRI& s)
141  {
142  R = s.R;
143  Z = s.Z;
144  names = s.names;
145  }
146 
147  // -----------------------------------------------------------------------------
148  // operator=
149  SRI& SRI::operator=(const SRI& right)
150  {
151  R = right.R;
152  Z = right.Z;
153  names = right.names;
154  return *this;
155  }
156 
157  // ------------------------------------------------------------------------
158  // modify SRIs
159  // -----------------------------------------------------------------------------
160  // Permute the SRI elements to match the input Namelist, which may differ
161  // with the SRI Namelist by AT MOST A PERMUTATION, throw if this is not true.
162  void SRI::permute(const Namelist& nl)
163  {
164  if (identical(names, nl))
165  {
166  return;
167  }
168  if (names != nl)
169  {
170  MatrixException me(
171  "Invalid input: Namelists must be == to w/in permute");
172  GNSSTK_THROW(me);
173  }
174 
175  try
176  {
177  const unsigned int n(R.rows());
178  unsigned int i, j;
179  // build a permutation matrix
180  Matrix<double> P(n, n, 0.0);
181  for (i = 0; i < n; i++)
182  {
183  j = nl.index(names.getName(i));
184  P(j, i) = 1;
185  }
186 
187  // inverse of P is transpose of P
188  retriangularize(R * transpose(P), Z);
189  names = nl;
190  }
191  catch (MatrixException& me)
192  {
193  GNSSTK_RETHROW(me);
194  }
195  catch (VectorException& ve)
196  {
197  GNSSTK_RETHROW(ve);
198  }
199  }
200 
201  // -----------------------------------------------------------------------------
202  /* Split this SRI (call it S) into two others, S1 and Sleft, where S1 has
203  a Namelist identical to the input Namelist (NL); set *this = S1 at the
204  end. NL must be a non-empty subset of names, and (names ^ NL) also must
205  be non-empty; throw MatrixException if this is not true. The second
206  output SRI, Sleft, will have the same names as S, but perhaps permuted.
207 
208  The routine works by first permuting S so that its Namelist if of the
209  form {N2,NL}, where N2 = (names ^ NL); this is possible only if NL is
210  a non-trivial subset of names. Then, the rows of S (rows of R and elements
211  of Z) naturally separate into the two component SRIs, with zeros in the
212  elements of the first SRI which correspond to N2, and those in Sleft
213  which correspond to NL.
214 
215  Example: S.name = A B C D E F G and NL = D E F G.
216  (Obviously, S may be permuted into such an order whenever this is needed.)
217  Note that here the R,Z pair is written in a format reminiscent of the
218  set of equations implied by R*X=Z, i.e. 1A+2B+3C+4D+5E+6F+7G=a, etc.
219 
220  S (R Z) = S1 + Sleft
221  with names NL names
222  A B C D E F G . . . D E F G A B C D E F G
223  - - - - - - - - - - - - - - - - - - - - - - - -
224  1 2 3 4 5 6 7 a = . . . . . . . . + 1 2 3 4 5 6 7 a
225  8 9 1 2 3 4 b . . . . . . . 8 9 1 2 3 4 b
226  5 6 7 8 9 c . . . . . . 5 6 7 8 9 c
227  1 2 3 4 d 1 2 3 4 d . . . . d
228  5 6 7 e 5 6 7 e . . . e
229  8 9 f 8 9 f . . f
230  1 g 1 g . g
231 
232  where "." denotes a zero. The split is simply separating the linear
233  equations which make up R*X=Z into two groups; because of the ordering,
234  one of the groups of equations (S1) depends only on a particular subset
235  of the elements of the state vector, i.e. the elements labeled by the
236  Namelist NL.
237 
238  The equation shown here is an information equation; if the two SRIs S1
239  and Sleft were merged again, none of the information would be lost.
240  Note that S1 has no dependence on A B C (hence the .'s), and therefore
241  its size can be reduced. However Sleft still depends on the full names
242  Namelist. Sleft is necessarily singular, but S1 is not.
243 
244  Note that the SRI contains information about both the solution and
245  the covariance, i.e. state and noise, and therefore one must be very
246  careful in interpreting the results of split and merge (operator+=). [Be
247  especially careful about the idea that a merge might be reversible with a
248  split() or vice-versa - strictly this is never possible unless the
249  Namelists are mutually exclusive - two separate problems.]
250 
251  For example, suppose two different SRI's, which have some elements in
252  common, are merged. The combined SRI will have more information (it can't
253  have less) about the common elements, and therefore the solution will be
254  'better' (assuming the underlying model equations for those elements are
255  identical). However the noises will also be combined, and the results you
256  get might be surprising. Also, note that if you then split the combined
257  SRI again, the solution won't change but the noises will be very
258  different; in particular the new split part will take all the information
259  with it, so the common states will have lower noise than they did in the
260  original SRI. See the test program tsri.cpp */
261  void SRI::split(const Namelist& NL, SRI& Sleft)
262  {
263  try
264  {
265  Sleft = SRI(0);
266  unsigned int n, m;
267  n = NL.size();
268  m = names.size();
269  if (n >= m)
270  {
271  MatrixException me(
272  "split: Input Namelist must be a subset of this one");
273  GNSSTK_THROW(me);
274  }
275 
276  unsigned int i, j;
277  // copy names and permute it so that its end matches NL
278  Namelist N0(names);
279  for (i = 1; i <= n; i++)
280  { // loop (backwards) over names in NL
281  for (j = 1; j <= m; j++)
282  { // search (backwards) in NO for a match
283  if (NL.labels[n - i] == N0.labels[m - j])
284  { // if found a match
285  N0.swap(m - i, m - j); // then move matching name to end
286  break; // and go on to next name in NL
287  }
288  }
289  if (j > m)
290  {
291  MatrixException me(
292  "split: Input Namelist is not non-trivial subset");
293  GNSSTK_THROW(me);
294  }
295  }
296 
297  // copy *this into Sleft, then do the permutation
298  Sleft = *this;
299  Sleft.permute(N0);
300 
301  // copy parts of Sleft into S1, and then zero out those parts of Sleft
302  SRI S1(NL);
303  S1.R = Matrix<double>(Sleft.R, m - n, m - n, n, n);
304  S1.Z.resize(n);
305  for (i = 0; i < n; i++)
306  S1.Z(i) = Sleft.Z(m - n + i);
307  for (i = m - n; i < m; i++)
308  Sleft.zeroOne(i);
309 
310  *this = S1;
311  }
312  catch (MatrixException& me)
313  {
314  GNSSTK_RETHROW(me);
315  }
316  catch (VectorException& ve)
317  {
318  GNSSTK_RETHROW(ve);
319  }
320  }
321 
322  /* -----------------------------------------------------------------------------
323  extend this SRI to include the given Namelist, with no added information;
324  names in the input namelist which are not unique are ignored. */
325  SRI& SRI::operator+=(const Namelist& NL)
326  {
327  try
328  {
329  Namelist B(names);
330  // NB assume that Namelist::operator|=() adds at the _end_
331  // NB if there are duplicate names, |= will not add them
332  B |= NL;
333  // NB assume that this zeros A.R and A.Z
334  SRI A(B);
335  // should do this with slices..
336  // copy into the new SRI
337  for (unsigned int i = 0; i < R.rows(); i++)
338  {
339  A.Z(i) = Z(i);
340  for (unsigned int j = 0; j < R.cols(); j++)
341  A.R(i, j) = R(i, j);
342  }
343  *this = A;
344  return *this;
345  }
346  catch (MatrixException& me)
347  {
348  GNSSTK_RETHROW(me);
349  }
350  catch (VectorException& ve)
351  {
352  GNSSTK_RETHROW(ve);
353  }
354  }
355 
356  /* -----------------------------------------------------------------------------
357  reshape this SRI to match the input Namelist, by calling other member
358  functions, including split(), operator+() and permute()
359  Given this SRI and a new Namelist NL, if NL does not match names,
360  transform names to match it, using (1) drop elements (this is probably
361  optional - you can always keep 'dead' elements), (2) add new elements
362  (with zero information), and (3) permute to match NL. */
363  void SRI::reshape(const Namelist& NL)
364  {
365  try
366  {
367  if (names == NL)
368  {
369  return;
370  }
371  Namelist keep(names);
372  keep &= NL; // keep only those in both names and NL
373  // Namelist drop(names); // (drop is unneeded - split would do it)
374  // drop ^= keep; // lose those in names but not in keep
375  Namelist add(NL);
376  add ^= keep; // add those in NL but not in keep
377  SRI Sdrop; // make a new SRI to hold the losers
378  // would like to allow caller access to Sdrop..
379  split(keep, Sdrop); // split off only the losers
380  // NB names = drop | keep; drop & keep is empty
381  *this += add; // add the new ones
382  this->permute(NL); // permute it to match NL
383  }
384  catch (MatrixException& me)
385  {
386  GNSSTK_RETHROW(me);
387  }
388  catch (VectorException& ve)
389  {
390  GNSSTK_RETHROW(ve);
391  }
392  }
393 
394  /* -----------------------------------------------------------------------------
395  append an SRI onto this SRI. Similar to opertor+= but simpler; input SRI
396  is simply appended, first using operator+=(Namelist), then filling the new
397  portions of R and Z, all without final Householder transformation of
398  result. Do not allow a name that is already present to be added: throw. */
399  SRI& SRI::append(const SRI& S)
400  {
401  try
402  {
403  // do not allow duplicates
404  if ((names & S.names).size() > 0)
405  {
406  Exception e("Cannot append duplicate names");
407  GNSSTK_THROW(e);
408  }
409 
410  // append to names at the end, and to R Z, zero filling
411  const size_t I(names.size());
412  *this += S.names;
413 
414  // just in case...to avoid overflow in loop below
415  if (I + S.names.size() != names.size())
416  {
417  Exception e("Append failed");
418  GNSSTK_THROW(e);
419  }
420 
421  // loop over new names, copying data from input into the new SRI
422  for (size_t i = 0; i < S.names.size(); i++)
423  {
424  Z(I + i) = S.Z(i);
425  for (size_t j = 0; j < S.names.size(); j++)
426  R(I + i, I + j) = S.R(i, j);
427  }
428 
429  return *this;
430  }
431  catch (MatrixException& me)
432  {
433  GNSSTK_RETHROW(me);
434  }
435  catch (VectorException& ve)
436  {
437  GNSSTK_RETHROW(ve);
438  }
439  }
440 
441  /* -----------------------------------------------------------------------------
442  merge this SRI with the given input SRI. ? should this be operator&=() ?
443  NB may reorder the names in the resulting Namelist. */
444  SRI& SRI::operator+=(const SRI& S)
445  {
446  try
447  {
448  Namelist all(names);
449  all |= S.names; // assumes Namelist::op|= adds unique S.names to _end_
450 
451  // all.sort(); // TEMP - for testing with old version
452 
453  // stack the (R|Z)'s from both in one matrix;
454  // all determines the columns, plus last column is for Z
455  unsigned int i, j, n, m, sm;
456  n = all.labels.size();
457  m = R.rows();
458  sm = S.R.rows();
459  Matrix<double> A(m + sm, n + 1, 0.0);
460 
461  // copy R into A, permuting columns as names differs from all
462  // loop over columns of R; do Z at the same time using j=row
463  for (j = 0; j < m; j++)
464  {
465  // find where this column of R goes in A
466  // (should never throw..)
467  int k = all.index(names.labels[j]);
468  if (k == -1)
469  {
470  MatrixException me("Algorithm error 1");
471  GNSSTK_THROW(me);
472  }
473 
474  // copy this col of R into A (R is UT)
475  for (i = 0; i <= j; i++)
476  A(i, k) = R(i, j);
477  // also the jth element of Z
478  A(j, n) = Z(j);
479  }
480 
481  // now do the same for S, but put S.R|S.Z below R|Z
482  for (j = 0; j < sm; j++)
483  {
484  int k = all.index(S.names.labels[j]);
485  if (k == -1)
486  {
487  MatrixException me("Algorithm error 2");
488  GNSSTK_THROW(me);
489  }
490  for (i = 0; i <= j; i++)
491  A(m + i, k) = S.R(i, j);
492  A(m + j, n) = S.Z(j);
493  }
494 
495  // now triangularize A and pull out the new R and Z
496  // DONT - dimensions change - retriangularize(A);
498  HA(A);
499  // submatrix args are matrix,toprow,topcol,numrows,numcols
500  R = Matrix<double>(HA.A, 0, 0, n, n);
501  Z = Vector<double>(HA.A.colCopy(n));
502  Z.resize(n);
503  names = all;
504 
505  return *this;
506  }
507  catch (MatrixException& me)
508  {
509  GNSSTK_RETHROW(me);
510  }
511  catch (VectorException& ve)
512  {
513  GNSSTK_RETHROW(ve);
514  }
515  }
516 
517  /* -----------------------------------------------------------------------------
518  merge two SRIs to produce a third. ? should this be operator&() ? */
519  SRI operator+(const SRI& Sleft, const SRI& Sright)
520  {
521  try
522  {
523  SRI S(Sleft);
524  S += Sright;
525  return S;
526  }
527  catch (MatrixException& me)
528  {
529  GNSSTK_RETHROW(me);
530  }
531  catch (VectorException& ve)
532  {
533  GNSSTK_RETHROW(ve);
534  }
535  }
536 
537  /* -----------------------------------------------------------------------------
538  Zero out the nth row of R and the nth element of Z, removing all
539  information about that element. */
540  void SRI::zeroOne(const unsigned int n)
541  {
542  if (n >= R.rows())
543  {
544  return;
545  }
546 
547  for (unsigned int j = n; j < R.cols(); j++) {
548  R(n, j) = 0.0;
549  }
550  Z(n) = 0.0;
551  }
552 
553  /* -----------------------------------------------------------------------------
554  Zero out all the first n rows of R and elements of Z, removing all
555  information about those elements. Default value of the input is 0,
556  meaning zero out the entire SRI. */
557  void SRI::zeroAll(const unsigned int n)
558  {
559  if (n <= 0)
560  {
561  R = 0.0;
562  Z = 0.0;
563  return;
564  }
565 
566  if (n >= int(R.rows()))
567  {
568  return;
569  }
570 
571  for (unsigned int i = 0; i < n; i++)
572  {
573  for (unsigned int j = i; j < R.cols(); j++) {
574  R(i, j) = 0.0;
575  }
576  Z(i) = 0.0;
577  }
578  }
579 
580  /* -----------------------------------------------------------------------------
581  Shift the state vector by a constant vector X0; does not change
582  information i.e. let R * X = Z => R * (X-X0) = Z' throw on invalid input
583  dimension */
584  void SRI::shift(const Vector<double>& X0)
585  {
586  if (X0.size() != R.cols())
587  {
588  MatrixException me("Invalid input dimension: SRI has dimension " +
589  asString<int>(R.rows()) +
590  " while input has length " +
591  asString<int>(X0.size()));
592  GNSSTK_THROW(me);
593  }
594  Z = Z - R * X0;
595  }
596 
597  /* -----------------------------------------------------------------------------
598  Shift the SRI state vector (Z) by a constant vector Z0;
599  does not change information. i.e. let Z => Z-Z0
600  throw on invalid input dimension */
601  void SRI::shiftZ(const Vector<double>& Z0)
602  {
603  if (Z0.size() != R.cols())
604  {
605  MatrixException me("Invalid input dimension: SRI has dimension " +
606  asString<int>(R.rows()) +
607  " while input has length " +
608  asString<int>(Z0.size()));
609  GNSSTK_THROW(me);
610  }
611  Z = Z - Z0;
612  }
613 
614  /* -----------------------------------------------------------------------------
615  Retriangularize the SRI, when it has been modified to a non-UT matrix
616  (e.g. by transform()). Given the matrix A=[R||Z], apply HH transforms
617  to retriagularize it and pull out new R and Z.
618  param A Matrix<double> which is [R || Z] to be retriangularizied.
619  throw if dimensions are wrong. */
620  void SRI::retriangularize(const Matrix<double>& A)
621  {
622  const unsigned int n(R.rows());
623  if (A.rows() != n || A.cols() != n + 1)
624  {
625  MatrixException me("Invalid input dimension: SRI has dimension " +
626  asString<int>(n) + " while input has dimension " +
627  asString<int>(A.rows()) + "x" +
628  asString<int>(A.cols()));
629  GNSSTK_THROW(me);
630  }
631 
633  HA(A);
634  // submatrix args are matrix,toprow,topcol,numrows,numcols
635  R = Matrix<double>(HA.A, 0, 0, n, n);
636  Z = Vector<double>(HA.A.colCopy(n));
637  // NB names cannot be changed - caller must do it.
638  }
639 
640  /* Retriangularize the SRI, that is assuming R has been modified to a non-UT
641  matrix (e.g. by transform()). Given RR and ZZ, apply HH transforms to
642  retriangularize, and store as R,Z.
643  @param R Matrix<double> input the modified (non-UT) R
644  @param Z Vector<double> input the (potentially) modified Z
645  @throw if dimensions are wrong. */
646  void SRI::retriangularize(Matrix<double> RR, Vector<double> ZZ)
647  {
648  const unsigned int n(R.rows());
649  if (RR.rows() != n || RR.cols() != n || ZZ.size() != n)
650  {
651  MatrixException me(
652  "Invalid input dimension: SRI has dimension " + asString<int>(n) +
653  " while input has dimension " + asString<int>(RR.rows()) + "x" +
654  asString<int>(RR.cols()) + " and " + asString<int>(ZZ.size()));
655  GNSSTK_THROW(me);
656  }
657 
658  Matrix<double> A(RR || ZZ);
659  retriangularize(A);
660  }
661 
662  /* -----------------------------------------------------------------------------
663  Apply transformation matrix T to the SRI; i.e. X -> T*X, Cov -> T*Cov*T^T
664  X' = T*X, C' = T*C*T^T = (TR^-1)(TR^-1)^T = R'^-1*R'^-T;
665  but then Z' = R'*X' = R'TX = RT^-1TX = RX = Z
666  This implies right multiplying R by inverse(T), which is the input, and
667  then using HH to retriangularize. Input is the _inverse_ of the
668  transformation. SRI.names is set to input Namelist throw MatrixException
669  if input dimensions are wrong. */
670  void SRI::transform(const Matrix<double>& invT, const Namelist& NL)
671  {
672  const unsigned int n(R.rows());
673  if (invT.rows() != n || invT.cols() != n)
674  {
675  MatrixException me("Invalid input dimension: SRI has dimension " +
676  asString<int>(n) + " while invT has dimension " +
677  asString<int>(invT.rows()) + "x" +
678  asString<int>(invT.cols()));
679  GNSSTK_THROW(me);
680  }
681 
682  R = R * invT;
683  retriangularize(R, Z);
684  names = NL;
685  }
686 
687  /* -----------------------------------------------------------------------------
688  Decrease the information in this SRI for, or 'Q bump', the element
689  with the input index. This means that the uncertainty and the state
690  element given by the index are divided by the input factor q; the
691  default input is zero, which means zero out the information (q =
692  infinite). A Q bump by factor q is equivalent to 'de-weighting' the
693  element by q. No effect if input index is out of range.
694 
695  Use a specialized form of the time update, with Phi=unity, G(N x 1) = 0
696  except 1 for the element (in) getting bumped, and Rw(1 x 1) = 1 / q.
697  Note that this bump of the covariance for element k results in
698  Cov(k,k) += q (plus, not times!).
699  if q is 0, replace q with 1/q, i.e. lose all information, covariance
700  goes singular; this is equivalent to (1) permute so that the 'in'
701  element is first, (2) zero out the first row of R and the first element
702  of Z, (3) permute the first row back to in. */
703  void SRI::Qbump(const unsigned int in, double q)
704  {
705  try
706  {
707  if (in >= R.rows())
708  {
709  return;
710  }
711  double factor = 0.0;
712  if (q != 0.0)
713  {
714  factor = 1.0 / q;
715  }
716 
717  unsigned int ns = 1, i, j, n = R.rows();
718 
719  Matrix<double> A(n + ns, n + ns + 1, 0.0), G(n, ns, 0.0);
720  A(0, 0) = factor; // Rw, dimension ns x ns = 1 x 1
721  G(in, 0) = 1.0;
722  G = R * G; // R*Phi*G
723  for (i = 0; i < n; i++)
724  {
725  A(ns + i, 0) = -G(i, 0); // A = Rw 0 zw=0
726  for (j = 0; j < n; j++) // -R*Phi*G R*Phi Z
727  if (i <= j)
728  {
729  A(ns + i, ns + j) = R(i, j); //
730  }
731  A(ns + i, ns + n) = Z(i);
732  }
733 
734  /* triangularize and pull out the new R and Z
735  NB do not call retriangularize() here! */
736  Householder<double> HA; // A = Rw Rwx zw
737  HA(A); // 0 R z
738  R = Matrix<double>(HA.A, ns, ns, n, n);
739  Vector<double> T = HA.A.colCopy(ns + n);
740  Z = Vector<double>(T, ns, n);
741  }
742  catch (MatrixException& me)
743  {
744  GNSSTK_RETHROW(me);
745  }
746  catch (VectorException& ve)
747  {
748  GNSSTK_RETHROW(ve);
749  }
750  }
751 
752  /* -----------------------------------------------------------------------------
753  Fix one state element (with the given name) to a given value, and set the
754  information for that element (== 1/sigma) to a given value.
755  No effect if name is not found
756  param name string labeling the state in Namelist names
757  param value to which the state element is fixed
758  param sigma (1/information) assigned to the element */
759  void SRI::stateFix(const std::string& name, double value,
760  double sigma, bool restore)
761  {
762  int index = names.index(name);
763  if (index == -1)
764  {
765  return;
766  }
767  stateFix((unsigned int)(index), value, sigma, restore);
768  }
769 
770  /* -----------------------------------------------------------------------------
771  Fix one state element (at the given index) to a given value, and set the
772  information for that element (== 1/sigma) to a given value.
773  No effect if index is out of range.
774  param index of the element to fix
775  param value to which the state element is fixed
776  param sigma (1/information) assigned to the element */
777  void SRI::stateFix(const unsigned int index, double value,
778  double sigma, bool restore)
779  {
780  if (index >= names.size())
781  {
782  GNSSTK_THROW(Exception("Index out of range"));
783  }
784  const unsigned int N(names.size());
785 
786  // make a namelist with the desired element last
787  Namelist NL(names);
788  if (index != N - 1)
789  {
790  NL.swap(index, N - 1);
791  permute(NL);
792  }
793 
794  // fix the element and information
795  Z(N - 1) = value / sigma;
796  R(N - 1, N - 1) = 1.0 / sigma;
797 
798  // permute back, if the caller wants
799  if (restore && index != N - 1)
800  {
801  NL = names;
802  NL.swap(index, N - 1);
803  permute(NL);
804  }
805  }
806 
807  /* -----------------------------------------------------------------------------
808  Fix the state element with the input index to the input value, and
809  collapse the SRI by removing that element.
810  No effect if index is out of range. */
811  void SRI::stateFixAndRemove(const unsigned int in, double bias)
812  {
813  if (in >= R.rows())
814  {
815  return;
816  }
817 
818  try
819  {
820  unsigned int i, j, ii, jj, n = R.rows();
821  Vector<double> Znew(n - 1, 0.0);
822  Matrix<double> Rnew(n - 1, n - 1, 0.0);
823  // move the X(in) terms to the data vector on the RHS
824  for (i = 0; i < in; i++)
825  Z(i) -= R(i, in) * bias;
826  // remove row/col in and collapse
827  for (i = 0, ii = 0; i < n; i++)
828  {
829  if (i == in)
830  {
831  continue;
832  }
833  Znew(ii) = Z(i);
834  for (j = i, jj = ii; j < n; j++)
835  {
836  if (j == in)
837  {
838  continue;
839  }
840  Rnew(ii, jj) = R(i, j);
841  jj++;
842  }
843  ii++;
844  }
845  R = Rnew;
846  Z = Znew;
847  names -= names.labels[in];
848  }
849  catch (MatrixException& me)
850  {
851  GNSSTK_RETHROW(me);
852  }
853  catch (VectorException& ve)
854  {
855  GNSSTK_RETHROW(ve);
856  }
857  }
858 
859  /* -----------------------------------------------------------------------------
860  Vector version of stateFixAndRemove with several states given in a
861  Namelist. */
862  void SRI::stateFixAndRemove(const Namelist& dropNL,
863  const Vector<double>& values_in)
864  {
865  try
866  {
867  if (dropNL.size() != values_in.size())
868  {
869  VectorException e("Input has inconsistent lengths");
870  GNSSTK_THROW(e);
871  }
872 
873  /*
874  // build a vector of indexes to keep
875  int i,j;
876  vector<int> indexes;
877  for(i=0; i<names.size(); i++) {
878  j = dropNL.index(names.getName(i)); // index in dropNL,
879  this state if(j == -1) indexes.push_back(i);// not found in dropNL,
880  so keep
881  }
882 
883  const int n=indexes.size(); // new dimension
884  if(n == 0) {
885  Exception e("Cannot drop all states");
886  GNSSTK_THROW(e);
887  }
888 
889  Vector<double> X,newX(n);
890  Matrix<double> C,newC(n,n);
891  Namelist newNL;
892 
893  double big,small;
894  getStateAndCovariance(X,C,&small,&big);
895 
896  for(i=0; i<n; i++) {
897  newX(i) = X(indexes[i]);
898  for(j=0; j<n; j++) newC(i,j) = C(indexes[i],indexes[j]);
899  newNL += names.getName(indexes[i]);
900  }
901 
902  R = Matrix<double>(inverseUT(upperCholesky(newC)));
903  Z = Vector<double>(R*newX);
904  names = newNL;
905  */
906  size_t i, j, k;
907  // create a vector of indexes and corresponding values
908  vector<int> indx;
909  vector<double> value;
910  for (i = 0; i < dropNL.size(); i++)
911  {
912  int in =
913  names.index(dropNL.getName(i)); // in must be allowed to be -1
914  if (in > -1)
915  {
916  indx.push_back(in);
917  value.push_back(values_in(i));
918  }
919  // else nothing happens
920  }
921  const unsigned int m = indx.size();
922  const unsigned int n = R.rows();
923  if (m == 0)
924  {
925  return;
926  }
927  if (m == n)
928  {
929  *this = SRI(0);
930  return;
931  }
932  // move the X(in) terms to the data vector on the RHS
933  for (k = 0; k < m; k++)
934  {
935  for (i = 0; i < indx[k]; i++)
936  {
937  Z(i) -= R(i, indx[k]) * value[k];
938  }
939  }
940 
941  // first remove the rows in indx
942  bool skip;
943  Vector<double> Ztmp(n - m, 0.0);
944  Matrix<double> Rtmp(n - m, n, 0.0);
945  for (i = 0, k = 0; i < n; i++)
946  {
947  skip = false;
948  for (j = 0; j < m; j++)
949  {
950  if ((int)i == indx[j])
951  {
952  skip = true;
953  break;
954  }
955  }
956  if (skip)
957  {
958  continue; // skip row to be dropped
959  }
960 
961  Ztmp(k) = Z(i);
962  for (j = i; j < n; j++)
963  {
964  Rtmp(k, j) = R(i, j);
965  }
966  k++;
967  }
968 
969  // Z is now done
970  Z = Ztmp;
971 
972  // now remove columns in indx
973  R = Matrix<double>(n - m, n - m, 0.0);
974  for (j = 0, k = 0; j < n; j++)
975  {
976  skip = false;
977  for (i = 0; i < m; i++)
978  {
979  if ((int)j == indx[i])
980  {
981  skip = true;
982  break;
983  }
984  }
985  if (skip)
986  {
987  continue; // skip col to be dropped
988  }
989 
990  for (i = 0; i <= j; i++)
991  {
992  R(i, k) = Rtmp(i, j);
993  }
994  k++;
995  }
996 
997  // remove the names
998  for (k = 0; k < dropNL.size(); k++)
999  {
1000  std::string name(dropNL.getName(k));
1001  names -= name;
1002  }
1003  }
1004  catch (MatrixException& me)
1005  {
1006  GNSSTK_RETHROW(me);
1007  }
1008  catch (VectorException& ve)
1009  {
1010  GNSSTK_RETHROW(ve);
1011  }
1012  }
1013 
1014  /*------------------------------------------------------------------------------
1015  Add a priori or 'constraint' information
1016  Prefer addAPrioriInformation(inverse(Cov), inverse(Cov)*X); */
1017  void SRI::addAPriori(const Matrix<double>& Cov, const Vector<double>& X)
1018  {
1019  if (Cov.rows() != Cov.cols() || Cov.rows() != R.rows() ||
1020  X.size() != R.rows())
1021  {
1022  MatrixException me(
1023  "Invalid input dimensions:\n SRI has dimension " +
1024  asString<int>(R.rows()) + ",\n while input is Cov(" +
1025  asString<int>(Cov.rows()) + "x" + asString<int>(Cov.cols()) +
1026  ") and X(" + asString<int>(X.size()) + ").");
1027  GNSSTK_THROW(me);
1028  }
1029 
1030  try
1031  {
1032  Matrix<double> InvCov = inverseLUD(Cov);
1033  addAPrioriInformation(InvCov, X);
1034  }
1035  catch (MatrixException& me)
1036  {
1037  GNSSTK_THROW(me);
1038  }
1039  }
1040 
1041  // -----------------------------------------------------------------------------
1042  void SRI::addAPrioriInformation(const Matrix<double>& InvCov,
1043  const Vector<double>& X)
1044  {
1045  if (InvCov.rows() != InvCov.cols() || InvCov.rows() != R.rows() ||
1046  X.size() != R.rows())
1047  {
1048  MatrixException me(
1049  "Invalid input dimensions:\n SRI has dimension " +
1050  asString<int>(R.rows()) + ",\n while input is InvCov(" +
1051  asString<int>(InvCov.rows()) + "x" + asString<int>(InvCov.cols()) +
1052  ") and X(" + asString<int>(X.size()) + ").");
1053  GNSSTK_THROW(me);
1054  }
1055 
1056  try
1057  {
1058  Matrix<double> L(lowerCholesky(InvCov));
1059  Matrix<double> apR(transpose(L)); // R = UT(inv(Cov))
1060  Vector<double> apZ(apR * X); // Z = R*X
1061  SrifMU(R, Z, apR, apZ);
1062  }
1063  catch (MatrixException& me)
1064  {
1065  GNSSTK_THROW(me);
1066  }
1067  }
1068 
1069  // -----------------------------------------------------------------------------
1070  void SRI::getConditionNumber(double& small, double& big) const
1071  {
1072  try
1073  {
1074  small = big = 0.0;
1075  const int n = R.rows();
1076  if (n == 0)
1077  {
1078  return;
1079  }
1080  SVD<double> svd;
1081  svd(R);
1082  svd.sort(true); // now the last s.v. is the smallest
1083  small = svd.S(n - 1);
1084  big = svd.S(0);
1085  }
1086  catch (MatrixException& me)
1087  {
1088  me.addText("Called by getConditionNumber");
1089  GNSSTK_RETHROW(me);
1090  }
1091  }
1092 
1093  /* -----------------------------------------------------------------------------
1094  Compute state without computing covariance. Use the fact that R is upper
1095  triangular. Throw if and when a zero diagonal element is found; values at
1096  larger index are still valid. On output *ptr is the largest singular index */
1097  void SRI::getState(Vector<double>& X, int *ptr) const
1098  {
1099  const int n = Z.size();
1100  X = Vector<double>(n, 0.0);
1101  if (ptr)
1102  {
1103  *ptr = -1;
1104  }
1105  if (n == 0)
1106  {
1107  return;
1108  }
1109  int i, j;
1110  for (i = n - 1; i >= 0; i--)
1111  { // loop over rows, in reverse order
1112  if (R(i, i) == 0.0)
1113  {
1114  if (ptr)
1115  {
1116  *ptr = i;
1117  }
1118  MatrixException me(
1119  "Singular matrix; zero diagonal element at index " +
1120  asString<int>(i));
1121  GNSSTK_THROW(me);
1122  }
1123  double sum = Z(i);
1124  for (j = i + 1; j < n; j++) // sum over columns to right of diagonal
1125  {
1126  sum -= R(i, j) * X(j);
1127  }
1128  X(i) = sum / R(i, i);
1129  }
1130  }
1131 
1132  /* -----------------------------------------------------------------------------
1133  get the state X and the covariance matrix C of the state, where
1134  C = transpose(inverse(R))*inverse(R) and X = inverse(R) * Z.
1135  Throws MatrixException if R is singular. */
1136  void SRI::getStateAndCovariance(Vector<double>& X, Matrix<double>& C,
1137  double *ptrSmall, double *ptrBig) const
1138  {
1139  try
1140  {
1141  double small, big;
1142  Matrix<double> invR(inverseUT(R, &small, &big));
1143  if (ptrSmall)
1144  {
1145  *ptrSmall = small;
1146  }
1147  if (ptrBig)
1148  {
1149  *ptrBig = big;
1150  }
1151 
1152  // cout << " small is " << scientific << setprecision(3) << small
1153  // << " and big is " << big;
1154  // cout << " exponent is " << ::log(big) - ::log(small) << endl;
1155  // how best to test?
1156  // ::log(big) - ::log(small) + 1 >=
1157  // numeric_limits<double>::max_exponent
1158  if (small <= 10 * numeric_limits<double>::epsilon())
1159  {
1160  MatrixException me("Singular matrix: condition number is " +
1161  asString<double>(big) + " / " +
1162  asString<double>(small));
1163  GNSSTK_THROW(me);
1164  }
1165 
1166  C = UTtimesTranspose(invR);
1167  X = invR * Z;
1168  }
1169  catch (MatrixException& me)
1170  {
1171  GNSSTK_RETHROW(me);
1172  }
1173  catch (VectorException& ve)
1174  {
1175  GNSSTK_RETHROW(ve);
1176  }
1177  }
1178 
1179  //---------------------------------------------------------------------------------
1180  // output operator
1181  ostream& operator<<(ostream& os, const SRI& S)
1182  {
1183  Namelist NLR(S.names);
1184  Namelist NLC(S.names);
1185  NLC += string("State");
1186  Matrix<double> A;
1187  A = S.R || S.Z;
1188  LabeledMatrix LM(NLR, NLC, A);
1189 
1190  ios_base::fmtflags flags = os.flags();
1191  if (flags & ios_base::scientific)
1192  {
1193  LM.scientific();
1194  }
1195  LM.setw(os.width());
1196  LM.setprecision(os.precision());
1197  LM.clean();
1198  // LM.message("NL");
1199  // LM.linetag("tag");
1200 
1201  os << LM;
1202 
1203  return os;
1204  }
1205 
1206 } // end namespace gnsstk
1207 
1208 //------------------------------------------------------------------------------------
1209 //------------------------------------------------------------------------------------
gnsstk::SRINullMatrix
const Matrix< double > SRINullMatrix
constant (empty) Matrix used for default input arguments
Definition: SRI.cpp:69
gnsstk::UTtimesTranspose
Matrix< T > UTtimesTranspose(const Matrix< T > &UT)
Definition: SRIMatrix.hpp:725
gnsstk::inverseLUD
Matrix< T > inverseLUD(const ConstMatrixBase< T, BaseClass > &m)
Definition: MatrixOperators.hpp:591
gnsstk::LabeledMatrix::scientific
LabeledMatrix & scientific()
Set the format to scientific.
Definition: Namelist.hpp:216
gnsstk::Namelist::index
int index(const std::string &name) const
Definition: Namelist.cpp:530
gnsstk::Namelist::labels
std::vector< std::string > labels
vector of names (strings)
Definition: Namelist.hpp:437
gnsstk::lowerCholesky
SparseMatrix< T > lowerCholesky(const SparseMatrix< T > &A)
Definition: SparseMatrix.hpp:2065
StringUtils.hpp
gnsstk::inverseUT
Matrix< T > inverseUT(const Matrix< T > &UT, T *ptrSmall=NULL, T *ptrBig=NULL)
Definition: SRIMatrix.hpp:636
gnsstk::operator+
SRI operator+(const SRI &Sleft, const SRI &Sright)
Definition: SRI.cpp:519
gnsstk::sum
T sum(const ConstVectorBase< T, BaseClass > &l)
Definition: VectorBaseOperators.hpp:84
gnsstk::SRI
Definition: SRI.hpp:175
gnsstk::Matrix::cols
size_t cols() const
The number of columns in the matrix.
Definition: Matrix.hpp:167
SRI.hpp
gnsstk::Matrix::rows
size_t rows() const
The number of rows in the matrix.
Definition: Matrix.hpp:165
gnsstk::SRI::R
Matrix< double > R
Information matrix, an upper triangular (square) matrix.
Definition: SRI.hpp:601
gnsstk::SRI::zeroOne
void zeroOne(const unsigned int n)
Definition: SRI.cpp:540
gnsstk::identical
bool identical(const Namelist &N1, const Namelist &N2)
Definition: Namelist.cpp:331
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::StringUtils::split
std::vector< std::string > split(const std::string &str, const char delimiter=' ')
Definition: StringUtils.hpp:2275
gnsstk::Vector::resize
Vector & resize(const size_t index)
Definition: Vector.hpp:262
gnsstk::SRI::Z
Vector< double > Z
SRI state vector, of length equal to the dimension (row and col) of R.
Definition: SRI.hpp:604
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::LabeledMatrix::setprecision
LabeledMatrix & setprecision(int p)
Set the precision to p digits.
Definition: Namelist.hpp:202
gnsstk::transform
SparseMatrix< T > transform(const SparseMatrix< T > &M, const SparseMatrix< T > &C)
gnsstk::SRI::permute
void permute(const Namelist &NL)
Definition: SRI.cpp:162
gnsstk::SrifMU
void SrifMU(Matrix< T > &R, Vector< T > &Z, SparseMatrix< T > &A, const unsigned int M)
Definition: SparseMatrix.hpp:2467
gnsstk::SRINullSparseMatrix
const SparseMatrix< double > SRINullSparseMatrix
constant (empty) SparseMatrix used for default input arguments
Definition: SRI.cpp:70
gnsstk::transpose
SparseMatrix< T > transpose(const SparseMatrix< T > &M)
transpose
Definition: SparseMatrix.hpp:829
gnsstk::Matrix< double >
nl
int nl
Definition: IERS1996NutationData.hpp:44
gnsstk::Namelist::size
unsigned int size() const
return the size of the list.
Definition: Namelist.hpp:408
gnsstk::Namelist::getName
std::string getName(const unsigned int in) const
Definition: Namelist.cpp:485
gnsstk::SVD::sort
void sort(bool descending=true)
Definition: MatrixFunctors.hpp:378
gnsstk::Householder::A
Matrix< T > A
The upper triangular transformed matrix.
Definition: MatrixFunctors.hpp:811
gnsstk::SRI::names
Namelist names
Namelist parallel to R and Z, labelling the elements of the state vector.
Definition: SRI.hpp:607
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
gnsstk::upperCholesky
SparseMatrix< T > upperCholesky(const SparseMatrix< T > &A)
Definition: SparseMatrix.hpp:2262
gnsstk::Vector< double >
gnsstk::TrackingCode::P
@ P
Legacy GPS precise code.
std::operator<<
std::ostream & operator<<(std::ostream &s, gnsstk::StringUtils::FFLead v)
Definition: FormattedDouble_T.cpp:44
gnsstk::LabeledMatrix
Definition: Namelist.hpp:162
gnsstk::Vector::size
size_t size() const
STL size.
Definition: Vector.hpp:207
std
Definition: Angle.hpp:142
gnsstk::ConstMatrixBase::colCopy
Vector< T > colCopy(size_t c, size_t r=0) const
Definition: MatrixBase.hpp:146
gnsstk::LabeledMatrix::clean
LabeledMatrix & clean(bool s=true)
If true, print 0.0 as 0.
Definition: Namelist.hpp:230
gnsstk::SVD::S
Vector< T > S
Vector of singular values.
Definition: MatrixFunctors.hpp:412
Namelist.hpp
gnsstk::Householder
Definition: MatrixFunctors.hpp:745
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::Namelist
Definition: Namelist.hpp:287
gnsstk::Namelist::swap
void swap(const unsigned int &i, const unsigned int &j)
Definition: Namelist.cpp:150
gnsstk::SparseMatrix
Definition: SparseMatrix.hpp:53
gnsstk::SVD
Definition: MatrixFunctors.hpp:99
gnsstk::LabeledMatrix::setw
LabeledMatrix & setw(int w)
Set the width to w characters.
Definition: Namelist.hpp:195


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