1 //==============================================================================
2 //
3 // This file is part of GPSTk, the GPS Toolkit.
4 //
5 // The GPSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GPSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GPSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38
39
40 /**
41 * @file PRSolutionLegacy.cpp
42 * Autonomous pseudorange navigation solution, including RAIM algorithm
43 */
44
45 #include "MathBase.hpp"
46 #include "PRSolutionLegacy.hpp"
47 #include "EphemerisRange.hpp"
48 #include "GPSEllipsoid.hpp"
49 #include "GPSWeekSecond.hpp"
50
51 //#define DEBUG_PRINT_WARNINGS
52
53 // ----------------------------------------------------------------------------
54 // Combinations.hpp
55 // Find all the Combinations of n things taken k at a time.
56
57 #include "Exception.hpp"
58
59 /// Class Combinations will compute C(n,k), all the Combinations of n things
60 /// taken k at a time (where k <= n).
61 /// Let n 'things' be indexed by i (i=0...n-1), e.g. stored in an array of length n.
62 /// This class computes C(n,k) as sets of k indexes into the 'things' array.
63 /// These indexes are accessible via member functions Selection() or isSelected().
64 /// Next() computes the next combination until there are no more (when it returns -1).
65
66 class Combinations
67 {
68
69 public:
70
71 /// Default constructor
Combinations(void)72 Combinations(void)
73 throw()
74 {
75 nc = n = k = 0;
76 Index = NULL;
77 }
78
79 /// Constructor for C(n,k) = Combinations of n things taken k at a time (k <= n)
80 /// @throw Exception on invalid input (k>n).
Combinations(int N,int K)81 Combinations(int N, int K)
82 {
83 try
84 {
85 init(N,K);
86 }
87 catch(gpstk::Exception& e)
88 {
89 GPSTK_RETHROW(e);
90 }
91 }
92
93 /// copy constructor
Combinations(const Combinations & right)94 Combinations(const Combinations& right)
95 throw()
96 {
97 *this = right;
98 }
99
100 /// destructor
~Combinations(void)101 ~Combinations(void)
102 {
103 if (Index)
104 delete[] Index;
105 Index = NULL;
106 }
107
108 /// Assignment operator.
operator =(const Combinations & right)109 Combinations& operator=(const Combinations& right)
110 throw()
111 {
112 this->~Combinations();
113 init(right.n,right.k);
114 nc = right.nc;
115 for (int j=0; j<k; j++)
116 {
117 Index[j] = right.Index[j];
118 }
119 return *this;
120 }
121
122 /// Compute the next combination, returning the number of Combinations computed
123 /// so far; if there are no more Combinations, return -1.
124 int Next(void) throw();
125
126 /// Return index i (0 <= i < n) of jth selection (0 <= j < k);
127 /// if j is out of range, return -1.
Selection(int j)128 int Selection(int j)
129 throw()
130 {
131 if (j < 0 || j >= k)
132 return -1;
133 return Index[j];
134 }
135
136 /// Return true if the given index j (0 <= j < n) is
137 /// currently selected (i.e. if j = Selection(i) for some i)
isSelected(int j)138 bool isSelected(int j)
139 throw()
140 {
141 for (int i=0; i<k; i++)
142 {
143 if (Index[i] == j)
144 return true;
145 }
146 return false;
147 }
148
149 private:
150
151 /// The initialization routine used by constructors.
152 /// @throw Exception on invalid input (k>n or either n or k < 0).
153 void init(int N, int K);
154
155 /// Recursive function to increment Index[j].
156 int Increment(int j) throw();
157
158 int nc; ///< number of Combinations computed so far
159 int k,n; ///< Combinations of n things taken k at a time, given at c'tor
160 int* Index; ///< Index[j] = index of jth selection (j=0...k-1; I[j]=0...n-1)
161
162 };
163
164 // ----------------------------------------------------------------------------
165
Next(void)166 int Combinations::Next(void)
167 throw()
168 {
169 if (k < 1)
170 return -1;
171 if (Increment(k-1) != -1)
172 return ++nc;
173 return -1;
174 }
175
Increment(int j)176 int Combinations::Increment(int j)
177 throw()
178 {
179 if (Index[j] < n-k+j) { // can this index be incremented?
180 Index[j]++;
181 for (int m=j+1; m<k; m++)
182 {
183 Index[m]=Index[m-1]+1;
184 }
185 return 0;
186 }
187 // is this the last index?
188 if (j-1 < 0) return -1;
189 // increment the next lower index
190 return Increment(j-1);
191 }
192
init(int N,int K)193 void Combinations::init(int N, int K)
194 {
195 if (K > N || N < 0 || K < 0)
196 {
197 gpstk::Exception e("Combinations(n,k) must have k <= n, with n,k >= 0");
198 GPSTK_THROW(e);
199 }
200
201 if (K > 0)
202 {
203 Index = new int[K];
204 if (!Index)
205 {
206 gpstk::Exception e("Could not allocate");
207 GPSTK_THROW(e);
208 }
209 }
210 else
211 Index = NULL;
212
213 nc = 0;
214 k = K;
215 n = N;
216 for (int j=0; j<k; j++)
217 {
218 Index[j]=j;
219 }
220 }
221
222 // ----------------------------------------------------------------------------
223
224 using namespace std;
225 using namespace gpstk;
226
227 namespace gpstk
228 {
RAIMCompute(const CommonTime & Tr,vector<SatID> & Satellite,const vector<double> & Pseudorange,const XvtStore<SatID> & Eph,TropModel * pTropModel)229 int PRSolutionLegacy::RAIMCompute(const CommonTime& Tr,
230 vector<SatID>& Satellite,
231 const vector<double>& Pseudorange,
232 const XvtStore<SatID>& Eph,
233 TropModel *pTropModel)
234 {
235 try
236 {
237 int iret,N,Nreject,MinSV,stage;
238 size_t i, j;
239 vector<bool> UseSat, UseSave;
240 vector<int> GoodIndexes;
241 // Use these to save the 'best' solution within the loop.
242 int BestNIter=0;
243 double BestRMS=0.0, BestSL=0.0, BestConv=0.0;
244 Vector<double> BestSol(3,0.0);
245 vector<bool> BestUse;
246 BestRMS = -1.0; // this marks the 'Best' set as unused.
247 Matrix<double> BestCovariance;
248
249 // ----------------------------------------------------------------
250 // initialize
251
252 Valid = false;
253
254 bool hasGlonass = false;
255 bool hasOther = false;
256 Vector<int> satSystems(Satellite.size());
257 //Check if we have a mixed system
258 for ( i = 0; i < Satellite.size(); ++i)
259 {
260 satSystems[i] = ((Satellite[i].system == SatelliteSystem::Glonass) ? (1) : (0) );
261
262 if (satSystems[i] == 1) hasGlonass = true;
263 else hasOther = true;
264 }
265
266 // Save the input solution
267 // (for use in rejection when ResidualCriterion is false).
268 if (!hasGlonass && Solution.size() != 4)
269 {
270 Solution.resize(4);
271 }
272 else if (hasGlonass && hasOther && Solution.size() != 5)
273 {
274 Solution.resize(5);
275 }
276 Solution = 0.0;
277 APrioriSolution = Solution;
278
279 // ----------------------------------------------------------------
280 // fill the SVP matrix, and use it for every solution
281 // NB this routine can set Satellite[.]=negative when no ephemeris
282
283 i = PrepareAutonomousSolution(Tr, Satellite, Pseudorange, Eph, SVP,
284 Debug?pDebugStream:0);
285 if(Debug && pDebugStream) {
286 *pDebugStream << "In RAIMCompute after PAS(): Satellites:";
287 for(j=0; j<Satellite.size(); j++) {
288 RinexSatID rs(::abs(Satellite[j].id), Satellite[j].system);
289 *pDebugStream << " " << (Satellite[j].id < 0 ? "-":"") << rs;
290 }
291 *pDebugStream << endl;
292 *pDebugStream << " SVP matrix("
293 << SVP.rows() << "," << SVP.cols() << ")" << endl;
294 *pDebugStream << fixed << setw(16) << setprecision(3) << SVP << endl;
295 }
296 if (i) return i; // return is 0 (ok) or -4 (no ephemeris)
297
298 // count how many good satellites we have
299 // Initialize UseSat based on Satellite, and build GoodIndexes.
300 // UseSat is used to mark good sats (true) and those to ignore (false).
301 // UseSave saves the original so it can be reused for each solution.
302 // Let GoodIndexes be all the indexes of Satellites that are good:
303 // UseSat[GoodIndexes[.]] == true by definition
304
305 for (N=0,i=0; i<Satellite.size(); i++)
306 {
307 if (Satellite[i].id > 0)
308 {
309 N++;
310 UseSat.push_back(true);
311 GoodIndexes.push_back(i);
312 }
313 else
314 {
315 UseSat.push_back(false);
316 }
317 }
318 UseSave = UseSat;
319
320 // don't even try if there are not 4 good satellites
321
322 if (!hasGlonass && N < 4)
323 return -3;
324 else if (hasGlonass && hasOther && N < 5)
325 return -3;
326
327 // minimum number of sats needed for algorithm
328 MinSV = 5; // this would be RAIM
329 // ( not really RAIM || not RAIM at all - just one solution)
330 if (!ResidualCriterion || NSatsReject==0)
331 MinSV=4;
332
333 // how many satellites can RAIM reject, if we have to?
334 // default is -1, meaning as many as possible
335 Nreject = NSatsReject;
336 if (Nreject == -1 || Nreject > N-MinSV)
337 Nreject=N-MinSV;
338
339 // ----------------------------------------------------------------
340 // now compute the solution, first with all the data. If this fails,
341 // reject 1 satellite at a time and try again, then 2, etc.
342
343 // Slopes for each satellite are computed (cf. the RAIM algorithm)
344 Vector<double> Slopes(Pseudorange.size());
345
346 // Residuals stores the post-fit data residuals.
347 Vector<double> Residuals(Satellite.size(),0.0);
348
349 // stage is the number of satellites to reject.
350 stage = 0;
351
352 do{
353 // compute all the Combinations of N satellites taken stage at a time
354 Combinations Combo(N,stage);
355
356 // compute a solution for each combination of marked satellites
357 do{
358 // Mark the satellites for this combination
359 UseSat = UseSave;
360 for (i = 0; i < GoodIndexes.size(); i++)
361 {
362 if (Combo.isSelected(i))
363 UseSat[i]=false;
364 }
365 // ----------------------------------------------------------------
366 // Compute a solution given the data; ignore ranges for marked
367 // satellites. Fill Vector 'Slopes' with slopes for each unmarked
368 // satellite.
369 // Return 0 ok
370 // -1 failed to converge
371 // -2 singular problem
372 // -3 not enough good data
373 NIterations = MaxNIterations; // pass limits in
374 Convergence = ConvergenceLimit;
375 iret = AutonomousPRSolution(Tr, UseSat, SVP, pTropModel, Algebraic,
376 NIterations, Convergence, Solution, Covariance, Residuals, Slopes,
377 pDebugStream, ((hasGlonass && hasOther)?(&satSystems):(NULL)) );
378
379 // ----------------------------------------------------------------
380 // Compute RMS residual...
381 if (!ResidualCriterion)
382 {
383 // when 'distance from a priori' is the criterion.
384 Vector<double> D=Solution-APrioriSolution;
385 RMSResidual = RMS(D);
386 }
387 else
388 {
389 // and in the usual case
390 RMSResidual = RMS(Residuals);
391 }
392 // ... and find the maximum slope
393 MaxSlope = 0.0;
394 if (iret == 0)
395 {
396 for (i=0; i<UseSat.size(); i++)
397 {
398 if (UseSat[i] && Slopes(i)>MaxSlope)
399 MaxSlope=Slopes[i];
400 }
401 }
402 // ----------------------------------------------------------------
403 // print solution with diagnostic information
404 if (Debug && pDebugStream)
405 {
406 GPSWeekSecond weeksec(Tr);
407 *pDebugStream << "RPS " << setw(2) << stage
408 << " " << setw(4) << weeksec.week
409 << " " << fixed << setw(10) << setprecision(3) << weeksec.sow
410 << " " << setw(2) << N-stage << setprecision(6)
411 << " " << setw(16) << Solution(0)
412 << " " << setw(16) << Solution(1)
413 << " " << setw(16) << Solution(2)
414 << " " << setw(14) << Solution(3);
415 if (hasGlonass && hasOther)
416 *pDebugStream << " " << setw(16) << Solution(4);
417 *pDebugStream << " " << setw(12) << RMSResidual
418 << " " << fixed << setw(5) << setprecision(1) << MaxSlope
419 << " " << NIterations
420 << " " << scientific << setw(8) << setprecision(2)<< Convergence;
421 // print the SatID for good sats
422 for (i=0; i<UseSat.size(); i++)
423 {
424 if (UseSat[i])
425 *pDebugStream << " " << setw(3)<< Satellite[i].id;
426 else
427 *pDebugStream << " " << setw(3) << -::abs(Satellite[i].id);
428 }
429 // also print the return value
430 *pDebugStream << " (" << iret << ")" << endl;
431 }// end debug print
432
433 // ----------------------------------------------------------------
434 // deal with the results of AutonomousPRSolution()
435 if (iret)
436 { // failure for this combination
437 RMSResidual = 0.0;
438 Solution = 0.0;
439 }
440 else
441 { // success
442 // save 'best' solution for later
443 if (BestRMS < 0.0 || RMSResidual < BestRMS)
444 {
445 BestRMS = RMSResidual;
446 BestSol = Solution;
447 BestUse = UseSat;
448 BestSL = MaxSlope;
449 BestConv = Convergence;
450 BestNIter = NIterations;
451 }
452 // quit immediately?
453 if ((stage==0 || ReturnAtOnce) && RMSResidual < RMSLimit)
454 break;
455 }
456
457 // get the next Combinations and repeat
458 } while(Combo.Next() != -1);
459
460 // end of the stage
461 if (BestRMS > 0.0 && BestRMS < RMSLimit)
462 { // success
463 iret=0;
464 break;
465 }
466
467 // go to next stage
468 stage++;
469 if (stage > Nreject)
470 break;
471
472 } while(iret == 0); // end loop over stages
473
474 // ----------------------------------------------------------------
475 // copy out the best solution and return
476 Convergence = BestConv;
477 NIterations = BestNIter;
478 RMSResidual = BestRMS;
479 Solution = BestSol;
480 MaxSlope = BestSL;
481 Covariance =BestCovariance;
482 for (Nsvs=0,i=0; i<BestUse.size(); i++)
483 {
484 if (!BestUse[i])
485 Satellite[i].id = -::abs(Satellite[i].id);
486 else
487 Nsvs++;
488 }
489
490 if (iret==0 && BestSL > SlopeLimit)
491 iret=1;
492 if (iret==0 && BestSL > SlopeLimit/2.0 && Nsvs == 5)
493 iret=1;
494 if (iret>=0 && BestRMS >= RMSLimit)
495 iret=2;
496
497 if (iret==0)
498 Valid=true;
499
500 return iret;
501 }
502 catch(Exception& e)
503 {
504 GPSTK_RETHROW(e);
505 }
506 } // end PRSolutionLegacy::RAIMCompute()
507
508 ///-------------------------------------------------------------------------///
509 ///----------------------PrepareAutonomousSolution--------------------------///
510 ///-------------------------------------------------------------------------///
511
PrepareAutonomousSolution(const CommonTime & Tr,vector<SatID> & Satellite,const vector<double> & Pseudorange,const XvtStore<SatID> & Eph,Matrix<double> & SVP,ostream * pDebugStream)512 int PRSolutionLegacy::PrepareAutonomousSolution(const CommonTime& Tr,
513 vector<SatID>& Satellite,
514 const vector<double>& Pseudorange,
515 const XvtStore<SatID>& Eph,
516 Matrix<double>& SVP,
517 ostream *pDebugStream)
518 throw()
519 {
520 int i,j,nsvs,N=Satellite.size();
521 CommonTime tx; // transmit time
522 Xvt PVT;
523
524 if (N <= 0)
525 return 0;
526 SVP = Matrix<double>(N,4);
527 SVP = 0.0;
528
529 for (nsvs=0,i=0; i<N; i++)
530 {
531 // skip marked satellites
532 if (Satellite[i].id <= 0) continue;
533
534 // test the system
535 if(Satellite[i].system == SatelliteSystem::GPS)
536 ;
537 else {
538 Satellite[i].id = -::abs(Satellite[i].id);
539 if(pDebugStream) *pDebugStream
540 << "Warning: Ignoring satellite (system) " << Satellite[i];
541 continue;
542 }
543
544
545 // first estimate of transmit time
546 tx = Tr;
547 tx -= Pseudorange[i]/C_MPS;
548 // get ephemeris range, etc
549 try
550 {
551 PVT = Eph.getXvt(Satellite[i], tx);
552 }
553 catch(InvalidRequest& e)
554 {
555 ///Negate SatID because getXvt failed.
556 #ifdef DEBUG_PRINT_WARNINGS
557 cout << "Eph.getXvt(Satellite[" << i << "], tx); threw InvalidRequest:" << endl;
558 cout << e << endl << endl;
559 #endif
560 Satellite[i].id = -::abs(Satellite[i].id);
561 if(pDebugStream) *pDebugStream
562 << "Warning: PRSolutionLegacy ignores satellite (ephemeris) "
563 << Satellite[i] << endl;
564 continue;
565 }
566
567 // update transmit time and get ephemeris range again
568 tx -= PVT.clkbias + PVT.relcorr; // clk+rel
569 try
570 {
571 PVT = Eph.getXvt(Satellite[i], tx);
572 }
573 catch(InvalidRequest& e)
574 {
575 ///Negate SatID because getXvt failed.
576 Satellite[i].id = -::abs(Satellite[i].id);
577 continue;
578 }
579
580 // SVP = {SV position at transmit time}, raw range + clk + rel
581 for (j=0; j<3; j++)
582 {
583 SVP(i,j) = PVT.x[j];
584 }
585 SVP(i,3) = Pseudorange[i] + C_MPS * (PVT.clkbias + PVT.relcorr);
586 nsvs++;
587 }
588
589 if (nsvs == 0)
590 return -4;
591 return 0;
592 } // end PrepareAutonomousPRSolution
593
594 ///-------------------------------------------------------------------------///
595 ///-------------------------------------------------------------------------///
596
AlgebraicSolution(Matrix<double> & A,Vector<double> & Q,Vector<double> & X,Vector<double> & R)597 int PRSolutionLegacy::AlgebraicSolution(Matrix<double>& A,
598 Vector<double>& Q,
599 Vector<double>& X,
600 Vector<double>& R)
601 {
602 try
603 {
604 int N=A.rows();
605 Matrix<double> AT=transpose(A);
606 Matrix<double> B=AT,C(4,4);
607
608 C = AT * A;
609 // invert
610 try
611 {
612 //double big,small;
613 //condNum(C,big,small);
614 //if (small < 1.e-15 || big/small > 1.e15) return -2;
615 C = inverseSVD(C);
616 }
617 catch(SingularMatrixException& sme)
618 {
619 return -2;
620 }
621
622 B = C * AT;
623
624 Vector<double> One(N,1.0),V(4),U(4);
625 double E,F,G,d,lam;
626
627 U = B * One;
628 V = B * Q;
629 E = Minkowski(U,U);
630 F = Minkowski(U,V) - 1.0;
631 G = Minkowski(V,V);
632 d = F*F-E*G;
633 // avoid imaginary solutions: what does this really mean?
634 if (d < 0.0)
635 d=0.0;
636 d = SQRT(d);
637
638 // first solution ...
639 lam = (-F+d)/E;
640 X = lam*U + V;
641 X(3) = -X(3);
642 // ... and its residual
643 R(0) = A(0,3)-X(3) - RSS(X(0)-A(0,0), X(1)-A(0,1), X(2)-A(0,2));
644
645 // second solution ...
646 lam = (-F-d)/E;
647 X = lam*U + V;
648 X(3) = -X(3);
649 // ... and its residual
650 R(1) = A(0,3)-X(3) - RSS(X(0)-A(0,0), X(1)-A(0,1), X(2)-A(0,2));
651
652 // pick the right solution
653 if (ABS(R(1)) > ABS(R(0)))
654 {
655 lam = (-F+d)/E;
656 X = lam*U + V;
657 X(3) = -X(3);
658 }
659
660 // compute the residuals
661 for (int i=0; i<N; i++)
662 {
663 R(i) = A(i,3)-X(3) - RSS(X(0)-A(i,0), X(1)-A(i,1), X(2)-A(i,2));
664 }
665
666 return 0;
667
668 }
669 catch(Exception& e)
670 {
671 GPSTK_RETHROW(e);
672 }
673 } // end PRSolutionLegacy::AlgebraicSolution
674
675 ///-------------------------------------------------------------------------///
676 ///--------------------------AutonomousPRSolution---------------------------///
677 ///-------------------------------------------------------------------------///
678
AutonomousPRSolution(const CommonTime & T,const vector<bool> & Use,const Matrix<double> SVP,TropModel * pTropModel,const bool Algebraic,int & n_iterate,double & converge,Vector<double> & Sol,Matrix<double> & Cov,Vector<double> & Resid,Vector<double> & Slope,ostream * pDebugStream,Vector<int> * satSystems)679 int PRSolutionLegacy::AutonomousPRSolution(const CommonTime& T,
680 const vector<bool>& Use,
681 const Matrix<double> SVP,
682 TropModel *pTropModel,
683 const bool Algebraic,
684 int& n_iterate,
685 double& converge,
686 Vector<double>& Sol,
687 Matrix<double>& Cov,
688 Vector<double>& Resid,
689 Vector<double>& Slope,
690 ostream *pDebugStream,
691 Vector<int>* satSystems) ///Change
692 {
693 if (!pTropModel)
694 {
695 Exception e("Undefined tropospheric model");
696 GPSTK_THROW(e);
697 }
698
699 int size;
700 if (satSystems != NULL)
701 size = 5;
702 else
703 size = 4;
704
705 try
706 {
707 int iret,j,n,N;
708 size_t i;
709 double rho,wt,svxyz[3];
710 GPSEllipsoid ell; // WGS84?
711
712 //if (pDebugStream)
713 // *pDebugStream << "Enter APRS " << n_iterate << " "
714 // << scientific << setprecision(3) << converge << endl;
715
716 // find the number of good satellites
717 for (N=0,i=0; i<Use.size(); i++)
718 {
719 if (Use[i])
720 N++;
721 }
722 if ((satSystems != NULL) && N < 5)
723 return -3;
724 else if (N < 4)
725 return -3;
726
727 // define for computation
728 Vector<double> CRange(N),dX(size);
729 Matrix<double> P(N,size),PT,G(size,N),PG(N,N);
730 Xvt SV,RX;
731
732 Sol.resize(size);
733 Cov.resize(size,size);
734 Resid.resize(N);
735 Slope.resize(Use.size());
736
737 // define for algebraic solution
738 Vector<double> U(size),Q(N);
739 Matrix<double> A(P);
740 // and for linearized least squares
741 int niter_limit = (n_iterate < 2 ? 2 : n_iterate);
742 double conv_limit = converge;
743
744 // prepare for iteration loop
745 Sol = 0.0; // initial guess: center of earth
746 n_iterate = 0;
747 converge = 0.0;
748
749 // iteration loop
750 // do at least twice (even for algebraic solution) so that
751 // trop model gets evaluated
752 //bool applied_trop;
753 do {
754 //applied_trop = true;
755
756
757 // current estimate of position solution
758 for(i=0; i<3; i++) RX.x[i]=Sol(i);
759
760 // loop over satellites, computing partials matrix
761 for (n=0,i=0; i<Use.size(); i++)
762 {
763 // ignore marked satellites
764 if (!Use[i])
765 continue;
766
767 // time of flight (sec)
768 if (n_iterate == 0)
769 rho = 0.070; // initial guess: 70ms
770 else
771 rho = RSS(SVP(i,0)-Sol(0), SVP(i,1)-Sol(1), SVP(i,2)-Sol(2))
772 / ell.c();
773
774 // correct for earth rotation
775 wt = ell.angVelocity()*rho; // radians
776 svxyz[0] = ::cos(wt)*SVP(i,0) + ::sin(wt)*SVP(i,1);
777 svxyz[1] = -::sin(wt)*SVP(i,0) + ::cos(wt)*SVP(i,1);
778 svxyz[2] = SVP(i,2);
779
780 // corrected pseudorange (m)
781 CRange(n) = SVP(i,3);
782
783 // correct for troposphere (but not on the first iteration)
784 if (n_iterate > 0)
785 {
786 SV.x[0] = svxyz[0];
787 SV.x[1] = svxyz[1];
788 SV.x[2] = svxyz[2];
789 // must test RX for reasonableness to avoid corrupting TropModel
790 Position R(RX),S(SV);
791 double tc=R.getHeight(), elev = R.elevation(SV);
792 if (elev < 0.0 || tc > 10000.0 || tc < -1000) {
793 tc=0.0;
794 //applied_trop = false;
795 }
796 else tc = pTropModel->correction(R,S,T);
797 //if(pDebugStream) *pDebugStream << "Trop " << i << " "
798 // << fixed << setprecision(3) << tc << endl;
799 CRange(n) -= tc;
800
801 }
802
803 // geometric range
804 rho = RSS(svxyz[0]-Sol(0),svxyz[1]-Sol(1),svxyz[2]-Sol(2));
805
806 // partials matrix
807 P(n,0) = (Sol(0)-svxyz[0])/rho; // x direction cosine
808 P(n,1) = (Sol(1)-svxyz[1])/rho; // y direction cosine
809 P(n,2) = (Sol(2)-svxyz[2])/rho; // z direction cosine
810 P(n,3) = 1.0;
811 if (satSystems != NULL)
812 P(n,4) = (*satSystems)[i]; // 1 if GLONASS, 0 if GPS
813
814 // data vector: corrected range residual
815 Resid(n) = CRange(n) - rho - Sol(3);
816 if (satSystems != NULL && (*satSystems)[i] == 1)
817 {
818 Resid(n) -= Sol(4);
819 }
820
821 // TD: allow weight matrix = measurement covariance
822 // P *= MCov;
823 // Resid *= MCov;
824
825 // compute intermediate quantities for algebraic solution
826 if (satSystems == NULL && Algebraic)
827 {
828 U(0) = A(n,0) = svxyz[0];
829 U(1) = A(n,1) = svxyz[1];
830 U(2) = A(n,2) = svxyz[2];
831 U(3) = A(n,3) = CRange(n);
832 U(4) = A(n,4) = P(n,4);
833 Q(n) = 0.5 * Minkowski(U,U);
834 }
835
836 n++; // n is number of good satellites - used for Slope
837 } // end loop over satellites
838
839 // compute information matrix = inverse covariance matrix
840 PT = transpose(P);
841 Cov = PT * P;
842
843 // invert using SVD
844 //double big,small;
845 //condNum(PT*P,big,small);
846 //if (small < 1.e-15 || big/small > 1.e15)
847 // return -2;
848 try
849 {
850 Cov = inverseSVD(Cov);
851 }
852 //try { Cov = inverseLUD(Cov); }
853 catch(SingularMatrixException& sme)
854 {
855 return -2;
856 }
857
858 // generalized inverse
859 G = Cov * PT;
860 PG = P * G; // used for Slope
861
862 n_iterate++; // increment number iterations
863
864 // ----------------- algebraic solution -----------------------
865 if (satSystems == NULL && Algebraic)
866 {
867 iret = PRSolutionLegacy::AlgebraicSolution(A,Q,Sol,Resid);
868 if (iret)
869 return iret; // (singular)
870 if (n_iterate > 1)
871 { // need 2, for trop
872 iret = 0;
873 break;
874 }
875 }
876 // ----------------- linearized least squares solution --------
877 else
878 {
879 dX = G * Resid;
880 Sol += dX;
881 // test for convergence
882 converge = norm(dX);
883 // success: quit
884 if (n_iterate > 1 && converge < conv_limit)
885 {
886 iret = 0;
887 break;
888 }
889 // failure: quit
890 if (n_iterate >= niter_limit || converge > 1.e10)
891 {
892 iret = -1;
893 break;
894 }
895 }
896
897 }
898
899 while(1); // end iteration loop
900
901 //if(!applied_trop && pDebugStream)
902 //*pDebugStream << "Warning - trop correction not applied at time "
903 //<< T.printf("%4F %10.3g\n");
904
905
906
907 // compute slopes
908 Slope = 0.0;
909 if (iret == 0)
910 {
911 for (j=0,i=0; i<Use.size(); i++)
912 {
913 if (!Use[i])
914 continue;
915 for (int k=0; k<4; k++)
916 {
917 Slope(i) += G(k,j)*G(k,j);
918 }
919 Slope(i) = SQRT(Slope(i)*double(n-4)/(1.0-PG(j,j)));
920 j++;
921 }
922 }
923
924 return iret;
925 }
926 catch(Exception& e)
927 {
928 GPSTK_RETHROW(e);
929 }
930 } // end PRSolutionLegacy::AutonomousPRSolution
931
932 ///-------------------------------------------------------------------------///
933 ///-------------------------------------------------------------------------///
934
935 } // namespace gpstk
936