0.5.0
Loading...
Searching...
No Matches
Validate.hpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9/// @file Validate.hpp
10/// @brief Ambiguity resolution validation algorithms
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2023-10-06
13
14#pragma once
15
17#include "util/Assert.h"
18#include "util/Eigen.hpp"
19#include "util/Logger.hpp"
20
21namespace NAV::Ambiguity
22{
23
24/// @brief Calculates the bootstrapped success rate
25/// @param[in] D_LTDL_Q Diagonal entries from the L^T * D * L decomposition of Q
26/// @return The bootstrapped success rate
27/// @note See \cite SpringerHandbookGNSS2017 Springer Handbook GNSS, ch. 23.2.4, eq. 23.28
28template<typename Derived>
29double successRateBootstrapping(const Eigen::MatrixBase<Derived>& D_LTDL_Q)
30{
31 INS_ASSERT_USER_ERROR(D_LTDL_Q.cols() == 1, "Parameter 'D_LTDL_Q' has to be a vector");
32
33 double prod = 1.0;
34 for (Eigen::Index i = 0; i < D_LTDL_Q.rows(); i++)
35 {
36 prod *= 2.0 * math::normalCDF(0.5 / std::sqrt(D_LTDL_Q(i))) - 1;
37 }
38
39 return prod;
40}
41
42/// @brief Difference test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::DifferenceTest
43/// @param[in] aFix1 Best integer ambiguities solution
44/// @param[in] aFix2 Second best integer ambiguities solution
45/// @param[in] aFloat Float ambiguities
46/// @param[in] Qa Covariance matrix of the ambiguities
47/// @param[in] criticalValue Critical value to check against (empirically determined value)
48/// @return True if the test passes and the best integer solution should be accepted
49/// @note See \cite Verhagen2006 Verhagen 2006, eq. 31
50template<typename DerivedAFix1, typename DerivedAFix2, typename DerivedAFloat, typename DerivedQ>
51bool differenceTest(const Eigen::MatrixBase<DerivedAFix1>& aFix1, const Eigen::MatrixBase<DerivedAFix2>& aFix2,
52 const Eigen::MatrixBase<DerivedAFloat>& aFloat, const Eigen::MatrixBase<DerivedQ>& Qa, double criticalValue)
53{
54 static_assert(DerivedAFix1::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix1::ColsAtCompileTime == 1);
55 static_assert(DerivedAFix2::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix2::ColsAtCompileTime == 1);
56 static_assert(DerivedAFloat::ColsAtCompileTime == Eigen::Dynamic || DerivedAFloat::ColsAtCompileTime == 1);
57 INS_ASSERT_USER_ERROR(aFix1.cols() == 1, "Parameter 'aFix1' has to be a vector");
58 INS_ASSERT_USER_ERROR(aFix2.cols() == 1, "Parameter 'aFix2' has to be a vector");
59 INS_ASSERT_USER_ERROR(aFloat.cols() == 1, "Parameter 'aFloat' has to be a vector");
60 INS_ASSERT_USER_ERROR(aFix1.rows() == aFix2.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
61 INS_ASSERT_USER_ERROR(aFix1.rows() == aFloat.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
62
63 return math::squaredNormVectorMatrix(aFloat - aFix2, Qa) - math::squaredNormVectorMatrix(aFloat - aFix1, Qa) >= criticalValue;
64}
65
66/// @brief Difference test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::DifferenceTest
67/// @param[in] sqNormFix1 Squared norm of the best integer ambiguities solution
68/// @param[in] sqNormFix2 Squared norm of the second best integer ambiguities solution
69/// @param[in] criticalValue Critical value to check against (empirically determined value)
70/// @return True if the test passes and the best integer solution should be accepted
71/// @note See \cite Verhagen2006 Verhagen 2006, eq. 31
72bool differenceTest(double sqNormFix1, double sqNormFix2, double criticalValue);
73
74/// @brief Ratio test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::RatioTestCriticalValue
75/// @param[in] aFix1 Best integer ambiguities solution
76/// @param[in] aFix2 Second best integer ambiguities solution
77/// @param[in] aFloat Float ambiguities
78/// @param[in] Qa Covariance matrix of the ambiguities
79/// @param[in] mu Critical value to check against, with range (0, 1]
80/// @return True if the test passes and the best integer solution should be accepted
81/// @note See \cite SpringerHandbookGNSS2017 Springer Handbook GNSS, ch. 23.6.4, eq. 23.78 or \cite Verhagen2006 Verhagen 2006, eq. 28, 29
82template<typename DerivedAFix1, typename DerivedAFix2, typename DerivedAFloat, typename DerivedQ>
83bool ratioTest(const Eigen::MatrixBase<DerivedAFix1>& aFix1, const Eigen::MatrixBase<DerivedAFix2>& aFix2,
84 const Eigen::MatrixBase<DerivedAFloat>& aFloat, const Eigen::MatrixBase<DerivedQ>& Qa, double mu)
85{
86 static_assert(DerivedAFix1::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix1::ColsAtCompileTime == 1);
87 static_assert(DerivedAFix2::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix2::ColsAtCompileTime == 1);
88 static_assert(DerivedAFloat::ColsAtCompileTime == Eigen::Dynamic || DerivedAFloat::ColsAtCompileTime == 1);
89 INS_ASSERT_USER_ERROR(aFix1.cols() == 1, "Parameter 'aFix1' has to be a vector");
90 INS_ASSERT_USER_ERROR(aFix2.cols() == 1, "Parameter 'aFix2' has to be a vector");
91 INS_ASSERT_USER_ERROR(aFloat.cols() == 1, "Parameter 'aFloat' has to be a vector");
92 INS_ASSERT_USER_ERROR(aFix1.rows() == aFix2.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
93 INS_ASSERT_USER_ERROR(aFix1.rows() == aFloat.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
94
95 return math::squaredNormVectorMatrix(aFloat - aFix1, Qa) / math::squaredNormVectorMatrix(aFloat - aFix2, Qa) <= mu;
96}
97
98/// @brief Ratio test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::RatioTestCriticalValue
99/// @param[in] sqNormFix1 Squared norm of the best integer ambiguities solution
100/// @param[in] sqNormFix2 Squared norm of the second best integer ambiguities solution
101/// @param[in] mu Critical value to check against, with range (0, 1]
102/// @return True if the test passes and the best integer solution should be accepted
103/// @note See \cite SpringerHandbookGNSS2017 Springer Handbook GNSS, ch. 23.6.4, eq. 23.78 or \cite Verhagen2006 Verhagen 2006, eq. 28, 29
104bool ratioTest(double sqNormFix1, double sqNormFix2, double mu);
105
106/// @brief Look-up table for the critical value µ, depending on failure rate Pf_ILS
107/// @param Pf Failure probability to not be higher
108/// @param Pf_ILS Upper bound of the failure probability
109/// @param nAmb Amount of ambiguities
110/// @return Critical value µ
111double criticalValueFailureRateLookup(double Pf, double Pf_ILS, size_t nAmb);
112
113/// @brief Ratio test with a fixed-failure rate for ambiguity resolution, see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::RatioTestFailureRate
114/// @param[in] Pf Fixed-failure rate
115/// @param[in] aFix1 Best integer ambiguities solution
116/// @param[in] aFix2 Second best integer ambiguities solution
117/// @param[in] aFloat Float ambiguities
118/// @param[in] Qa Covariance matrix of the ambiguities
119/// @param[in] D_LTDL_Q Diagonal entries from the L^T * D * L decomposition of Q
120/// @return True if the test passes and the best integer solution should be accepted
121/// @note See \cite Verhagen2013 Verhagen 2013
122template<typename DerivedAFix1, typename DerivedAFix2, typename DerivedAFloat, typename DerivedQ, typename DerivedD>
123bool fixedFailureRateRatioTest(double Pf, const Eigen::MatrixBase<DerivedAFix1>& aFix1, const Eigen::MatrixBase<DerivedAFix2>& aFix2,
124 const Eigen::MatrixBase<DerivedAFloat>& aFloat, const Eigen::MatrixBase<DerivedQ>& Qa,
125 const Eigen::MatrixBase<DerivedD>& D_LTDL_Q)
126{
127 // Bootstrapped failure rate is an upper bound for the ILS failure rate
128 double Pf_ILS = 1.0 - successRateBootstrapping(D_LTDL_Q);
129 LOG_DATA("Pf_ILS = {}", Pf_ILS);
130
131 // If Pf_ILS <= Pf, set µ equal to 1.0 which always accept the solution in the ratio test. So we can directly return true
132 if (Pf_ILS <= Pf) { return true; }
133
134 double mu = criticalValueFailureRateLookup(Pf, Pf_ILS, static_cast<size_t>(aFloat.rows()));
135
136 return ratioTest(aFix1, aFix2, aFloat, Qa, mu);
137}
138
139/// @brief Ratio test with a fixed-failure rate for ambiguity resolution, see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::RatioTestFailureRate
140/// @param[in] Pf Fixed-failure rate
141/// @param[in] sqNormFix1 Squared norm of the best integer ambiguities solution
142/// @param[in] sqNormFix2 Squared norm of the second best integer ambiguities solution
143/// @param[in] nAmb Number of ambiguities
144/// @param[in] D_LTDL_Q Diagonal entries from the L^T * D * L decomposition of Q
145/// @param[in] validateBootstrappedSuccessRate Whether to check the bootstrapped success rate before doing the ratio test
146/// @return True if the test passes and the best integer solution should be accepted
147/// @note See \cite Verhagen2013 Verhagen 2013
148template<typename DerivedD>
149bool fixedFailureRateRatioTest(double Pf, double sqNormFix1, double sqNormFix2, size_t nAmb, const Eigen::MatrixBase<DerivedD>& D_LTDL_Q, bool validateBootstrappedSuccessRate = true)
150{
151 // Bootstrapped failure rate is an upper bound for the ILS failure rate
152 double Pf_ILS = 1.0 - successRateBootstrapping(D_LTDL_Q);
153 LOG_DATA("Pf_ILS = {}", Pf_ILS);
154
155 // If Pf_ILS <= Pf, set µ equal to 1.0 which always accept the solution in the ratio test. So we can directly return true
156 if (validateBootstrappedSuccessRate && Pf_ILS <= Pf) { return true; }
157
158 double mu = criticalValueFailureRateLookup(Pf, Pf_ILS, nAmb);
159
160 return ratioTest(sqNormFix1, sqNormFix2, mu);
161}
162
163/// @brief Projector test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::ProjectorTest
164/// @param[in] aFix1 Best integer ambiguities solution
165/// @param[in] aFix2 Second best integer ambiguities solution
166/// @param[in] aFloat Float ambiguities
167/// @param[in] Qa Covariance matrix of the ambiguities
168/// @param[in] mu Critical value to check against, with range (0, 1]
169/// @return True if the test passes and the best integer solution should be accepted
170/// @note See \cite Verhagen2006 Verhagen 2006, eq. 35
171template<typename DerivedAFix1, typename DerivedAFix2, typename DerivedAFloat, typename DerivedQ>
172bool projectorTest(const Eigen::MatrixBase<DerivedAFix1>& aFix1, const Eigen::MatrixBase<DerivedAFix2>& aFix2,
173 const Eigen::MatrixBase<DerivedAFloat>& aFloat, const Eigen::MatrixBase<DerivedQ>& Qa, double mu)
174{
175 static_assert(DerivedAFix1::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix1::ColsAtCompileTime == 1);
176 static_assert(DerivedAFix2::ColsAtCompileTime == Eigen::Dynamic || DerivedAFix2::ColsAtCompileTime == 1);
177 static_assert(DerivedAFloat::ColsAtCompileTime == Eigen::Dynamic || DerivedAFloat::ColsAtCompileTime == 1);
178 INS_ASSERT_USER_ERROR(aFix1.cols() == 1, "Parameter 'aFix1' has to be a vector");
179 INS_ASSERT_USER_ERROR(aFix2.cols() == 1, "Parameter 'aFix2' has to be a vector");
180 INS_ASSERT_USER_ERROR(aFloat.cols() == 1, "Parameter 'aFloat' has to be a vector");
181 INS_ASSERT_USER_ERROR(aFix1.rows() == aFix2.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
182 INS_ASSERT_USER_ERROR(aFix1.rows() == aFloat.rows(), "Parameter 'aFix1' needs to have the same size as 'aFix2' and 'aFloat'");
183
184 double proj = (aFix2 - aFix1).transpose() * Qa.inverse() * (aFloat - aFix1);
185 return std::abs(proj / math::squaredNormVectorMatrix(aFix2 - aFix1, Qa)) <= mu;
186}
187
188} // namespace NAV::Ambiguity
Assertion helpers.
#define INS_ASSERT_USER_ERROR(_EXP, _MSG)
Assert function with message.
Definition Assert.h:21
Vector space operations.
Utility class for logging to console and file.
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
Simple Math functions.
bool fixedFailureRateRatioTest(double Pf, const Eigen::MatrixBase< DerivedAFix1 > &aFix1, const Eigen::MatrixBase< DerivedAFix2 > &aFix2, const Eigen::MatrixBase< DerivedAFloat > &aFloat, const Eigen::MatrixBase< DerivedQ > &Qa, const Eigen::MatrixBase< DerivedD > &D_LTDL_Q)
Ratio test with a fixed-failure rate for ambiguity resolution, see NAV::AmbiguityResolutionParameters...
Definition Validate.hpp:123
bool differenceTest(double sqNormFix1, double sqNormFix2, double criticalValue)
Difference test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgori...
Definition Validate.cpp:98
bool ratioTest(double sqNormFix1, double sqNormFix2, double mu)
Ratio test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorithm::...
Definition Validate.cpp:103
double successRateBootstrapping(const Eigen::MatrixBase< Derived > &D_LTDL_Q)
Calculates the bootstrapped success rate.
Definition Validate.hpp:29
bool projectorTest(const Eigen::MatrixBase< DerivedAFix1 > &aFix1, const Eigen::MatrixBase< DerivedAFix2 > &aFix2, const Eigen::MatrixBase< DerivedAFloat > &aFloat, const Eigen::MatrixBase< DerivedQ > &Qa, double mu)
Projector test for the ambiguity resolution see NAV::AmbiguityResolutionParameters::ValidationAlgorit...
Definition Validate.hpp:172
double criticalValueFailureRateLookup(double Pf, double Pf_ILS, size_t nAmb)
Look-up table for the critical value µ, depending on failure rate Pf_ILS.
Definition Validate.cpp:108
DerivedA::Scalar squaredNormVectorMatrix(const Eigen::MatrixBase< DerivedA > &a, const Eigen::MatrixBase< DerivedQ > &Q)
Calculates the squared norm of the vector and matrix.
Definition Math.hpp:321
double normalCDF(double value)
Calculates the cumulative distribution function (CDF) of the standard normal distribution.
Definition Math.cpp:48