0.3.0
Loading...
Searching...
No Matches
KalmanFilter.cpp
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 KalmanFilter.cpp
10/// @brief SPP Kalman Filter
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2023-12-22
13
14#include "KalmanFilter.hpp"
15
16#include <algorithm>
17#include <functional>
18#include <variant>
19
27#include "util/Logger.hpp"
28#include <Eigen/src/Core/Matrix.h>
29#include <fmt/format.h>
30
31namespace NAV::SPP
32{
33void KalmanFilter::reset(const std::vector<SatelliteSystem>& satelliteSystems)
34{
35 // Covariance of the P matrix initialization velocity uncertainty [m²/s²]
37 {
40 break;
43 break;
44 }
45
46 // Covariance of the P matrix initialization clock drift uncertainty [m²/s²]
48 {
51 break;
54 break;
57 break;
60 break;
61 }
62
63 // Covariance of the P matrix initialization inter system clock drift uncertainty [m²/s²]
65 {
68 break;
71 break;
74 break;
77 break;
78 }
79
80 // ###########################################################################################################
81
82 // Reset values to 0 and remove inter system states
85
87
88 for (const auto& satSys : satelliteSystems)
89 {
90 _kalmanFilter.addState(Keys::RecvClkBias{ satSys });
91 _kalmanFilter.addState(Keys::RecvClkDrift{ satSys });
92 }
94
95 LOG_DATA("F = \n{}", _kalmanFilter.F);
96 LOG_DATA("G = \n{}", _kalmanFilter.G);
97 LOG_DATA("W = \n{}", _kalmanFilter.W);
98 _initialized = false;
99}
100
102{
103 LOG_DATA("x_KF(pre-init) = \n{}", _kalmanFilter.x.transposed());
104 _kalmanFilter.x(states.rowKeys()) = states(all);
105 _kalmanFilter.P(variance.rowKeys(), variance.colKeys()) = variance(all, all) * 100.0; // LSQ variance is very small. So make bigger
106
107 if (!states.hasAnyRows(VelKey)) // We always estimate velocity in the KF, but LSQ could not, so set a default value
108 {
109 _kalmanFilter.P(VelKey, VelKey).diagonal() << Eigen::Vector3d::Ones() * _initCovarianceVelocity;
110 }
111 // We always estimate receiver clock drift in the KF, but LSQ could not, so set a default value
112 for (const auto& key : _kalmanFilter.P.rowKeys())
113 {
114 if (std::holds_alternative<Keys::RecvClkDrift>(key) && !states.hasRow(key))
115 {
117 }
118 }
119
120 _initialized = true;
121}
122
124{
125 _initialized = false;
126}
127
128void KalmanFilter::predict(const double& dt, const Eigen::Vector3d& lla_pos, [[maybe_unused]] const std::string& nameId)
129{
130 // Update the State transition matrix (𝚽) and the Process noise covariance matrix (𝐐)
131
132 LOG_DATA("{}: F =\n{}", nameId, _kalmanFilter.F);
133 LOG_DATA("{}: G =\n{}", nameId, _kalmanFilter.G);
134 LOG_DATA("{}: W =\n{}", nameId, _kalmanFilter.W);
135
136 _motionModel.updatePhiAndQ(_kalmanFilter.Phi,
141 dt,
142 lla_pos(0),
143 lla_pos(1),
145
146 _receiverClockModel.updatePhiAndQ(_kalmanFilter.Phi,
151 dt,
153
154 _interFrequencyBiasModel.updatePhiAndQ(_kalmanFilter.Phi,
156 dt);
157
158 LOG_DATA("{}: Phi =\n{}", nameId, _kalmanFilter.Phi);
159 LOG_DATA("{}: Q =\n{}", nameId, _kalmanFilter.Q);
160
161 LOG_DATA("{}: P (a posteriori) =\n{}", nameId, _kalmanFilter.P);
162 LOG_DATA("{}: x (a posteriori) =\n{}", nameId, _kalmanFilter.x.transposed());
163 _kalmanFilter.predict();
164 LOG_DATA("{}: x (a priori ) =\n{}", nameId, _kalmanFilter.x.transposed());
165 LOG_DATA("{}: P (a priori ) =\n{}", nameId, _kalmanFilter.P);
166}
167
168void KalmanFilter::update(const std::vector<Meas::MeasKeyTypes>& measKeys,
172 [[maybe_unused]] const std::string& nameId)
173{
174 LOG_DATA("{}: called", nameId);
175
176 _kalmanFilter.setMeasurements(measKeys);
177
178 _kalmanFilter.H = H;
179 _kalmanFilter.R = R;
180 _kalmanFilter.z = dz;
181
182 _kalmanFilter.correctWithMeasurementInnovation();
183}
184
186{
187 auto bias = Keys::InterFreqBias{ freq };
188 _kalmanFilter.addState(bias);
189 _kalmanFilter.P(bias, bias) = _kalmanFilter.P(Keys::RecvClkBias{ freq.getSatSys() },
190 Keys::RecvClkBias{ freq.getSatSys() });
191 _interFrequencyBiasModel.initialize(bias,
194 _kalmanFilter.W);
195}
196
197bool KalmanFilter::ShowGuiWidgets(const char* id, bool useDoppler, bool multiConstellation, bool estimateInterFrequencyBiases, float itemWidth, float unitWidth)
198{
199 bool changed = false;
200
201 itemWidth -= ImGui::GetStyle().IndentSpacing;
202 float configWidth = itemWidth + unitWidth;
203
204 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
205 if (ImGui::TreeNode(fmt::format("System/Process noise##{}", id).c_str()))
206 {
207 changed |= SystemModelGui(_systemModelCalcAlgorithm, itemWidth, id);
208
209 changed |= _motionModel.ShowGui(configWidth, unitWidth, id);
210 changed |= _receiverClockModel.ShowGui(configWidth, unitWidth, id);
211 if (estimateInterFrequencyBiases)
212 {
213 changed |= _interFrequencyBiasModel.ShowGui(configWidth, unitWidth, id);
214 }
215
216 ImGui::TreePop();
217 }
218
219 if (!useDoppler)
220 {
221 ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
222 if (ImGui::TreeNode(fmt::format("Initial Error Covariance Matrix P##{}", id).c_str()))
223 {
224 if (gui::widgets::InputDoubleWithUnit(fmt::format("{} of the velocity uncertainty##{}",
225 _gui_initCovarianceVelocityUnit == InitCovarianceVelocityUnits::m_s ? "Standard deviation" : "Variance", id)
226 .c_str(),
227 configWidth, unitWidth, &_gui_initCovarianceVelocity, _gui_initCovarianceVelocityUnit, "m/s\0m^2/s^2\0\0",
228 0.0, 0.0, "%.2e", ImGuiInputTextFlags_CharsScientific))
229 {
230 LOG_DEBUG("{}: _gui_initCovarianceVelocity changed to {}", id, _gui_initCovarianceVelocity);
231 LOG_DEBUG("{}: _gui_initCovarianceVelocityUnit changed to {}", id, fmt::underlying(_gui_initCovarianceVelocityUnit));
232 changed = true;
233 }
234 if (gui::widgets::InputDoubleWithUnit(fmt::format("{} of the clock drift uncertainty##{}",
237 ? "Standard deviation"
238 : "Variance",
239 id)
240 .c_str(),
241 configWidth, unitWidth, &_gui_initCovarianceClockDrift, _gui_initCovarianceClockDriftUnit, "m/s\0s/s\0m^2/s^2\0s^2/s^2\0\0",
242 0.0, 0.0, "%.2e", ImGuiInputTextFlags_CharsScientific))
243 {
244 LOG_DEBUG("{}: _gui_initCovarianceClockDrift changed to {}", id, _gui_initCovarianceClockDrift);
245 LOG_DEBUG("{}: _gui_initCovarianceClockDriftUnit changed to {}", id, fmt::underlying(_gui_initCovarianceClockDriftUnit));
246 changed = true;
247 }
248 if (multiConstellation
249 && gui::widgets::InputDoubleWithUnit(fmt::format("{} of the inter system clock drift uncertainty##{}",
252 ? "Standard deviation"
253 : "Variance",
254 id)
255 .c_str(),
256 configWidth, unitWidth, &_gui_initCovarianceInterSysClockDrift, _gui_initCovarianceInterSysClockDriftUnit, "m/s\0s/s\0m^2/s^2\0s^2/s^2\0\0",
257 0.0, 0.0, "%.2e", ImGuiInputTextFlags_CharsScientific))
258 {
259 LOG_DEBUG("{}: _gui_initCovarianceInterSysClockDrift changed to {}", id, _gui_initCovarianceInterSysClockDrift);
260 LOG_DEBUG("{}: _gui_initCovarianceInterSysClockDriftUnit changed to {}", id, fmt::underlying(_gui_initCovarianceInterSysClockDriftUnit));
261 changed = true;
262 }
263
264 ImGui::TreePop();
265 }
266 }
267
268 ImGui::SetNextItemOpen(false, ImGuiCond_FirstUseEver);
269 if (ImGui::TreeNode(fmt::format("Kalman Filter matrices##{}", id).c_str()))
270 {
271 _kalmanFilter.showKalmanFilterMatrixViews(id);
272 ImGui::TreePop();
273 }
274
275 return changed;
276}
277
279{
280 for (const auto& state : _kalmanFilter.P.rowKeys())
281 {
282 if (const auto* bias = std::get_if<Keys::RecvClkBias>(&state))
283 {
284 _kalmanFilter.P(*bias, *bias) = clkPhaseDrift;
285 }
286 }
287}
288
289const std::vector<SPP::States::StateKeyType>& KalmanFilter::getStateKeys() const
290{
291 return _kalmanFilter.x.rowKeys();
292}
293
298
303
304void to_json(json& j, const KalmanFilter& data)
305{
306 j = {
307 { "systemModelCalcAlgorithm", data._systemModelCalcAlgorithm },
308 { "motionModel", data._motionModel },
309 { "receiverClockModel", data._receiverClockModel },
310 { "interFrequencyBiasModel", data._interFrequencyBiasModel },
311 };
312} // namespace NAV::SPP
313
314void from_json(const json& j, KalmanFilter& data)
315{
316 if (j.contains("systemModelCalcAlgorithm")) { j.at("systemModelCalcAlgorithm").get_to(data._systemModelCalcAlgorithm); }
317 if (j.contains("motionModel")) { j.at("motionModel").get_to(data._motionModel); }
318 if (j.contains("receiverClockModel")) { j.at("receiverClockModel").get_to(data._receiverClockModel); }
319 if (j.contains("interFrequencyBiasModel")) { j.at("interFrequencyBiasModel").get_to(data._interFrequencyBiasModel); }
320}
321
322} // namespace NAV::SPP
Transformation collection.
nlohmann::json json
json namespace
Keys for the SPP algorithm for use inside the KeyedMatrices.
Defines Widgets which allow the input of values and the selection of the unit.
Inter Frequency Bias System Model.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
Receiver Clock System Model.
GNSS Satellite System.
System Model.
Frequency definition for different satellite systems.
Definition Frequency.hpp:59
SatelliteSystem getSatSys() const
Get the satellite system for which this frequency is defined.
static constexpr double C
Speed of light [m/s].
Definition Constants.hpp:34
void predict()
Do a Time Update.
The Spp Kalman Filter related options.
MotionModel< SPP::States::StateKeyType > _motionModel
Motion Model.
InitCovarianceClockDriftUnits _gui_initCovarianceClockDriftUnit
Gui selection for the Unit of the P matrix initialization clock drift uncertainty.
void deinitialize()
Deinitialize the KF (can be used to reinitialize the Filter when results seem strange)
void setClockBiasErrorCovariance(double clkPhaseDrift)
Set the P matrix entry for the covariance of the clock phase drift.
const std::vector< SPP::States::StateKeyType > & getStateKeys() const
Get the States in the Kalman Filter.
const std::array< SPP::States::StateKeyType, 6 > & PosVelKey
All position and velocity keys.
void reset(const std::vector< SatelliteSystem > &satelliteSystems)
Resets the filter.
void update(const std::vector< Meas::MeasKeyTypes > &measKeys, const KeyedMatrixXd< Meas::MeasKeyTypes, States::StateKeyType > &H, const KeyedMatrixXd< Meas::MeasKeyTypes, Meas::MeasKeyTypes > &R, const KeyedVectorXd< Meas::MeasKeyTypes > &dz, const std::string &nameId)
Does the Kalman Filter update.
const KeyedVectorXd< States::StateKeyType > & getState() const
Returns the State vector x̂
ReceiverClockModel< SPP::States::StateKeyType > _receiverClockModel
Receiver clock Model.
double _initCovarianceClockDrift
Covariance of the P matrix initialization clock drift uncertainty [m²/s²].
void initialize(const KeyedVectorXd< States::StateKeyType > &states, const KeyedMatrixXd< States::StateKeyType, States::StateKeyType > &variance)
Initialize the filter.
double _initCovarianceInterSysClockDrift
Covariance of the P matrix initialization inter system clock drift uncertainty [m²/s²].
void addInterFrequencyBias(const Frequency &freq)
Adds the frequency as inter-frequency bias state.
InitCovarianceClockDriftUnits _gui_initCovarianceInterSysClockDriftUnit
Gui selection for the Unit of the P matrix initialization inter system clock drift uncertainty.
SystemModelCalcAlgorithm _systemModelCalcAlgorithm
Algorithm to calculate the system models with.
InterFrequencyBiasModel< SPP::States::StateKeyType > _interFrequencyBiasModel
Inter-frequency bias Model.
InitCovarianceVelocityUnits _gui_initCovarianceVelocityUnit
Gui selection for the Unit of the P matrix initialization velocity uncertainty.
double _gui_initCovarianceVelocity
GUI selection for the P matrix initialization velocity uncertainty.
KeyedKalmanFilterD< SPP::States::StateKeyType, SPP::Meas::MeasKeyTypes > _kalmanFilter
Kalman Filter representation.
double _gui_initCovarianceClockDrift
GUI selection for the P matrix initialization clock drift uncertainty.
const std::array< SPP::States::StateKeyType, 3 > & VelKey
All velocity keys.
double _initCovarianceVelocity
Covariance of the P matrix initialization velocity uncertainty [m²/s²].
bool _initialized
Boolean that determines, if Kalman Filter is initialized (from weighted LSE solution)
double _gui_initCovarianceInterSysClockDrift
GUI selection for the P matrix initialization inter system clock drift uncertainty.
bool ShowGuiWidgets(const char *id, bool useDoppler, bool multiConstellation, bool estimateInterFrequencyBiases, float itemWidth, float unitWidth)
Shows the GUI input to select the options.
const KeyedMatrixXd< States::StateKeyType, States::StateKeyType > & getErrorCovarianceMatrix() const
Returns the Error covariance matrix 𝐏
bool hasRow(const RowKeyType &key) const
Checks if the matrix has the key.
const std::vector< RowKeyType > & rowKeys() const
Returns the row keys.
bool hasAnyRows(std::span< const RowKeyType > keys) const
Checks if the matrix has any key.
std::variant< Psr, Doppler > MeasKeyTypes
Alias for the measurement key type.
Definition Keys.hpp:64
std::variant< Keys::MotionModelKey, Keys::RecvClkBias, Keys::RecvClkDrift, Keys::InterFreqBias > StateKeyType
Alias for the state key type.
Definition Keys.hpp:37
void to_json(json &j, const Algorithm &obj)
Converts the provided object into json.
void from_json(const json &j, Algorithm &obj)
Converts the provided json object into a node object.
InputWithUnitChange InputDoubleWithUnit(const char *label, float itemWidth, float unitWidth, double *v, U &combo_current_item, const char *combo_items_separated_by_zeros, double step=0.0, double step_fast=0.0, const char *format="%.6f", ImGuiInputTextFlags flags=0, int combo_popup_max_height_in_items=-1)
Shows an InputText GUI element to modify the provided value and also set its unit.
bool SystemModelGui(SystemModelCalcAlgorithm &algorithm, float itemWidth, const char *id)
Shows a GUI.
KeyedVectorX< double, RowKeyType > KeyedVectorXd
Dynamic size KeyedVector with double types.
KeyedKalmanFilter< double, StateKeyType, MeasKeyType > KeyedKalmanFilterD
Keyed Kalman Filter class with double as type.
KeyedVector< Scalar, RowKeyType, Eigen::Dynamic > KeyedVectorX
Dynamic size KeyedVector.
static const internal::all_t all
Used to request all rows or columns in KeyedMatrices.
KeyedMatrixX< double, RowKeyType, ColKeyType > KeyedMatrixXd
Dynamic size KeyedMatrix with double types.
Receiver clock error [m].
Receiver clock drift [m/s].