From cf502f3fca6b1ed37a61cf7f1570e432bb46a800 Mon Sep 17 00:00:00 2001
From: joanvallve <jvallve@iri.upc.edu>
Date: Thu, 29 Jul 2021 18:37:09 +0200
Subject: [PATCH] residual and residual_ci

---
 include/gnss_utils/tdcp.h |   1 +
 src/tdcp.cpp              | 111 +++++++++++++++++++++++---------------
 2 files changed, 68 insertions(+), 44 deletions(-)

diff --git a/include/gnss_utils/tdcp.h b/include/gnss_utils/tdcp.h
index 28cef3d..00ca035 100644
--- a/include/gnss_utils/tdcp.h
+++ b/include/gnss_utils/tdcp.h
@@ -18,6 +18,7 @@ struct TdcpOutput
     Eigen::Vector4d d = Eigen::Vector4d::Zero();
     Eigen::Matrix4d cov_d = Eigen::Matrix4d::Zero();
     double dt = 0;
+    double residual = 0;
     double residual_ci = 0;
 };
 
diff --git a/src/tdcp.cpp b/src/tdcp.cpp
index 6093631..aa3720f 100644
--- a/src/tdcp.cpp
+++ b/src/tdcp.cpp
@@ -288,8 +288,11 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
     TdcpOutput output;
     Eigen::Vector4d& d(output.d);
     Eigen::Matrix4d& cov_d(output.cov_d);
+    double& residual(output.residual);
     double& residual_ci(output.residual_ci);
 
+    const int n_rows = A.rows();
+
     // Initial guess
     Eigen::Vector4d delta_d(Eigen::Vector4d::Zero());
     d = d_0;
@@ -297,7 +300,7 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
     // initial sagnac correction
     Eigen::VectorXd prev_sagnac_corr(s_k.cols());
     if (tdcp_params.sagnac_correction == 2 )
-        for (int row = 0; row < A.rows(); row++)
+        for (int row = 0; row < n_rows; row++)
         {
             double sagnac_corr_r = computeSagnacCorrection(x_r,s_r.col(row)); //OMGE*(s_r.col(row)(0)*x_r(1)-s_r.col(row)(1)*x_r(0))/CLIGHT;
             double sagnac_corr_k = computeSagnacCorrection(x_r+d_0.head(3),s_k.col(row)); //OMGE*(s_k.col(row)(0)*(x_r(1)+d_0(1))-s_k.col(row)(1)*(x_r(0)+d_0(0)))/CLIGHT;
@@ -308,7 +311,7 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
     for (int j = 0; j < tdcp_params.max_iterations; j++)
     {
         // fill A and r
-        for (int row = 0; row < A.rows(); row++)
+        for (int row = 0; row < n_rows; row++)
         {
             // skip discarded rows
             if (raim_discarded_rows.count(row) != 0)
@@ -360,7 +363,7 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                 std::cout << "Displacement update =" << delta_d.head<3>().transpose() << std::endl;
                 printf("Ref distance      = %7.3f m\n", d_0.norm());
                 printf("Computed distance = %7.3f m\n", d.head<3>().norm());
-                printf("Tdcp: rows          = %lu\n", r.rows());
+                printf("Tdcp: rows          = %lu\n", n_rows);
                 std::cout << "Tdcp: r             = " << r.transpose() << std::endl;
                 std::cout << "Tdcp: drho_m        = " << drho_m.transpose() << std::endl;
                 std::cout << "Tdcp: A             = \n" << A << std::endl;
@@ -374,15 +377,18 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
             return output;
         }
 
-        // residual_ci
+        // residual
         if (tdcp_params.residual_opt == 0) // all problem
-            residual_ci = chisq2ci((r + A * delta_d).squaredNorm() / var_tdcp, A.rows());
+            residual = (r + A * delta_d).squaredNorm() / var_tdcp;
         else if (tdcp_params.residual_opt == 1) // worst sat
-            residual_ci = chisq2ci((r + A * delta_d).cwiseAbs2().maxCoeff() / var_tdcp, 1);
+            residual = (r + A * delta_d).cwiseAbs2().maxCoeff() / var_tdcp;
         else
             throw std::runtime_error("unknown value for residual_opt");
         // residual = (r + A * delta_d).norm();
 
+        // residual_ci
+        residual_ci = chisq2ci(residual, tdcp_params.residual_opt == 0 ? n_rows : 1);
+
         #if GNSS_UTILS_TDCP_DEBUG == 1
             if (j == 0)
             {
@@ -391,8 +397,9 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                 std::cout << "Displacement update =" << delta_d.head<3>().transpose() << std::endl;
                 printf("Ref distance      = %7.3f m\n", d_0.norm());
                 printf("Computed distance = %7.3f m\n", d.head<3>().norm());
-                printf("Tdcp: residual_ci      = %13.10f\n", residual_ci);
-                printf("Tdcp: rows          = %lu\n", r.rows());
+                printf("Tdcp: residual      = %13.10f\n", residual);
+                printf("Tdcp: residual_ci   = %13.10f\n", residual_ci);
+                printf("Tdcp: rows          = %lu\n", n_rows);
                 std::cout << "Tdcp: r             = " << r.transpose() << std::endl;
                 std::cout << "Tdcp: r+A*delta_d   = " << (r + A * delta_d).transpose() << std::endl;
                 std::cout << "Tdcp: drho_m        = " << drho_m.transpose() << std::endl;
@@ -402,15 +409,15 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                 printf("Tdcp: dT            = %8.3f secs\n", d(3));
                 std::cout << "Check RAIM conditions...\n";
                 std::cout << "\titeration == 0:                         " << (j==0 ? "OK\n":"FAILED\n");
-                std::cout << "\tA.rows() > tdcp_params.min_common_sats: " << (A.rows() > tdcp_params.min_common_sats ? "OK\n":"FAILED\n");
+                std::cout << "\tn_rows > tdcp_params.min_common_sats: " << (n_rows > tdcp_params.min_common_sats ? "OK\n":"FAILED\n");
                 std::cout << "\ttdcp_params.raim_n > 0:                 " << (tdcp_params.raim_n > 0 ? "OK\n":"FAILED\n");
-                std::cout << "\tresidual_ci > tdcp_params.max_residual_ci:    " << (residual_ci > tdcp_params.max_residual_ci ? "OK\n":"FAILED\n");
+                std::cout << "\ttdcp_params.max_residual_ci:            " << tdcp_params.max_residual_ci;
             }
         #endif
 
         // RAIM ====================================== (after first iteration)
         if (j == 0 and
-            A.rows() > tdcp_params.min_common_sats and
+            n_rows > tdcp_params.min_common_sats and
             tdcp_params.raim_n > 0 and
             residual_ci > tdcp_params.max_residual_ci)
         {
@@ -419,22 +426,22 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
             #endif
 
             int             worst_sat_row = -1;
-            double          best_residual_ci = 1e12;
+            double          best_residual = 1e12;
             Eigen::Vector4d best_d;
 
-            // remove up to 'raim_n' observations (if enough satellites and residual_ci condition holds)
+            // remove up to 'raim_n' observations (if enough satellites and residual condition holds)
             while (raim_discarded_rows.size() < tdcp_params.raim_n and
-                   A.rows() - raim_discarded_rows.size() > tdcp_params.min_common_sats and
+                   n_rows - raim_discarded_rows.size() > tdcp_params.min_common_sats and
                    residual_ci > tdcp_params.max_residual_ci)
             {
                 auto A_raim = A;
                 auto r_raim = r;
 
-                // METHOD A: using normalized RMSE residual_ci
+                // METHOD A: using normalized RMSE residual
                 if (tdcp_params.residual_opt == 0)
                 {
                     // solve removing each row
-                    for (int row_removed = 0; row_removed < A_raim.rows(); row_removed++)
+                    for (int row_removed = 0; row_removed < n_rows; row_removed++)
                     {
                         // skip already discarded rows
                         if (raim_discarded_rows.count(row_removed) != 0)
@@ -451,30 +458,34 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                         // no NaN
                         if (!d_raim.array().isNaN().any())
                         {
-                            // residual_ci
+                            // residual
                             if (tdcp_params.residual_opt == 0) // all problem
-                                residual_ci = chisq2ci((r_raim + A_raim * delta_d_raim).squaredNorm() / var_tdcp, A_raim.rows() - raim_discarded_rows.size());
+                                residual = (r_raim + A_raim * delta_d_raim).squaredNorm() / var_tdcp;
                             else if (tdcp_params.residual_opt == 1) // worst sat
-                                residual_ci = chisq2ci((r_raim + A_raim * delta_d_raim).cwiseAbs2().maxCoeff() / var_tdcp, 1);
+                                residual = (r_raim + A_raim * delta_d_raim).cwiseAbs2().maxCoeff() / var_tdcp;
                             else
                                 throw std::runtime_error("unknown value for residual_opt");
-                            // residual = (r_raim + A_raim * delta_d_raim).norm() / (A_raim.rows() - 1);
+                            // residual = (r_raim + A_raim * delta_d_raim).norm() / (n_rows - 1);
+
+                            // residual_ci
+                            residual_ci = chisq2ci(residual, tdcp_params.residual_opt == 0 ? n_rows - raim_discarded_rows.size() : 1);
 
                             #if GNSS_UTILS_TDCP_DEBUG == 1
                                 std::cout << "RAIM excluding row " << row_removed;// << std::endl;
                                 //std::cout << "\tDisplacement vector =" << d_raim.head<3>().transpose() << std::endl;
-                                printf("\tresidual_ci          = %13.10f\n", residual_ci);
+                                printf("\tresidual              = %13.10f\n", residual);
+                                printf("\tresidual_ci           = %13.10f\n", residual_ci);
                                 //std::cout << "Tdcp: drho          = " << r_raim.transpose() << std::endl;
                                 //std::cout << "Tdcp: A             = \n" << A_raim << std::endl;
                                 //std::cout << "Tdcp: H             = \n" << A_raim.transpose() * A_raim << std::endl;
                                 //printf("Tdcp: dT            = %8.3f secs\n", d_raim(3));
                             #endif
 
-                            // store if best residual_ci
-                            if (residual_ci < best_residual_ci)
+                            // store if best residual
+                            if (residual < best_residual)
                             {
                                 worst_sat_row = row_removed;
-                                best_residual_ci = residual_ci;
+                                best_residual = residual;
                                 best_d        = d_raim;
                             }
                         }
@@ -483,10 +494,10 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                         r_raim(row_removed)     = r(row_removed);
                     }
                 }
-                // METHOD B: using max residual_ci in Mahalanobis distance
+                // METHOD B: using max residual in Mahalanobis distance
                 else if (tdcp_params.residual_opt == 1)
                 {
-                    // find index of max residual_ci
+                    // find index of max residual
                     (r + A * delta_d).cwiseAbs2().maxCoeff(&worst_sat_row);
 
                     // remove row
@@ -500,18 +511,22 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                     // no NaN
                     if (!d_raim.array().isNaN().any())
                     {
-                        // residual_ci
+                        // residual
                         if (tdcp_params.residual_opt == 0) // all problem
-                            residual_ci = chisq2ci((r_raim + A_raim * delta_d_raim).squaredNorm() / var_tdcp, A_raim.rows() - raim_discarded_rows.size());
+                            residual = (r_raim + A_raim * delta_d_raim).squaredNorm() / var_tdcp;
                         else if (tdcp_params.residual_opt == 1) // worst sat
-                            residual_ci = chisq2ci((r_raim + A_raim * delta_d_raim).cwiseAbs2().maxCoeff() / var_tdcp, 1);
+                            residual = (r_raim + A_raim * delta_d_raim).cwiseAbs2().maxCoeff() / var_tdcp;
                         else
                             throw std::runtime_error("unknown value for residual_opt");
-                        // residual = (r_raim + A_raim * delta_d_raim).norm() / (A_raim.rows() - 1);
+                        // residual = (r_raim + A_raim * delta_d_raim).norm() / (n_rows - 1);
+
+                        // residual_ci
+                        residual_ci = chisq2ci(residual, tdcp_params.residual_opt == 0 ? n_rows - raim_discarded_rows.size() : 1);
 
                         #if GNSS_UTILS_TDCP_DEBUG == 1
                             std::cout << "RAIM excluding row " << worst_sat_row;// << std::endl;
                             //std::cout << "\tDisplacement vector =" << d_raim.head<3>().transpose() << std::endl;
+                            printf("\tresidual             = %13.10f\n", residual);
                             printf("\tresidual_ci          = %13.10f\n", residual_ci);
                             //std::cout << "Tdcp: drho          = " << r_raim.transpose() << std::endl;
                             //std::cout << "Tdcp: A             = \n" << A_raim << std::endl;
@@ -519,8 +534,8 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                             //printf("Tdcp: dT            = %8.3f secs\n", d_raim(3));
                         #endif
 
-                        // store as best residual_ci
-                        best_residual_ci = residual_ci;
+                        // store as best residual
+                        best_residual = residual;
                         best_d        = d_raim;
                     }
                 }
@@ -544,9 +559,9 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                 r(worst_sat_row)     = 0;
 
                 // Choose the best RAIM solution
-                d     = best_d;
-                cov_d = (A.transpose() * A).inverse();
-                residual_ci = best_residual_ci;
+                d       = best_d;
+                cov_d   = (A.transpose() * A).inverse();
+                residual= best_residual;
             }
 
             #if GNSS_UTILS_TDCP_DEBUG == 1
@@ -558,7 +573,7 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
                 std::cout << "\tInitial guess = " << d_0.transpose() << " (" << d_0.head<3>().norm() << "m)" << std::endl;
                 std::cout << "\tSolution      = " << d.transpose() << " (" << d.head<3>().norm() << "m)" << std::endl;
                 std::cout << "\tClock offset  = " << d(3) << std::endl;
-                std::cout << "\tResidual      = " << best_residual_ci << std::endl;
+                std::cout << "\tResidual      = " << best_residual << std::endl;
                 std::cout << "\tA             = \n" << A << std::endl;
                 std::cout << "\tH             = \n" << A.transpose() * A << std::endl;
                 std::cout << "\tcov_d         = \n" << cov_d << std::endl;
@@ -574,7 +589,8 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
             std::cout << "\tInitial guess = " << d_0.transpose() << " (" << d_0.head<3>().norm() << "m)" << std::endl;
             std::cout << "\tSolution      = " << d.transpose() << " (" << d.head<3>().norm() << "m)" << std::endl;
             std::cout << "\tClock offset  = " << d(3) << std::endl;
-            std::cout << "\tResidual      = " << residual_ci << std::endl;
+            std::cout << "\tResidual      = " << residual << std::endl;
+            std::cout << "\tResidual_ci   = " << residual_ci << std::endl;
             std::cout << "\tA             = \n" << A << std::endl;
             std::cout << "\tH             = \n" << A.transpose() * A << std::endl;
             std::cout << "\tcov_d         = \n" << cov_d << std::endl;
@@ -586,20 +602,27 @@ TdcpOutput Tdcp(const Eigen::Vector3d&  x_r,
     for (int row = 0; row < r.size(); row++)
         if (raim_discarded_rows.count(row) == 0)
             r(row) = drho_m(row) - (s_k.col(row) - x_r - d.head(3)).norm() + (s_r.col(row) - x_r).norm() - d(3);
-    // residual_ci
+    // residual
     if (tdcp_params.residual_opt == 0) // all problem
-        residual_ci = chisq2ci(r.squaredNorm() / var_tdcp, r.rows() - raim_discarded_rows.size());
+        residual = r.squaredNorm() / var_tdcp;
     else if (tdcp_params.residual_opt == 1) // worst sat
-        residual_ci = chisq2ci(r.cwiseAbs2().maxCoeff() / var_tdcp, 1);
+        residual = r.cwiseAbs2().maxCoeff() / var_tdcp;
     else
         throw std::runtime_error("unknown value for residual_opt");
     //residual = sqrt(r.squaredNorm() / (r.size() - raim_discarded_rows.size()));
 
-    // check residual_ci condition
-    if (tdcp_params.validate_residual and residual_ci > tdcp_params.max_residual_ci)
+    // residual_ci
+    residual_ci = chisq2ci(residual, tdcp_params.residual_opt == 0 ? n_rows - raim_discarded_rows.size() : 1);
+
+    // check residual condition
+    if (tdcp_params.validate_residual and
+        residual_ci > tdcp_params.max_residual_ci)
     {
-        printf("Tdcp: Didn't success. Final residual_ci=%f bigger than max_residual_ci=%f.\n", residual_ci, tdcp_params.max_residual_ci);
-        output.msg = "Residual bigger than max_residual_ci";
+        printf("Tdcp: Didn't success. Final residual=%f (CI %f) bigger than max_residual_ci=%f.\n",
+               residual,
+               residual_ci,
+               tdcp_params.max_residual_ci);
+        output.msg = "residual_ci bigger than max_residual_ci";
         output.success = false;
     }
     else
-- 
GitLab