56 const string PRSolution::calfmt = string(
"%04Y/%02m/%02d %02H:%02M:%02S %P");
57 const string PRSolution::gpsfmt = string(
"%4F %10.3g");
58 const string PRSolution::timfmt = gpsfmt + string(
" ") + calfmt;
68 const vector<double>& Pseudorange,
75 int j,noeph(0),N,NSVS;
81 if(allowedGNSS.size() == 0) {
82 Exception e(
"Must define systems vector allowedGNSS before processing");
87 for(N=0,i=0; i<Sats.size(); i++) {
88 if(Sats[i].
id <= 0)
continue;
89 if(
vectorindex(allowedGNSS, Sats[i].system) == -1) {
90 LOG(
DEBUG) <<
" PRSolution ignores satellite (system) "
92 Sats[i].id = -Sats[i].id;
99 LOG(
DEBUG) <<
"Sats.size is " << Sats.size();
105 for(i=0; i<Sats.size(); i++) {
108 if(Sats[i].
id <= 0) {
109 LOG(
DEBUG) <<
" PRSolution ignores marked satellite "
123 tx -= Pseudorange[i]/
C_MPS;
131 NavValidityType::ValidOnly, order));
132 LOG(
DEBUG) <<
" returned from getXvt";
134 catch(AssertionFailure& e) {
135 LOG(
DEBUG) <<
"Warning - PRSolution ignores satellite (no ephemeris) "
137 <<
" [" << e.getText() <<
"]";
138 Sats[i].id = -::abs(Sats[i].
id);
154 NavValidityType::ValidOnly, order));
156 catch(AssertionFailure& e) {
157 LOG(
DEBUG) <<
"Warning - PRSolution ignores satellite (no ephemeris 2) "
159 <<
" [" << e.getText() <<
"]";
160 Sats[i].id = -::abs(Sats[i].
id);
166 for(j=0; j<3; j++) SVP(i,j) = PVT.
x[j];
170 <<
" PR " << fixed << setprecision(3) << Pseudorange[i]
178 if(noeph == N)
return -4;
189 const vector<SatID>& Sats,
193 const int& niterLimit,
194 const double& convLimit,
199 Exception e(
"Undefined tropospheric model");
202 if(Sats.size() != SVP.
rows() ||
203 (invMC.
rows() > 0 && invMC.
rows() != Sats.size())) {
204 LOG(
ERROR) <<
"Sats has length " << Sats.size();
206 LOG(
ERROR) <<
"invMC has dimension " << invMC.
rows() <<
"x" << invMC.
cols();
210 if(allowedGNSS.size() == 0) {
211 Exception e(
"Must define systems vector allowedGNSS before processing");
217 double rho,wt,svxyz[3];
225 vector<SatelliteSystem> currGNSS;
228 vector<SatelliteSystem> tempGNSS;
229 for(Nsvs=0,i=0; i<Sats.size(); i++) {
239 tempGNSS.push_back(sys);
243 for(i=0; i<allowedGNSS.size(); i++)
245 currGNSS.push_back(allowedGNSS[i]);
249 const size_t dim(3 + currGNSS.size());
252 if(Nsvs < dim)
return -3;
257 if(invMC.
rows() > 0) {
260 for(n=0,i=0; i<Sats.size(); i++) {
261 if(Sats[i].
id <= 0)
continue;
262 for(k=0,j=0; j<Sats.size(); j++) {
263 if(Sats[j].
id <= 0)
continue;
264 iMC(n,k) = invMC(i,j);
269 LOG(
DEBUG) <<
"inv MCov matrix is\n" << fixed << setprecision(4) << iMC;
279 Solution.resize(dim);
280 Covariance.resize(dim,dim);
283 LOG(
DEBUG) <<
" Solution dimension is " << dim <<
" and Nsvs is " << Nsvs;
287 int n_iterate(0), niter_limit(niterLimit < 2 ? 2 : niterLimit);
288 double converge(0.0);
293 for(i=0; i<3; i++) localAPSol[i] = APSolution[i];
294 for(i=0; i<currGNSS.size(); i++) {
296 localAPSol[3+i] = (k == -1 ? 0.0 : APSolution[3+k]);
302 LOG(
DEBUG) <<
" no memory - no apriori solution";
304 Solution = localAPSol;
308 vector<RinexSatID> RSats;
313 RX.
x =
Triple(Solution(0),Solution(1),Solution(2));
316 for(n=0,i=0; i<Sats.size(); i++) {
318 if(Sats[i].
id <= 0)
continue;
327 rho =
RSS(SVP(i,0)-Solution(0),
328 SVP(i,1)-Solution(1), SVP(i,2)-Solution(2))/ellip.
c();
332 svxyz[0] =
::cos(wt)*SVP(i,0) +
::sin(wt)*SVP(i,1);
333 svxyz[1] = -
::sin(wt)*SVP(i,0) +
::cos(wt)*SVP(i,1);
337 rho =
RSS(svxyz[0]-Solution(0),
338 svxyz[1]-Solution(1),
339 svxyz[2]-Solution(2));
342 dirCos[0] = (Solution(0)-svxyz[0])/rho;
343 dirCos[1] = (Solution(1)-svxyz[1])/rho;
344 dirCos[2] = (Solution(2)-svxyz[2])/rho;
348 CRange(n) = SVP(i,3) - rho;
352 SV.
x =
Triple(svxyz[0],svxyz[1],svxyz[2]);
365 if(bad || R.
elevation(S) < 0.0 || tc < -1000.0)
375 LOG(
DEBUG) <<
"Trop " << i <<
" " << Sats[i] <<
" "
376 << fixed << setprecision(3) << tc;
384 const double clk(Solution(j));
385 LOG(
DEBUG) <<
"Clock is (" << j <<
") " << clk;
388 Resids(n) = CRange(n) - clk;
404 Exception e(
"Counting error after satellite loop");
408 LOG(
DEBUG) <<
"Partials (" <<
P.rows() <<
"x" <<
P.cols() <<
")\n"
409 << fixed << setprecision(4) <<
P;
411 << fixed << setprecision(3) << Resids;
418 if(invMC.
rows() > 0) Covariance = PT * iMC *
P;
419 else Covariance = PT *
P;
425 catch(MatrixException& sme) {
return -2; }
426 LOG(
DEBUG) <<
"InvCov (" << Covariance.rows() <<
"x" << Covariance.cols()
427 <<
")\n" << fixed << setprecision(4) << Covariance;
430 if(invMC.
rows() > 0) G = Covariance * PT * iMC;
431 else G = Covariance * PT;
435 LOG(
DEBUG) <<
"PG (" << PG.rows() <<
"x" << PG.cols()
436 <<
")\n" << fixed << setprecision(4) << PG;
449 if(n_iterate > 1 && converge < convLimit) {
465 if(n_iterate >= niter_limit || converge > 1.e10) {
471 LOG(
DEBUG) <<
"Out of iteration loop";
473 if(TropFlag)
LOG(
DEBUG) <<
"Trop correction not applied at time "
479 if(iret == 0)
for(j=0,i=0; i<Sats.size(); i++) {
480 if(Sats[i].
id <= 0)
continue;
484 if(::fabs(1.0-PG(j,j)) < 1.e-8)
continue;
486 for(
int k=0; k<dim; k++) Slopes(j) += G(k,j)*G(k,j);
487 Slopes(j) =
SQRT(Slopes(j)*
double(n-dim)/(1.0-PG(j,j)));
488 if(Slopes(j) > MaxSlope) MaxSlope = Slopes(j);
491 LOG(
DEBUG) <<
"Computed slopes, found max member";
495 PreFitResidual =
P*(Solution-localAPSol) - Resids;
496 LOG(
DEBUG) <<
"Computed pre-fit residuals";
499 RMSResidual =
RMS(Resids);
500 LOG(
DEBUG) <<
"Computed RMS residual";
508 NIterations = n_iterate;
509 Convergence = converge;
523 const vector<double>& Pseudorange,
530 return (RAIMCompute(Tr, Sats, Pseudorange, invMC, eph, pTropModel,
543 const vector<double>& Pseudorange,
557 vector<int> GoodIndexes;
560 bool BestTropFlag(
false);
561 int BestNIter(0),BestIret(-5);
562 double BestRMS(-1.0),BestSL(0.0),BestConv(0.0);
564 vector<SatID> BestSats,SaveSats;
566 vector<SatelliteSystem> BestGNSS;
571 TropFlag = SlopeFlag = RMSFlag =
false;
577 N = PreparePRSolution(Tr, Sats, Pseudorange, eph, SVP, order);
579 if(
LOGlevel >= ConfigureLOG::Level(
"DEBUG")) {
580 LOG(
DEBUG) <<
"Prepare returns " << N;
582 oss <<
"RAIMCompute: after PrepareAS(): Satellites:";
583 for(i=0; i<Sats.size(); i++) {
584 RinexSatID rs(::abs(Sats[i].
id), Sats[i].system);
585 oss <<
" " << (Sats[i].id < 0 ?
"-" :
"") << rs;
589 oss <<
" SVP matrix("
590 << SVP.
rows() <<
"," << SVP.
cols() <<
")" << endl;
591 oss << fixed << setw(16) << setprecision(5) << SVP;
597 if(N <= 0)
return -4;
606 for(i=0; i<Sats.size(); i++)
608 GoodIndexes.push_back(i);
611 if(
LOGlevel >= ConfigureLOG::Level(
"DEBUG")) {
613 oss <<
" Good satellites (" << N <<
") are:";
614 for(i=0; i<GoodIndexes.size(); i++)
615 oss <<
" " <<
RinexSatID(Sats[GoodIndexes[i]]);
639 for(i=0; i<GoodIndexes.size(); i++)
641 Sats[GoodIndexes[i]].id = -::abs(Sats[GoodIndexes[i]].
id);
643 if(
LOGlevel >= ConfigureLOG::Level(
"DEBUG")) {
645 oss <<
" RAIM: Try the combo ";
646 for(i=0; i<Sats.size(); i++) {
647 RinexSatID rs(::abs(Sats[i].
id), Sats[i].system);
648 oss <<
" " << (Sats[i].id < 0 ?
"-" :
" ") << rs;
662 iret = SimplePRSolution(Tr, Sats, SVP, invMC, pTropModel,
663 MaxNIterations, ConvergenceLimit, Resids, Slopes);
665 LOG(
DEBUG) <<
" RAIM: SimplePRS returns " << iret;
666 if(iret <= 0 && iret > BestIret) BestIret = iret;
672 LOG(
DEBUG) <<
" SPS: Failed to converge - go on";
675 else if(iret == -2) {
676 LOG(
DEBUG) <<
" SPS: singular - go on";
679 else if(iret == -3) {
680 LOG(
DEBUG) <<
" SPS: not enough satellites: quit";
683 else if(iret == -4) {
684 LOG(
DEBUG) <<
" SPS: no ephemeris: quit";
691 LOG(
DEBUG) << outputString(
string(
"RPS"),iret);
700 if(BestRMS < 0.0 || RMSResidual < BestRMS) {
701 BestRMS = RMSResidual;
703 BestSats = SatelliteIDs;
706 BestConv = Convergence;
707 BestNIter = NIterations;
708 BestCov = Covariance;
709 BestInvMCov = invMeasCov;
710 BestPartials = Partials;
711 BestPFR = PreFitResidual;
712 BestTropFlag = TropFlag;
716 if(stage==0 && RMSResidual <
RMSLimit)
719 }
while(Combo.
Next() != -1);
722 if(BestRMS > 0.0 && BestRMS <
RMSLimit) {
723 LOG(
DEBUG) <<
" RAIM: Success in the RAIM loop";
732 if(NSatsReject > -1 && stage > NSatsReject) {
733 LOG(
DEBUG) <<
" RAIM: break before stage " << stage
734 <<
" due to NSatsReject " << NSatsReject;
739 if(iret == -3 || iret == -4) {
740 LOG(
DEBUG) <<
" RAIM: break before stage " << stage
741 <<
"; " << (iret==-3 ?
"too few sats" :
"no ephemeris");
745 LOG(
DEBUG) <<
" RAIM: go to stage " << stage;
752 Sats = SatelliteIDs = BestSats;
755 Covariance = BestCov;
756 invMeasCov = BestInvMCov;
757 Partials = BestPartials;
758 PreFitResidual = BestPFR;
759 Convergence = BestConv;
760 NIterations = BestNIter;
761 RMSResidual = BestRMS;
763 TropFlag = BestTropFlag;
767 if(dataGNSS.size() != BestGNSS.size()) {
768 N = 3+dataGNSS.
size();
775 for(j=0,i=0; i<dataGNSS.size(); i++) {
776 indexes.push_back(dataGNSS[i] == BestGNSS[j] ? j++ : -1);
781 Solution(i) = BestSol(i);
782 for(j=0; j<Partials.rows(); j++) Partials(j,i) = BestPartials(j,i);
783 for(j=0; j<3; j++) Covariance(i,j) = BestCov(i,j);
784 for(j=0; j<indexes.size(); j++) {
785 Covariance(i,3+j)=(indexes[j]==-1 ? 0.:BestCov(i,3+indexes[j]));
786 Covariance(3+j,i)=(indexes[j]==-1 ? 0.:BestCov(3+indexes[j],i));
791 for(j=0; j<indexes.size(); j++) {
794 Solution(3+j) = (ok ? BestSol(3+n) : 0.0);
795 for(i=0; i<Partials.rows(); i++)
796 Partials(i,3+j) = (ok ? BestPartials(i,3+n) : 0.0);
797 for(i=0; i<indexes.size(); i++) {
798 Covariance(3+i,3+j) = (ok ? BestCov(3+i,3+n) : 0.0);
799 Covariance(3+j,3+i) = (ok ? BestCov(3+n,3+i) : 0.0);
805 for(Nsvs=0,i=0; i<SatelliteIDs.size(); i++)
806 if(SatelliteIDs[i].
id > 0)
811 if(hasMemory && iret==0) {
813 addToMemory(Solution,Covariance,PreFitResidual,Partials,invMeasCov);
815 updateAPSolution(Solution);
822 if(BestSL > SlopeLimit) { iret = 1; SlopeFlag =
true; }
823 if(BestSL > SlopeLimit/2.0 && Nsvs == 5) { iret = 1; SlopeFlag =
true; }
824 if(BestRMS >=
RMSLimit) { iret = 1; RMSFlag =
true; }
825 if(TropFlag) iret = 1;
828 else if(iret == -1)
Valid =
false;
830 LOG(
DEBUG) <<
" RAIM exit with ret value " << iret
831 <<
" and Valid " << (
Valid ?
"T":
"F");
842 int PRSolution::DOPCompute(
void)
847 PDOP =
SQRT(Cov(0,0)+Cov(1,1)+Cov(2,2));
849 for(
size_t i=3; i<Cov.
rows(); i++) TDOP += Cov(i,i);
851 GDOP =
RSS(PDOP,TDOP);
859 string PRSolution::outputValidString(
int iret)
863 oss <<
" (" << iret <<
" " << errorCodeString(iret);
866 if(RMSFlag) oss <<
" large RMS residual";
867 if(SlopeFlag) oss <<
" large slope";
868 if(TropFlag) oss <<
" missed trop. corr.";
870 oss <<
") " << (
Valid ?
"" :
"N") <<
"V";
875 string PRSolution::outputNAVString(
string tag,
int iret,
const Vector<double>& Vec)
882 int len = oss.str().size();
884 oss <<
"#" << tag <<
" NAV " << setw(len) <<
"time"
885 <<
" " << setw(18) <<
"Sol/Resid:X(m)"
886 <<
" " << setw(18) <<
"Sol/Resid:Y(m)"
887 <<
" " << setw(18) <<
"Sol/Resid:Z(m)"
888 <<
" " << setw(18) <<
"sys clock" <<
" [sys clock ...] Valid/Not";
893 oss << tag <<
" NAV " <<
printTime(currTime,gpsfmt)
894 << fixed << setprecision(6)
895 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(0) : Vec(0))
896 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(1) : Vec(1))
897 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(2) : Vec(2))
898 << fixed << setprecision(3);
899 for(
size_t i=0; i<dataGNSS.size(); i++) {
901 oss <<
" " << sat.
systemString3() <<
" " << setw(11) << Solution(3+i);
903 oss << outputValidString(iret);
908 string PRSolution::outputPOSString(
string tag,
int iret,
const Vector<double>& Vec)
915 int len = oss.str().size();
916 if(len > 3) len -= 3;
918 oss <<
"#" << tag <<
" POS " << setw(len) <<
"time"
919 <<
" " << setw(16) <<
"Sol-X(m)"
920 <<
" " << setw(16) <<
"Sol-Y(m)"
921 <<
" " << setw(16) <<
"Sol-Z(m)"
922 <<
" (ret code) Valid/Not";
927 oss << tag <<
" POS " <<
printTime(currTime,gpsfmt)
928 << fixed << setprecision(6)
929 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(0) : Vec(0))
930 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(1) : Vec(1))
931 <<
" " << setw(16) << (&Vec==&PRSNullVector ? Solution(2) : Vec(2))
932 << outputValidString(iret);
937 string PRSolution::outputCLKString(
string tag,
int iret)
944 int len = oss.str().size();
945 if(len > 3) len -= 3;
947 oss <<
"#" << tag <<
" CLK " << setw(len) <<
"time"
948 <<
" sys " << setw(11) <<
"clock" <<
" ...";
953 oss << tag <<
" CLK " <<
printTime(currTime,gpsfmt)
954 << fixed << setprecision(3);
957 for(
size_t i=0; i<dataGNSS.size(); i++) {
959 oss <<
" " << sat.
systemString3() <<
" " << setw(11) << Solution(3+i);
961 oss << outputValidString(iret);
967 string PRSolution::outputRMSString(
string tag,
int iret)
974 int len = oss.str().size();
975 if(len > 3) len -= 3;
977 oss <<
"#" << tag <<
" RMS " << setw(len) <<
"time"
978 <<
" " << setw(2) <<
"Ngood"
979 <<
" " << setw(8) <<
"resid"
980 <<
" " << setw(7) <<
"TDOP"
981 <<
" " << setw(7) <<
"PDOP"
982 <<
" " << setw(7) <<
"GDOP"
983 <<
" " << setw(5) <<
"Slope"
984 <<
" " << setw(2) <<
"nit"
985 <<
" " << setw(8) <<
"converge"
986 <<
" sats(-rej)... (ret code) Valid/Not";
994 vector<RinexSatID> sats,goodsats;
995 for(i=0; i<SatelliteIDs.size(); i++) {
996 RinexSatID rs(::abs(SatelliteIDs[i].
id), SatelliteIDs[i].system);
997 if(find(sats.begin(),sats.end(),rs) == sats.end())
999 if(SatelliteIDs[i].
id > 0) {
1000 if(find(goodsats.begin(),goodsats.end(),rs) == goodsats.end())
1001 goodsats.push_back(rs);
1007 oss << tag <<
" RMS " <<
printTime(currTime,gpsfmt)
1008 <<
" " << setw(2) << goodsats.size()
1009 << fixed << setprecision(3)
1010 <<
" " << setw(8) << RMSResidual
1012 <<
" " << setw(7) << TDOP
1013 <<
" " << setw(7) << PDOP
1014 <<
" " << setw(7) << GDOP
1016 <<
" " << setw(5) << MaxSlope
1017 <<
" " << setw(2) << NIterations
1018 << scientific << setprecision(2)
1019 <<
" " << setw(8) << Convergence;
1020 for(
size_t i=0; i<sats.size(); i++) {
1021 if(find(goodsats.begin(),goodsats.end(),sats[i]) != goodsats.end())
1022 oss <<
" " << sats[i];
1024 oss <<
" -" << sats[i];
1026 oss << outputValidString(iret);
1035 oss << outputNAVString(tag,iret,Vec) << endl;
1036 oss << outputRMSString(tag,iret);
1041 string PRSolution::errorCodeString(
int iret)
1043 string str(
"unknown");
1044 if(iret == 1) str = string(
"ok but perhaps degraded");
1045 else if(iret== 0) str = string(
"ok");
1046 else if(iret==-1) str = string(
"failed to converge");
1047 else if(iret==-2) str = string(
"singular solution");
1048 else if(iret==-3) str = string(
"not enough satellites");
1049 else if(iret==-4) str = string(
"not any ephemeris");
1053 string PRSolution::configString(
string tag)
1057 <<
"\n iterations " << MaxNIterations
1058 <<
"\n convergence " << scientific << setprecision(2) << ConvergenceLimit
1059 <<
"\n RMS residual limit " << fixed <<
RMSLimit
1060 <<
"\n RAIM slope limit " << fixed << SlopeLimit <<
" meters"
1061 <<
"\n Maximum number of satellites to reject is " << NSatsReject
1062 <<
"\n Memory information IS " << (hasMemory ?
"":
"NOT ") <<
"stored"