113 "infer_lqn_ekf requires transcendental arithmetic: its Er and Ea summaries "
114 "are root mean squares, and the sensitivity matrix it corrects on is a "
115 "finite difference whose truncation error no arithmetic can remove");
117 const std::size_t np = a0.size();
118 const std::size_t no = Z.
rows();
119 const std::size_t nsteps = Z.
cols();
120 if (np == 0)
throw InputError(
"infer_lqn_ekf: empty parameter vector");
121 if (nsteps == 0)
throw InputError(
"infer_lqn_ekf: no measurements");
122 if (P0.
rows() != np || P0.
cols() != np)
throw InputError(
"infer_lqn_ekf: P0 is not np x np");
123 if (Q.
rows() != np || Q.
cols() != np)
throw InputError(
"infer_lqn_ekf: Q is not np x np");
124 if (R.
rows() != no || R.
cols() != no)
throw InputError(
"infer_lqn_ekf: R is not no x no");
125 if (!opts.a_true.empty() && opts.a_true.size() != np)
126 throw InputError(
"infer_lqn_ekf: aTrue has the wrong length");
136 out.
Phist.reserve(nsteps);
138 std::vector<T> a = a0;
141 for (std::size_t k = 0; k < nsteps; ++k) {
143 const std::vector<T> aPred = a;
145 for (std::size_t i = 0; i < np; ++i)
146 for (std::size_t j = 0; j < np; ++j) Ppred(i, j) = P(i, j) + Q(i, j);
151 if (jac.
h0.size() != no)
152 throw InputError(
"infer_lqn_ekf: the observation map and Z disagree on the "
153 "observation count");
157 std::vector<T> e(no, zero);
158 for (std::size_t i = 0; i < no; ++i) e[i] = Z(i, k) - jac.
h0[i];
162 for (std::size_t i = 0; i < np; ++i)
163 for (std::size_t j = 0; j < no; ++j) {
165 for (std::size_t l = 0; l < np; ++l) s += Ppred(i, l) * H(j, l);
169 for (std::size_t i = 0; i < no; ++i)
170 for (std::size_t j = 0; j < no; ++j) {
172 for (std::size_t l = 0; l < np; ++l) s += H(i, l) * B(l, j);
176 const std::vector<std::size_t> piv =
lu_factor(LU);
178 for (std::size_t i = 0; i < np; ++i) {
179 std::vector<T> rhs(no, zero);
180 for (std::size_t j = 0; j < no; ++j) rhs[j] = B(i, j);
182 for (std::size_t j = 0; j < no; ++j) K(i, j) = rhs[j];
186 for (std::size_t i = 0; i < np; ++i) {
188 for (std::size_t j = 0; j < no; ++j) s += K(i, j) * e[j];
191 if (opts.clamp_positive)
192 for (std::size_t i = 0; i < np; ++i)
193 if (a[i] < floor) a[i] = floor;
197 for (std::size_t i = 0; i < np; ++i)
198 for (std::size_t j = 0; j < np; ++j) {
200 for (std::size_t l = 0; l < no; ++l) s += K(i, l) * H(l, j);
204 for (std::size_t i = 0; i < np; ++i)
205 for (std::size_t j = 0; j < np; ++j) {
207 for (std::size_t l = 0; l < np; ++l) s -= KH(i, l) * Ppred(l, j);
210 for (std::size_t i = 0; i < np; ++i)
211 for (std::size_t j = i; j < np; ++j) {
212 const T s = half * (Pnew(i, j) + Pnew(j, i));
218 for (std::size_t i = 0; i < np; ++i) out.
ahat(i, k) = a[i];
219 for (std::size_t i = 0; i < no; ++i) {
223 out.
Phist.push_back(P);
229 for (std::size_t i = 0; i < no; ++i)
230 for (std::size_t k = 0; k < nsteps; ++k) se += out.
e(i, k) * out.
e(i, k);
231 const std::size_t ne = no * nsteps;
232 out.
Er = ne == 0 ? zero
235 if (!opts.a_true.empty()) {
237 for (std::size_t i = 0; i < np; ++i)
238 for (std::size_t k = 0; k < nsteps; ++k) {
239 const T d = out.
ahat(i, k) - opts.a_true[i];
242 const std::size_t na = np * nsteps;
JacobianResult< T > infer_lqn_jacobian(const std::function< std::vector< T >(const std::vector< T > &)> &hfun, const std::vector< T > &a, double fd_step=1e-3, double fd_floor=1e-6)
Forward finite-difference sensitivity matrix of an observation map.
EkfResult< T > infer_lqn_ekf(const std::function< std::vector< T >(const std::vector< T > &)> &hfun, const std::vector< T > &a0, const Matrix< T > &P0, const Matrix< T > &Z, const Matrix< T > &Q, const Matrix< T > &R, const EkfOptions< T > &opts=EkfOptions< T >())
Extended Kalman Filter for LQN parameter identification.
void lu_solve(const Matrix< T > &LU, const std::vector< std::size_t > &piv, std::vector< T > &b)
Solve LUx = Pb in place on b, using the factors from lu_factor.