Line | Branch | Exec | Source |
---|---|---|---|
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 NumericalIntegration.hpp | ||
10 | /// @brief Provides Numerical integration methods | ||
11 | /// @author T. Topp (topp@ins.uni-stuttgart.de) | ||
12 | /// @date 2023-12-11 | ||
13 | |||
14 | #pragma once | ||
15 | |||
16 | #include <array> | ||
17 | #include <numeric> | ||
18 | #include <type_traits> | ||
19 | #include <gcem.hpp> | ||
20 | |||
21 | #include "util/Assert.h" | ||
22 | #include "util/Logger.hpp" | ||
23 | |||
24 | namespace NAV | ||
25 | { | ||
26 | |||
27 | namespace ButcherTableau | ||
28 | { | ||
29 | |||
30 | #if defined(__GNUC__) && !defined(__clang__) | ||
31 | #pragma GCC diagnostic push | ||
32 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // NOLINT(clang-diagnostic-unknown-warning-option) | ||
33 | #endif | ||
34 | |||
35 | /// @brief Calculates explicit Runge-Kutta methods. Order is defined by the Butcher tableau | ||
36 | /// @param[in] y_n State vector at time t_n | ||
37 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
38 | /// @param[in] h Integration step in [s] | ||
39 | /// @param[in] f Time derivative function | ||
40 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
41 | /// @param[in] t_n Time t_n | ||
42 | /// @return State vector at time t_(n+1) | ||
43 | template<typename Y, typename Z, std::floating_point Scalar, size_t s, std::array<std::array<Scalar, s + 1>, s + 1> butcherTableau> | ||
44 | 120194 | inline Y RungeKuttaExplicit(const Y& y_n, const std::array<Z, s>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n) | |
45 | { | ||
46 | static_assert(gcem::abs(static_cast<Scalar>(1.0) - std::accumulate(butcherTableau[s].begin(), butcherTableau[s].end(), static_cast<Scalar>(0.0))) < 1e-8, // NOLINT(boost-use-ranges,modernize-use-ranges) // There is no ranges::accumulate | ||
47 | "The sum of the last row in the Butcher tableau has to be 1"); | ||
48 |
2/2✓ Branch 0 taken 296278 times.
✓ Branch 1 taken 69412 times.
|
619600 | for (size_t r = 0; r <= s; ++r) |
49 | { | ||
50 |
2/2✓ Branch 0 taken 490992 times.
✓ Branch 1 taken 296278 times.
|
1295090 | for (size_t c = r + 1; c <= s; ++c) |
51 | { | ||
52 |
3/6✓ Branch 1 taken 490992 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 490992 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 490992 times.
✗ Branch 7 not taken.
|
795684 | INS_ASSERT_USER_ERROR(butcherTableau.at(r).at(c) == 0.0, "All terms in the upper triangle have to be 0"); |
53 | } | ||
54 | } | ||
55 | |||
56 | // std::string result = "y_(n+1) = y_n"; | ||
57 | |||
58 | // std::string sum_b_str; | ||
59 | // std::string sum_b_val; | ||
60 |
1/2✓ Branch 1 taken 69412 times.
✗ Branch 2 not taken.
|
120194 | Y sum_b{}; |
61 |
3/4✓ Branch 1 taken 226866 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 226866 times.
✓ Branch 4 taken 69412 times.
|
499406 | std::array<Y, s> k{}; |
62 |
2/2✓ Branch 0 taken 226866 times.
✓ Branch 1 taken 69412 times.
|
499406 | for (size_t i = 1; i <= s; ++i) |
63 | { | ||
64 |
1/2✓ Branch 2 taken 226866 times.
✗ Branch 3 not taken.
|
379212 | auto b = butcherTableau[s].at(i); |
65 |
1/2✓ Branch 1 taken 226866 times.
✗ Branch 2 not taken.
|
379212 | auto c = butcherTableau.at(i - 1)[0]; |
66 |
1/2✓ Branch 1 taken 226866 times.
✗ Branch 2 not taken.
|
379212 | Y sum_a{}; |
67 | // std::string sum_a_str; | ||
68 | // std::string sum_a_val; | ||
69 |
2/2✓ Branch 0 taken 264126 times.
✓ Branch 1 taken 226866 times.
|
795684 | for (size_t j = 2; j <= i; ++j) |
70 | { | ||
71 |
2/4✓ Branch 1 taken 264126 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 264126 times.
✗ Branch 5 not taken.
|
416472 | auto a = butcherTableau.at(i - 1).at(j - 1); |
72 |
5/8✓ Branch 0 taken 157454 times.
✓ Branch 1 taken 106672 times.
✓ Branch 3 taken 157454 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 157454 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 157454 times.
✗ Branch 10 not taken.
|
416472 | if (j == 2) { sum_a = a * k.at(j - 2); } |
73 |
3/6✓ Branch 1 taken 106672 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106672 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 106672 times.
✗ Branch 8 not taken.
|
157454 | else { sum_a += a * k.at(j - 2); } |
74 | // sum_a_str += fmt::format("a{}{} * k{}", i, j-1, j-1); | ||
75 | // sum_a_val += fmt::format("{:^3.1f} * k{}", a, j - 1); | ||
76 | // if (j < i) { | ||
77 | // sum_a_str += " + "; | ||
78 | // sum_a_val += " + "; | ||
79 | // } | ||
80 | } | ||
81 | |||
82 |
5/8✓ Branch 0 taken 69412 times.
✓ Branch 1 taken 157454 times.
✓ Branch 3 taken 69412 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 69412 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 69412 times.
✗ Branch 10 not taken.
|
379212 | if (i < 2) { k.at(i - 1) = f(y_n, z.at(i - 1), constParam, t_n + c * h); } // Do not add sum_a, because can have nan values |
83 |
6/12✓ Branch 1 taken 157454 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157454 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 157454 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 157454 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 157454 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 157454 times.
✗ Branch 17 not taken.
|
259018 | else { k.at(i - 1) = f(y_n + sum_a * h, z.at(i - 1), constParam, t_n + c * h); } |
84 | // if (sum_a_str.empty()) { sum_a_str = "0"; } | ||
85 | // if (sum_a_val.empty()) { sum_a_val = "0"; } | ||
86 | // fmt::println("k{} = f(t_n + c{} * h, y_n + ({}) * h)", i, i, sum_a_str); | ||
87 | // fmt::println("k{} = f(t_n + {:^3.1f} * h, y_n + ({:^{w}}) * h)", i, c, sum_a_val, fmt::arg("w",sum_a_str.length())); | ||
88 | |||
89 |
5/8✓ Branch 0 taken 69412 times.
✓ Branch 1 taken 157454 times.
✓ Branch 3 taken 69412 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 69412 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 69412 times.
✗ Branch 10 not taken.
|
379212 | if (i == 1) { sum_b = b * k.at(i - 1); } |
90 |
3/6✓ Branch 1 taken 157454 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157454 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 157454 times.
✗ Branch 8 not taken.
|
259018 | else { sum_b += b * k.at(i - 1); } |
91 | // sum_b_str += fmt::format("b{} * k{}", i, i); | ||
92 | // sum_b_val += fmt::format("{:.2f} * k{}", butcherTableau[s].at(i), i); | ||
93 | // if (i < s) | ||
94 | // { | ||
95 | // sum_b_str += " + "; | ||
96 | // sum_b_val += " + "; | ||
97 | // } | ||
98 | } | ||
99 | |||
100 | // std::cout << result + fmt::format(" + h * ({})", sum_b_str) << std::endl; | ||
101 | // std::cout << result + fmt::format(" + h * ({})", sum_b_val) << std::endl; | ||
102 |
3/6✓ Branch 1 taken 69412 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69412 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 69412 times.
✗ Branch 8 not taken.
|
120194 | return y_n + h * sum_b; |
103 | } | ||
104 | |||
105 | #if defined(__GNUC__) && !defined(__clang__) | ||
106 | #pragma GCC diagnostic pop | ||
107 | #endif | ||
108 | |||
109 | /// @brief Butcher tableau for Runge-Kutta 1st order (explicit) / (Forward) Euler method | ||
110 | template<typename Scalar> | ||
111 | constexpr std::array<std::array<Scalar, 2>, 2> RK1 = { { { 0.0, /*|*/ }, | ||
112 | //------------------ | ||
113 | { 0.0, /*|*/ 1.0 } } }; | ||
114 | |||
115 | /// @brief Butcher tableau for Runge-Kutta 2nd order (explicit) / Explicit midpoint method | ||
116 | template<typename Scalar> | ||
117 | constexpr std::array<std::array<Scalar, 3>, 3> RK2 = { { { 0.0, /*|*/ }, | ||
118 | { 0.5, /*|*/ 0.5 }, | ||
119 | //----------------------- | ||
120 | { 0.0, /*|*/ 0.0, 1.0 } } }; | ||
121 | |||
122 | /// @brief Butcher tableau for Heun's method (2nd order) (explicit) | ||
123 | template<typename Scalar> | ||
124 | constexpr std::array<std::array<Scalar, 3>, 3> Heun2 = { { { 0.0, /*|*/ }, | ||
125 | { 1.0, /*|*/ 1.0 }, | ||
126 | //----------------------- | ||
127 | { 0.0, /*|*/ 0.5, 0.5 } } }; | ||
128 | |||
129 | /// @brief Butcher tableau for Runge-Kutta 3rd order (explicit) / Simpson's rule | ||
130 | template<typename Scalar> | ||
131 | constexpr std::array<std::array<Scalar, 4>, 4> RK3 = { { { 0.0, /*|*/ }, | ||
132 | { 0.5, /*|*/ 0.5 }, | ||
133 | { 1.0, /*|*/ -1.0, 2.0 }, | ||
134 | //---------------------------------------------- | ||
135 | { 0.0, /*|*/ 1.0 / 6.0, 4.0 / 6.0, 1.0 / 6.0 } } }; | ||
136 | |||
137 | /// @brief Butcher tableau for Heun's method (3nd order) (explicit) | ||
138 | template<typename Scalar> | ||
139 | constexpr std::array<std::array<Scalar, 4>, 4> Heun3 = { { { 0.0, /* |*/ }, | ||
140 | { 1.0 / 3.0, /*|*/ 1.0 / 3.0 }, | ||
141 | { 2.0 / 3.0, /*|*/ 0.0, 2.0 / 3.0 }, | ||
142 | //---------------------------------------- | ||
143 | { 0.0, /*|*/ 1.0 / 4.0, 0.0, 3.0 / 4.0 } } }; | ||
144 | |||
145 | /// @brief Butcher tableau for Runge-Kutta 4th order (explicit) | ||
146 | template<typename Scalar> | ||
147 | constexpr std::array<std::array<Scalar, 5>, 5> RK4 = { { { 0.0, /*|*/ }, | ||
148 | { 0.5, /*|*/ 0.5 }, | ||
149 | { 0.5, /*|*/ 0.0, 0.5 }, | ||
150 | { 1.0, /*|*/ 0.0, 0.0, 1.0 }, | ||
151 | //------------------ | ||
152 | { 0.0, /*|*/ 1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0 } } }; | ||
153 | |||
154 | } // namespace ButcherTableau | ||
155 | |||
156 | /// @brief Runge-Kutta 1st order (explicit) / (Forward) Euler method | ||
157 | /// \anchor eq-RungeKutta1-explicit \f{equation}{ \label{eq:eq-RungeKutta1-explicit} | ||
158 | /// y_{n+1} = y_n + h f(t_n, y_n) | ||
159 | /// \f} | ||
160 | /// Butcher tableau: | ||
161 | /// \anchor eq-RungeKutta1-explicit-bt \f{equation}{ \label{eq:eq-RungeKutta1-explicit-bt} | ||
162 | /// \renewcommand\arraystretch{1.2} | ||
163 | /// \begin{array}{c|c} | ||
164 | /// 0 \\ \hline | ||
165 | /// & 1 \\ | ||
166 | /// \end{array} | ||
167 | /// \f} | ||
168 | /// @param[in] y_n State vector at time t_n | ||
169 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
170 | /// @param[in] h Integration step in [s] | ||
171 | /// @param[in] f Time derivative function | ||
172 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
173 | /// @param[in] t_n Time t_n | ||
174 | template<typename Y, typename Z, std::floating_point Scalar> | ||
175 | ✗ | Y RungeKutta1(const Y& y_n, const std::array<Z, 1>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | |
176 | { | ||
177 | ✗ | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 1, ButcherTableau::RK1<Scalar>>(y_n, z, h, f, constParam, t_n); | |
178 | } | ||
179 | |||
180 | /// @brief Runge-Kutta 2nd order (explicit) / Explicit midpoint method | ||
181 | /// \anchor eq-RungeKutta2-explicit \f{equation}{ \label{eq:eq-RungeKutta2-explicit} | ||
182 | /// \begin{aligned} | ||
183 | /// y_{n+1} &= y_n + h k_2 \\[1em] | ||
184 | /// k_1 &= f(t_n, y_n) \\ | ||
185 | /// k_2 &= f(t_n + \frac{h}{2}, y_n + \frac{h}{2} k_1) \\ | ||
186 | /// \end{aligned} | ||
187 | /// \f} | ||
188 | /// Butcher tableau: | ||
189 | /// \anchor eq-RungeKutta2-explicit-bt \f{equation}{ \label{eq:eq-RungeKutta2-explicit-bt} | ||
190 | /// \renewcommand\arraystretch{1.2} | ||
191 | /// \begin{array}{c|cc} | ||
192 | /// 0 \\ | ||
193 | /// \frac{1}{2} & \frac{1}{2} \\ \hline | ||
194 | /// & 0 & 1 \\ | ||
195 | /// \end{array} | ||
196 | /// \f} | ||
197 | /// @param[in] y_n State vector at time t_n | ||
198 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
199 | /// @param[in] h Integration step in [s] | ||
200 | /// @param[in] f Time derivative function | ||
201 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
202 | /// @param[in] t_n Time t_n | ||
203 | template<typename Y, typename Z, std::floating_point Scalar> | ||
204 | ✗ | Y RungeKutta2(const Y& y_n, const std::array<Z, 2>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | |
205 | { | ||
206 | ✗ | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 2, ButcherTableau::RK2<Scalar>>(y_n, z, h, f, constParam, t_n); | |
207 | } | ||
208 | |||
209 | /// @brief Heun's method (2nd order) (explicit) | ||
210 | /// \anchor eq-Heun2 \f{equation}{ \label{eq:eq-Heun2} | ||
211 | /// \begin{aligned} | ||
212 | /// y_{n+1} &= y_n + \frac{h}{2} (k_1 + k_2) \\[1em] | ||
213 | /// k_1 &= f(t_n, y_n) \\ | ||
214 | /// k_2 &= f(t_n + h, y_n + h k_1) \\ | ||
215 | /// \end{aligned} | ||
216 | /// \f} | ||
217 | /// Butcher tableau: | ||
218 | /// \anchor eq-Heun2-bt \f{equation}{ \label{eq:eq-Heun2-bt} | ||
219 | /// \renewcommand\arraystretch{1.2} | ||
220 | /// \begin{array}{c|cc} | ||
221 | /// 0 \\ | ||
222 | /// 1 & 1 \\ \hline | ||
223 | /// & \frac{1}{2} & \frac{1}{2} \\ | ||
224 | /// \end{array} | ||
225 | /// \f} | ||
226 | /// @param[in] y_n State vector at time t_n | ||
227 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
228 | /// @param[in] h Integration step in [s] | ||
229 | /// @param[in] f Time derivative function | ||
230 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
231 | /// @param[in] t_n Time t_n | ||
232 | template<typename Y, typename Z, std::floating_point Scalar> | ||
233 | ✗ | Y Heun2(const Y& y_n, const std::array<Z, 2>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | |
234 | { | ||
235 | ✗ | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 2, ButcherTableau::Heun2<Scalar>>(y_n, z, h, f, constParam, t_n); | |
236 | } | ||
237 | |||
238 | /// @brief Runge-Kutta 3rd order (explicit) / Simpson's rule | ||
239 | /// \anchor eq-RungeKutta3-explicit \f{equation}{ \label{eq:eq-RungeKutta3-explicit} | ||
240 | /// \begin{aligned} | ||
241 | /// y_{n+1} &= y_n + \frac{h}{6} ( k_1 + 4 k_2 + k_3 ) \\[1em] | ||
242 | /// k_1 &= f(t_n, y_n) \\ | ||
243 | /// k_2 &= f(t_n + \frac{h}{2}, y_n + \frac{h}{2} k_1) \\ | ||
244 | /// k_3 &= f(t_n + h, y_n + h (-k_1 + 2 k_2)) \\ | ||
245 | /// \end{aligned} | ||
246 | /// \f} | ||
247 | /// Butcher tableau: | ||
248 | /// \anchor eq-RungeKutta3-explicit-bt \f{equation}{ \label{eq:eq-RungeKutta3-explicit-bt} | ||
249 | /// \renewcommand\arraystretch{1.2} | ||
250 | /// \begin{array}{c|ccc} | ||
251 | /// 0 \\ | ||
252 | /// \frac{1}{2} & \frac{1}{2} \\ | ||
253 | /// 1 & -1 & 2 \\ \hline | ||
254 | /// & \frac{1}{6} & \frac{4}{6} & \frac{1}{6} \\ | ||
255 | /// \end{array} | ||
256 | /// \f} | ||
257 | /// @param[in] y_n State vector at time t_n | ||
258 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
259 | /// @param[in] h Integration step in [s] | ||
260 | /// @param[in] f Time derivative function | ||
261 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
262 | /// @param[in] t_n Time t_n | ||
263 | template<typename Y, typename Z, std::floating_point Scalar> | ||
264 | 50782 | Y RungeKutta3(const Y& y_n, const std::array<Z, 3>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | |
265 | { | ||
266 | 50782 | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 3, ButcherTableau::RK3<Scalar>>(y_n, z, h, f, constParam, t_n); | |
267 | } | ||
268 | |||
269 | /// @brief Heun's method (3nd order) (explicit) | ||
270 | /// \anchor eq-Heun3 \f{equation}{ \label{eq:eq-Heun3} | ||
271 | /// \begin{aligned} | ||
272 | /// y_{n+1} &= y_n + \frac{h}{4} (k_1 + 3 k_3) \\[1em] | ||
273 | /// k_1 &= f(t_n, y_n) \\ | ||
274 | /// k_2 &= f(t_n + \frac{h}{3}, y_n + \frac{h}{3} k_1) \\ | ||
275 | /// k_3 &= f(t_n + \frac{2 h}{3}, y_n + \frac{2 h}{3} k_2) \\ | ||
276 | /// \end{aligned} | ||
277 | /// \f} | ||
278 | /// Butcher tableau: | ||
279 | /// \anchor eq-Heun3-bt \f{equation}{ \label{eq:eq-Heun3-bt} | ||
280 | /// \renewcommand\arraystretch{1.2} | ||
281 | /// \begin{array}{c|ccc} | ||
282 | /// 0 \\ | ||
283 | /// \frac{1}{3} & \frac{1}{3} \\ | ||
284 | /// \frac{2}{3} & 0 & \frac{2}{3} \\ \hline | ||
285 | /// & \frac{1}{4} & 0 & \frac{3}{4} \\ | ||
286 | /// \end{array} | ||
287 | /// \f} | ||
288 | /// @param[in] y_n State vector at time t_n | ||
289 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
290 | /// @param[in] h Integration step in [s] | ||
291 | /// @param[in] f Time derivative function | ||
292 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
293 | /// @param[in] t_n Time t_n | ||
294 | template<typename Y, typename Z, std::floating_point Scalar> | ||
295 | Y Heun3(const Y& y_n, const std::array<Z, 3>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | ||
296 | { | ||
297 | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 3, ButcherTableau::Heun3<Scalar>>(y_n, z, h, f, constParam, t_n); | ||
298 | } | ||
299 | |||
300 | /// @brief Runge-Kutta 4th order (explicit) | ||
301 | /// \anchor eq-RungeKutta4-explicit \f{equation}{ \label{eq:eq-RungeKutta4-explicit} | ||
302 | /// \begin{aligned} | ||
303 | /// y_{n+1} &= y_n + \frac{h}{6} ( k_1 + 2 k_2 + 2 k_3 + k_4 ) \\[1em] | ||
304 | /// k_1 &= f(t_n, y_n) \\ | ||
305 | /// k_2 &= f(t_n + \frac{h}{2}, y_n + \frac{h}{2} k_1) \\ | ||
306 | /// k_3 &= f(t_n + \frac{h}{2}, y_n + \frac{h}{2} k_2) \\ | ||
307 | /// k_4 &= f(t_n + h, y_n + h k_3) \\ | ||
308 | /// \end{aligned} | ||
309 | /// \f} | ||
310 | /// Butcher tableau: | ||
311 | /// \anchor eq-RungeKutta4-explicit-bt \f{equation}{ \label{eq:eq-RungeKutta4-explicit-bt} | ||
312 | /// \renewcommand\arraystretch{1.2} | ||
313 | /// \begin{array}{c|cccc} | ||
314 | /// 0 \\ | ||
315 | /// \frac{1}{2} & \frac{1}{2} \\ | ||
316 | /// \frac{1}{2} & 0 & \frac{1}{2} \\ | ||
317 | /// 1 & 0 & 0 & 1 \\ \hline | ||
318 | /// & \frac{1}{6} & \frac{1}{3} & \frac{1}{3} & \frac{1}{6} \\ | ||
319 | /// \end{array} | ||
320 | /// \f} | ||
321 | /// @param[in] y_n State vector at time t_n | ||
322 | /// @param[in] z Array of measurements, one for each evaluation point of the Runge Kutta | ||
323 | /// @param[in] h Integration step in [s] | ||
324 | /// @param[in] f Time derivative function | ||
325 | /// @param[in] constParam Constant parameters passed to each time derivative function call | ||
326 | /// @param[in] t_n Time t_n | ||
327 | template<typename Y, typename Z, std::floating_point Scalar> | ||
328 | 18630 | Y RungeKutta4(const Y& y_n, const std::array<Z, 4>& z, const Scalar& h, const auto& f, const auto& constParam, const Scalar& t_n = 0) | |
329 | { | ||
330 | 18630 | return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 4, ButcherTableau::RK4<Scalar>>(y_n, z, h, f, constParam, t_n); | |
331 | } | ||
332 | |||
333 | } // namespace NAV | ||
334 |