Autoware.Auto
srcf_core.hpp
Go to the documentation of this file.
1 // Copyright 2018 the Autoware Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // Co-developed by Tier IV, Inc. and Apex.AI, Inc.
18 #ifndef KALMAN_FILTER__SRCF_CORE_HPP_
19 #define KALMAN_FILTER__SRCF_CORE_HPP_
20 
21 #include <common/types.hpp>
23 #include <Eigen/Core>
24 
25 #include <cmath>
26 #include <limits>
27 
29 
30 namespace autoware
31 {
34 namespace prediction
35 {
37 namespace kalman_filter
38 {
41 
46 template<int32_t NumStates, int32_t ProcessNoiseDim>
47 class SrcfCore
48 {
49 public:
50  using state_vec_t = Eigen::Matrix<float32_t, NumStates, 1>;
51  using square_mat_t = Eigen::Matrix<float32_t, NumStates, NumStates>;
52 
69  template<int32_t ColN1, int32_t ColN2>
70  static void zero_row(
71  Eigen::Matrix<float32_t, NumStates, ColN1> & A,
72  Eigen::Matrix<float32_t, NumStates, ColN2> & B,
73  const index_t row,
74  const index_t col_start,
75  const index_t col_end)
76  {
77  // TODO(cvasfi): Use the proper Eigen API (eg. JacobiRotation) for matrix decompositions
78 
79  for (index_t j = col_start; j < col_end; ++j) {
80  const float32_t g = B(row, j);
81  // TODO(c.ho) benchmark branchi-ness
82  if (fabsf(g) <= std::numeric_limits<decltype(g)>::epsilon()) {
83  // c = 1, s = 0
84  // Do nothing, identity rotation
85  } else if (fabsf(A(row, row)) <= std::numeric_limits<decltype(g)>::epsilon()) {
86  // c = 0, s = sign(g)
87  for (index_t k = row; k < NumStates; ++k) {
88  const float32_t tau = std::copysign(A(k, row), g);
89  A(k, row) = std::copysign(B(k, j), g);
90  B(k, j) = tau;
91  }
92  } else {
93  const float32_t f = A(row, row);
94  const float32_t ir = 1.0F / std::copysign(sqrtf((f * f) + (g * g)), f);
95  const float32_t s = g * ir;
96  const float32_t c = fabsf(f * ir);
97  // TODO(c.ho) benchmark BLAS
98  // probably slightly more efficient to do it this way than ~6 ish BLAS ops
99  for (index_t k = row; k < NumStates; ++k) {
100  const float32_t tau = (c * B(k, j)) - (s * A(k, row));
101  A(k, row) = (s * B(k, j)) + (c * A(k, row));
102  B(k, j) = tau;
103  }
104  }
105  }
106  }
107 
117  template<int32_t NCols2>
119  square_mat_t & A,
120  Eigen::Matrix<float32_t, NumStates, NCols2> & B,
121  const index_t b_rank = NCols2)
122  {
123  // For each row in fat partitioned matrix, [A | B]
124  for (index_t i = index_t{}; i < NumStates; ++i) {
125  zero_row(A, B, i, index_t(), b_rank);
126  zero_row(A, A, i, i + 1, NumStates);
127  }
128  }
129 
141  template<typename Derived>
143  const float32_t z,
144  const float32_t r,
145  const Eigen::MatrixBase<Derived> & h,
146  square_mat_t & C,
147  state_vec_t & x)
148  {
149  // This implementation is adapted from the lower triangle update in
150  // "Estimation with Applications to Tracking and Navigation" Bar-shalom & Li,
151  // Ch 7.4: pg314-315
152  // Where the implementation is modified by applying the diagonal scaling in-place,
153  // i.e. P = LDL^T = SS^T <--> S = LD^(1/2)
154  // all operations are guanteed to be in domain if r is positive
155  if (r <= 0.0F) {
156  throw std::domain_error("ScrfCore: measurement noise variance must be positive");
157  }
158  float32_t alpha = r;
159  m_k.setZero();
160  for (index_t idx = NumStates - 1; idx < NumStates && idx >= 0; --idx) {
161  const index_t jdx = NumStates - idx;
162  Eigen::Block<square_mat_t> col = C.block(idx, idx, jdx, 1);
163  // f_j = C_j^T * h^T, C_j = j'th col of C
164  const float32_t sigma =
165  (h.block(0, idx, 1, jdx) * col)(0, 0);
166  // beta = alpha_{j-1}
167  const float32_t beta = alpha;
168  // alpha_j = alpha_{j-1} + (f_j^2)
169  alpha += (sigma * sigma);
170  m_tau.block(0, 0, jdx, 1) = col;
171  const float32_t zetap = -sigma / beta; // beta is positive if R is positive
172  // Update covariance column C_j = -K_{j-1} * (f_j / beta) + C_j
173  col += zetap * m_k.block(idx, 0, jdx, 1);
174  const float32_t etap = sqrtf(beta / alpha); // alpha positive if beta is
175  // scale by diagonal factor C_j = C_j * sqrt(beta / alpha)
176  col *= etap;
177  // accumulate unscaled kalman gain: K = K + f_j * C_{j, -}
178  m_k.block(idx, 0, jdx, 1) += sigma * m_tau.block(0, 0, jdx, 1);
179  }
180  const float32_t del = z - (h * x)(0, 0);
181 
182  // alpha established to be positive
183  if (alpha <= 0.0F) {
184  // if code is written properly, this branch should never hit!
185  throw std::runtime_error("ScrfCore: invariant broken, kalman gain must be positive");
186  }
187  // Update state vector by error * unscaled kalman_gain
188  const float32_t del_alpha = del / alpha;
189  x += del_alpha * m_k;
190 
191  // constant for computation (logf isn't constexpr due to errno)
192  constexpr float32_t logf2pi = 1.83787706641F;
193  // alpha = r + h^T * P * h = s = scalar component of innovation covariance (variance)
194  // use gaussian likelihood
195  return -0.5F * (logf2pi + logf(alpha) + (del * del_alpha));
196  }
197 
198 private:
199  state_vec_t m_tau;
200  state_vec_t m_k;
201  static_assert(NumStates > 0U, "must have positive number of states");
202  static_assert(ProcessNoiseDim > 0U, "must have positive number of process noise dimensions");
203 }; // class SrcfCore
204 } // namespace kalman_filter
205 } // namespace prediction
206 } // namespace autoware
207 
208 #endif // KALMAN_FILTER__SRCF_CORE_HPP_
static void right_lower_triangularize_matrices(square_mat_t &A, Eigen::Matrix< float32_t, NumStates, NCols2 > &B, const index_t b_rank=NCols2)
Triangularize the fat partitioned matrix, [A | B] s.t.: [A&#39; | 0] = [A | B] * T, where A&#39; is lower tri...
Definition: srcf_core.hpp:118
DifferentialEquation f
Definition: kinematic_bicycle.snippet.hpp:44
Eigen::Index index_t
Type for matrix indexing.
Definition: srcf_core.hpp:40
float float32_t
Definition: types.hpp:36
This class is an implementation of the carlson-schmidt temporal and observation update for the square...
Definition: srcf_core.hpp:47
This file includes common type definition.
Eigen::Matrix< float32_t, NumStates, NumStates > square_mat_t
Definition: srcf_core.hpp:51
float32_t scalar_update(const float32_t z, const float32_t r, const Eigen::MatrixBase< Derived > &h, square_mat_t &C, state_vec_t &x)
do the Carlson first-order observation update, assumes uncorrelated measurement noise ...
Definition: srcf_core.hpp:142
static void zero_row(Eigen::Matrix< float32_t, NumStates, ColN1 > &A, Eigen::Matrix< float32_t, NumStates, ColN2 > &B, const index_t row, const index_t col_start, const index_t col_end)
Applies the right triangularization operation on a single row, e.g. implicitly applying the givens ro...
Definition: srcf_core.hpp:70
Eigen::Matrix< float32_t, NumStates, 1 > state_vec_t
Definition: srcf_core.hpp:50
IntermediateState beta
Definition: kinematic_bicycle.snippet.hpp:42
DifferentialState x
Definition: kinematic_bicycle.snippet.hpp:28
std::size_t Index
Index type for identifying bins of the hash/lattice.
Definition: spatial_hash_config.hpp:49
This file defines the lanelet2_map_provider_node class.
Definition: quick_sort.hpp:24