blob: e82c668b6639775d72b2b0262906eb84ca4c7b2e [file] [log] [blame]
Austin Schuha647d602018-02-18 14:05:15 -08001#ifndef FRC971_CONTROL_LOOPS_JACOBIAN_H_
2#define FRC971_CONTROL_LOOPS_JACOBIAN_H_
3
4#include <Eigen/Dense>
5
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -08006namespace frc971::control_loops {
Austin Schuha647d602018-02-18 14:05:15 -08007
James Kuszmauld6e7f692024-10-29 22:29:17 -07008template <int num_states, int num_inputs, typename Scalar, typename F>
9::Eigen::Matrix<Scalar, num_states, num_inputs> NumericalJacobian(
10 const F &fn, ::Eigen::Matrix<Scalar, num_inputs, 1> input) {
11 constexpr Scalar kEpsilon = 1e-5;
12 ::Eigen::Matrix<Scalar, num_states, num_inputs> result =
13 ::Eigen::Matrix<Scalar, num_states, num_inputs>::Zero();
Austin Schuha647d602018-02-18 14:05:15 -080014
15 // It's more expensive, but +- epsilon will be more accurate
16 for (int i = 0; i < num_inputs; ++i) {
James Kuszmauld6e7f692024-10-29 22:29:17 -070017 ::Eigen::Matrix<Scalar, num_inputs, 1> dX_plus = input;
Austin Schuha647d602018-02-18 14:05:15 -080018 dX_plus(i, 0) += kEpsilon;
James Kuszmauld6e7f692024-10-29 22:29:17 -070019 ::Eigen::Matrix<Scalar, num_inputs, 1> dX_minus = input;
Austin Schuha647d602018-02-18 14:05:15 -080020 dX_minus(i, 0) -= kEpsilon;
21 result.col(i) = (fn(dX_plus) - fn(dX_minus)) / (kEpsilon * 2.0);
22 }
23 return result;
24}
25
26// Implements a numerical jacobian with respect to X for f(X, U, ...).
James Kuszmauld6e7f692024-10-29 22:29:17 -070027template <int num_states, int num_u, typename Scalar, typename F,
28 typename... Args>
29::Eigen::Matrix<Scalar, num_states, num_states> NumericalJacobianX(
30 const F &fn, ::Eigen::Matrix<Scalar, num_states, 1> X,
31 ::Eigen::Matrix<Scalar, num_u, 1> U, Args &&...args) {
Austin Schuha647d602018-02-18 14:05:15 -080032 return NumericalJacobian<num_states, num_states>(
James Kuszmauld6e7f692024-10-29 22:29:17 -070033 [&](::Eigen::Matrix<Scalar, num_states, 1> X) {
Austin Schuha647d602018-02-18 14:05:15 -080034 return fn(X, U, args...);
35 },
36 X);
37}
38
39// Implements a numerical jacobian with respect to U for f(X, U, ...).
James Kuszmauld6e7f692024-10-29 22:29:17 -070040template <int num_states, int num_u, typename Scalar, typename F,
41 typename... Args>
42::Eigen::Matrix<Scalar, num_states, num_u> NumericalJacobianU(
43 const F &fn, ::Eigen::Matrix<Scalar, num_states, 1> X,
44 ::Eigen::Matrix<Scalar, num_u, 1> U, Args &&...args) {
Austin Schuha647d602018-02-18 14:05:15 -080045 return NumericalJacobian<num_states, num_u>(
James Kuszmauld6e7f692024-10-29 22:29:17 -070046 [&](::Eigen::Matrix<Scalar, num_u, 1> U) { return fn(X, U, args...); },
Austin Schuha647d602018-02-18 14:05:15 -080047 U);
48}
49
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080050} // namespace frc971::control_loops
Austin Schuha647d602018-02-18 14:05:15 -080051
52#endif // FRC971_CONTROL_LOOPS_JACOBIAN_H_