Line data Source code

1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <cstddef> 8 : 9 : #include "DataStructures/DataVector.hpp" 10 : 11 : /// \ingroup ControlSystemGroup 12 : /// A PND (proportional to Q and N derivatives of Q) controller that computes 13 : /// the control signal: 14 : /// \f[ U(t) = \sum_{k=0}^{N} a_{k} \frac{d^kQ}{dt^k} \f] 15 : /// where N is specified by the template parameter `DerivOrder`. 16 : /// 17 : /// If an averager is used for `q_and_derivs` (as we typically do), there is an 18 : /// induced time offset, \f$\Delta t\f$, due to the time-weighted averaging. 19 : /// Therefore, the `q_and_derivs` that we have in hand are at some time 20 : /// \f$t_{0}\f$. However, we desire `q_and_derivs` at the current time 21 : /// \f$t = t_{0} + \Delta t\f$ to determine the appropriate control 22 : /// signal. We accomplish this by Taylor expanding 23 : /// \f$Q(t_{0} + \Delta t)\f$. The averager allows for averaging of 24 : /// \f$Q\f$ and its derivatives OR to not average \f$Q\f$ while still averaging 25 : /// the derivatives (the derivatives are always averaged in order to reduce 26 : /// noise due to numerical differentiation). When they are both averaged, the 27 : /// time offset will be identical for \f$Q\f$ and the derivatives, 28 : /// i.e. `q_time_offset` = `deriv_time_offset`. If an unaveraged \f$Q\f$ is 29 : /// used, then the time offset associated with \f$Q\f$ is zero, 30 : /// i.e. `q_time_offset`=0. and the derivative time offset, `deriv_time_offset`, 31 : /// remains non-zero. 32 : template <size_t DerivOrder> 33 1 : class Controller { 34 : public: 35 0 : DataVector operator()( 36 : const DataVector& timescales, 37 : const std::array<DataVector, DerivOrder + 1>& q_and_derivs, 38 : double q_time_offset, double deriv_time_offset) const noexcept; 39 : };