- 3.0.2 core module.
SensitivityApproximation.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 #include <unsupported/Eigen/MatrixFunctions>
9 
10 #define SYMPLECTIC_ENABLED \
11  template <size_t V, size_t P> \
12  typename std::enable_if<(V > 0 && P > 0), void>::type
13 #define SYMPLECTIC_DISABLED \
14  template <size_t V, size_t P> \
15  typename std::enable_if<(V <= 0 || P <= 0), void>::type
16 
17 namespace ct {
18 namespace core {
19 
21 
27 template <size_t STATE_DIM,
28  size_t CONTROL_DIM,
29  size_t P_DIM = STATE_DIM / 2,
30  size_t V_DIM = STATE_DIM / 2,
31  typename SCALAR = double>
32 class SensitivityApproximation : public Sensitivity<STATE_DIM, CONTROL_DIM, SCALAR>
33 {
34 public:
35  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
36 
39 
40 
43  const std::shared_ptr<LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>& linearSystem = nullptr,
46  : linearSystem_(linearSystem), settings_(dt, approx)
47  {
48  }
49 
50 
53  const std::shared_ptr<LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>& linearSystem = nullptr)
54  : linearSystem_(linearSystem), settings_(settings)
55  {
56  }
57 
58 
60  SensitivityApproximation(const SensitivityApproximation& other) : settings_(other.settings_)
61  {
62  if (other.linearSystem_ != nullptr)
63  linearSystem_ = std::shared_ptr<LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>(other.linearSystem_->clone());
64  }
65 
66 
69 
70 
73  {
75  }
76 
77 
80  {
81  settings_.approximation_ = approx;
82  }
83 
84 
88  virtual void setLinearSystem(
89  const std::shared_ptr<LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>& linearSystem) override
90  {
91  linearSystem_ = linearSystem;
92  }
93 
94 
96  virtual void setTimeDiscretization(const SCALAR& dt) override { settings_.dt_ = dt; }
98  void updateSettings(const SensitivityApproximationSettings& settings) { settings_ = settings; }
100 
111  const StateVector<STATE_DIM, SCALAR>& x_next,
112  const int n,
113  const size_t numSteps,
114  state_matrix_t& A,
115  state_control_matrix_t& B) override
116  {
117  if (linearSystem_ == nullptr)
118  throw std::runtime_error("Error in SensitivityApproximation: linearSystem not properly set.");
119 
123  switch (settings_.approximation_)
124  {
126  {
127  forwardEuler(x, u, n, A, B);
128  break;
129  }
131  {
132  backwardEuler(x, u, n + 1, A, B);
133  break;
134  }
136  {
137  symplecticEuler<V_DIM, P_DIM>(x, u, x_next, n, A, B);
138  break;
139  }
141  {
147  state_matrix_t Ac_front;
149  state_control_matrix_t Bc_front;
150 
151  // front derivatives
152  linearSystem_->getDerivatives(Ac_front, Bc_front, x, u, n * settings_.dt_);
153  Ac_front *= settings_.dt_;
154 
155  state_matrix_t Ac_back =
156  settings_.dt_ * linearSystem_->getDerivativeState(x_next, u, (n + 1) * settings_.dt_);
157 
158 
160  state_matrix_t aNewInv;
161  aNewInv.template topLeftCorner<STATE_DIM, STATE_DIM>() =
162  (state_matrix_t::Identity() - Ac_back).colPivHouseholderQr().inverse();
163  A = aNewInv * (state_matrix_t::Identity() + Ac_front);
164  B = aNewInv * settings_.dt_ * Bc_front;
165  break;
166  }
168  {
169  matrixExponential(x, u, n, A, B);
170  break;
171  }
172  default:
173  throw std::runtime_error("Unknown Approximation type in SensitivityApproximation.");
174  } // end switch
175  }
176 
177 
178 private:
179  void forwardEuler(const StateVector<STATE_DIM, SCALAR>& x_n,
181  const int& n,
182  state_matrix_t& A_discr,
183  state_control_matrix_t& B_discr)
184  {
189  state_matrix_t A_cont;
190  state_control_matrix_t B_cont;
191  linearSystem_->getDerivatives(A_cont, B_cont, x_n, u_n, n * settings_.dt_);
192 
193  A_discr = state_matrix_t::Identity() + settings_.dt_ * A_cont;
194  B_discr = settings_.dt_ * B_cont;
195  }
196 
197  void backwardEuler(const StateVector<STATE_DIM, SCALAR>& x_n,
199  const int& n,
200  state_matrix_t& A_discr,
201  state_control_matrix_t& B_discr)
202  {
207  state_matrix_t A_cont;
208  state_control_matrix_t B_cont;
209  linearSystem_->getDerivatives(A_cont, B_cont, x_n, u_n, n * settings_.dt_);
210 
211  state_matrix_t aNew = settings_.dt_ * A_cont;
212  A_discr.setZero();
213  A_discr.template topLeftCorner<STATE_DIM, STATE_DIM>() =
214  (state_matrix_t::Identity() - aNew).colPivHouseholderQr().inverse();
215 
216  B_discr = A_discr * settings_.dt_ * B_cont;
217  }
218 
219 
220  void matrixExponential(const StateVector<STATE_DIM, SCALAR>& x_n,
222  const int& n,
223  state_matrix_t& A_discr,
224  state_control_matrix_t& B_discr)
225  {
226  state_matrix_t Ac;
227  state_control_matrix_t Bc;
228  linearSystem_->getDerivatives(Ac, Bc, x_n, u_n, n * settings_.dt_);
229 
230  state_matrix_t Adt = settings_.dt_ * Ac;
231 
232  A_discr.template topLeftCorner<STATE_DIM, STATE_DIM>() = Adt.exp();
233  B_discr.template topLeftCorner<STATE_DIM, CONTROL_DIM>() =
234  Ac.inverse() * (A_discr - state_matrix_t::Identity()) * Bc;
235  }
236 
237 
239 
248  SYMPLECTIC_ENABLED symplecticEuler(const StateVector<STATE_DIM, SCALAR>& x,
250  const StateVector<STATE_DIM, SCALAR>& x_next,
251  const int& n,
252  state_matrix_t& A_sym,
253  state_control_matrix_t& B_sym)
254  {
255  const SCALAR& dt = settings_.dt_;
256 
257  // our implementation of symplectic integrators first updates the positions, we need to reconstruct an intermediate state accordingly
258  StateVector<STATE_DIM, SCALAR> x_interm = x;
259  x_interm.topRows(P_DIM) = x_next.topRows(P_DIM);
260 
261  state_matrix_t Ac1; // continuous time A matrix for start state and control
262  state_control_matrix_t Bc1; // continuous time B matrix for start state and control
263  linearSystem_->getDerivatives(Ac1, Bc1, x, u, n * dt);
264 
265  state_matrix_t Ac2; // continuous time A matrix for intermediate state and control
266  state_control_matrix_t Bc2; // continuous time B matrix for intermediate state and control
267  linearSystem_->getDerivatives(Ac2, Bc2, x_interm, u, n * dt);
268 
269  getSymplecticEulerApproximation<V_DIM, P_DIM>(Ac1, Ac2, Bc1, Bc2, A_sym, B_sym);
270  }
271 
272 
274 
284  SYMPLECTIC_ENABLED symplecticEuler(const StateVector<STATE_DIM, SCALAR>& x,
286  const int& n,
287  state_matrix_t& A_sym,
288  state_control_matrix_t& B_sym)
289  {
290  const SCALAR& dt = settings_.dt_;
291 
292  state_matrix_t Ac1; // continuous time A matrix for start state and control
293  state_control_matrix_t Bc1; // continuous time B matrix for start state and control
294  linearSystem_->getDerivatives(Ac1, Bc1, x, u, n * dt);
295 
296  getSymplecticEulerApproximation<V_DIM, P_DIM>(Ac1, Ac1, Bc1, Bc1, A_sym, B_sym);
297  }
298 
299 
301 
309  SYMPLECTIC_ENABLED getSymplecticEulerApproximation(const state_matrix_t& Ac1,
310  const state_matrix_t& Ac2,
311  const state_control_matrix_t& Bc1,
312  const state_control_matrix_t& Bc2,
313  state_matrix_t& A_sym,
314  state_control_matrix_t& B_sym)
315  {
316  const SCALAR& dt = settings_.dt_;
317 
318  typedef Eigen::Matrix<SCALAR, P_DIM, P_DIM> p_matrix_t;
319  typedef Eigen::Matrix<SCALAR, V_DIM, V_DIM> v_matrix_t;
320  typedef Eigen::Matrix<SCALAR, P_DIM, V_DIM> p_v_matrix_t;
321  typedef Eigen::Matrix<SCALAR, V_DIM, P_DIM> v_p_matrix_t;
322  typedef Eigen::Matrix<SCALAR, P_DIM, CONTROL_DIM> p_control_matrix_t;
323  typedef Eigen::Matrix<SCALAR, V_DIM, CONTROL_DIM> v_control_matrix_t;
324 
325  // for ease of notation, make a block-wise map to references
326  // elements taken form the linearization at the starting state
327  const Eigen::Ref<const p_matrix_t> A11 = Ac1.topLeftCorner(P_DIM, P_DIM);
328  const Eigen::Ref<const p_v_matrix_t> A12 = Ac1.topRightCorner(P_DIM, V_DIM);
329  const Eigen::Ref<const p_control_matrix_t> B1 = Bc1.topRows(P_DIM);
330 
331  // elements taken from the linearization at the intermediate state
332  const Eigen::Ref<const v_p_matrix_t> A21 = Ac2.bottomLeftCorner(V_DIM, P_DIM);
333  const Eigen::Ref<const v_matrix_t> A22 = Ac2.bottomRightCorner(V_DIM, V_DIM);
334  const Eigen::Ref<const v_control_matrix_t> B2 = Bc2.bottomRows(V_DIM);
335 
336  // discrete approximation A matrix
337  A_sym.topLeftCorner(P_DIM, P_DIM) = p_matrix_t::Identity() + dt * A11;
338  A_sym.topRightCorner(P_DIM, V_DIM) = dt * A12;
339  A_sym.bottomLeftCorner(V_DIM, P_DIM) = dt * (A21 * (p_matrix_t::Identity() + dt * A11));
340  A_sym.bottomRightCorner(V_DIM, V_DIM) = v_matrix_t::Identity() + dt * (A22 + dt * A21 * A12);
341 
342  // discrete approximation B matrix
343  B_sym.topRows(P_DIM) = dt * B1;
344  B_sym.bottomRows(V_DIM) = dt * (B2 + dt * A21 * B1);
345  }
346 
347 
349  SYMPLECTIC_DISABLED symplecticEuler(const StateVector<STATE_DIM, SCALAR>& x_n,
351  const StateVector<STATE_DIM, SCALAR>& x_next,
352  const int& n,
353  state_matrix_t& A,
354  state_control_matrix_t& B)
355  {
356  throw std::runtime_error("SensitivityApproximation : selected symplecticEuler but System is not symplectic.");
357  }
358 
360  SYMPLECTIC_DISABLED symplecticEuler(const StateVector<STATE_DIM, SCALAR>& x,
362  const int& n,
363  state_matrix_t& A_sym,
364  state_control_matrix_t& B_sym)
365  {
366  throw std::runtime_error("SensitivityApproximation : selected symplecticEuler but System is not symplectic.");
367  }
368 
369  SYMPLECTIC_DISABLED getSymplecticEulerApproximation(const state_matrix_t& Ac1,
370  const state_matrix_t& Ac2,
371  const state_control_matrix_t& Bc1,
372  const state_control_matrix_t& Bc2,
373  state_matrix_t& A_sym,
374  state_control_matrix_t B_sym)
375  {
376  throw std::runtime_error("SensitivityApproximation : selected symplecticEuler but System is not symplectic.");
377  }
378 
380  std::shared_ptr<LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>> linearSystem_;
381 
384 };
385 
386 
387 } // namespace core
388 } // namespace ct
389 
390 
391 #undef SYMPLECTIC_ENABLED
392 #undef SYMPLECTIC_DISABLED
interface class for a general linear system or linearized system
Definition: LinearSystem.h:23
APPROXIMATION approximation_
type of discretization strategy used.
Definition: Sensitivity.h:29
APPROXIMATION
different discrete-time approximations to linear systems
Definition: Sensitivity.h:15
virtual void setTimeDiscretization(const SCALAR &dt) override
update the time discretization
Definition: SensitivityApproximation.h:96
ct::core::ControlVector< control_dim > u
virtual void setLinearSystem(const std::shared_ptr< LinearSystem< STATE_DIM, CONTROL_DIM, SCALAR >> &linearSystem) override
update the linear system
Definition: SensitivityApproximation.h:88
SensitivityApproximation(const SCALAR &dt, const std::shared_ptr< LinearSystem< STATE_DIM, CONTROL_DIM, SCALAR >> &linearSystem=nullptr, const SensitivityApproximationSettings::APPROXIMATION &approx=SensitivityApproximationSettings::APPROXIMATION::FORWARD_EULER)
constructor
Definition: SensitivityApproximation.h:42
#define SYMPLECTIC_ENABLED
Definition: SensitivityApproximation.h:10
Definition: StateMatrix.h:12
SensitivityApproximationSettings::APPROXIMATION getApproximation() const
retrieve the approximation type for the discrete-time system
Definition: SensitivityApproximation.h:86
const double dt
virtual void setApproximation(const SensitivityApproximationSettings::APPROXIMATION &approx) override
update the approximation type for the discrete-time system
Definition: SensitivityApproximation.h:79
Definition: ControlVector.h:12
virtual SensitivityApproximation< STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR > * clone() const override
deep cloning
Definition: SensitivityApproximation.h:72
double dt_
discretization time-step
Definition: Sensitivity.h:26
CppAD::AD< CppAD::cg::CG< double > > SCALAR
virtual void getAandB(const StateVector< STATE_DIM, SCALAR > &x, const ControlVector< CONTROL_DIM, SCALAR > &u, const StateVector< STATE_DIM, SCALAR > &x_next, const int n, const size_t numSteps, state_matrix_t &A, state_control_matrix_t &B) override
get A and B matrix for linear time invariant system
Definition: SensitivityApproximation.h:109
constexpr size_t n
Definition: MatrixInversionTest.cpp:14
Definition: StateVector.h:12
SensitivityApproximation(const SensitivityApproximationSettings &settings, const std::shared_ptr< LinearSystem< STATE_DIM, CONTROL_DIM, SCALAR >> &linearSystem=nullptr)
constructor
Definition: SensitivityApproximation.h:52
void updateSettings(const SensitivityApproximationSettings &settings)
update the settings
Definition: SensitivityApproximation.h:98
SensitivityApproximation(const SensitivityApproximation &other)
copy constructor
Definition: SensitivityApproximation.h:60
ct::core::StateVector< state_dim > x
Definition: Sensitivity.h:33
settings for the SensitivityApproximation
Definition: Sensitivity.h:12
interface class for a general linear system or linearized system
Definition: SensitivityApproximation.h:32
virtual ~SensitivityApproximation()
destructor
Definition: SensitivityApproximation.h:68
StateControlMatrix< STATE_DIM, CONTROL_DIM, SCALAR > state_control_matrix_t
input Jacobian type
Definition: SensitivityApproximation.h:38
#define SYMPLECTIC_DISABLED
Definition: SensitivityApproximation.h:13
Definition: StateControlMatrix.h:12
EIGEN_MAKE_ALIGNED_OPERATOR_NEW typedef StateMatrix< STATE_DIM, SCALAR > state_matrix_t
state Jacobian type
Definition: SensitivityApproximation.h:37