forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaffine_system.h
303 lines (268 loc) · 11.9 KB
/
affine_system.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#pragma once
#include <memory>
#include <vector>
#include "drake/common/drake_copyable.h"
#include "drake/common/eigen_types.h"
#include "drake/common/symbolic/expression.h"
#include "drake/systems/framework/leaf_system.h"
namespace drake {
namespace systems {
/**
* Base class for a discrete- or continuous-time, time-varying affine
* system, with potentially time-varying coefficients.
*
* @system
* name: TimeVaryingAffineSystem
* input_ports:
* - u0
* output_ports:
* - y0
* @endsystem
*
* If `time_period > 0.0`, then the affine system will have the state update:
* @f[ x(t+h) = A(t) x(t) + B(t) u(t) + f_0(t), @f]
* where `h` is the time_period. If `time_period == 0.0`, then the system will
* have the time derivatives:
* @f[ \dot{x}(t) = A(t) x(t) + B(t) u(t) + f_0(t), @f]
* where `u` denotes the input vector, `x` denotes the state vector.
*
* In both cases, the system will have the output:
* @f[ y(t) = C(t) x(t) + D(t) u(t) + y_0(t), @f]
* where `y` denotes the output vector.
*
* When configured as a discrete system, the discrete update can be triggered
* either by the defined periodic trigger or via a manual forced update.
*
* @tparam_default_scalar
* @ingroup primitive_systems
* *
* @see AffineSystem
*/
template <typename T>
class TimeVaryingAffineSystem : public LeafSystem<T> {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(TimeVaryingAffineSystem);
/// Returns the input port containing the externally applied input.
const InputPort<T>& get_input_port() const;
/// Returns the output port containing the output state.
const OutputPort<T>& get_output_port() const;
/// @name Methods To Be Implemented by Subclasses
///
/// Implementations must define these, and the returned matrices must
/// be sized to match the `num_states`, `num_inputs`, and `num_outputs`
/// specified in the constructor.
/// @{
virtual MatrixX<T> A(const T& t) const = 0;
virtual MatrixX<T> B(const T& t) const = 0;
virtual VectorX<T> f0(const T& t) const = 0;
virtual MatrixX<T> C(const T& t) const = 0;
virtual MatrixX<T> D(const T& t) const = 0;
virtual VectorX<T> y0(const T& t) const = 0;
/// @}
/// Configures the value that will be assigned to the state vector in
/// `SetDefaultContext`. `x0` must be a vector of length `num_states`.
void configure_default_state(const Eigen::Ref<const VectorX<T>>& x0);
/// Configures the Gaussian distribution over state vectors used in the
/// `SetRandomContext` methods. The mean of the distribution will be the
/// default state (@see configure_default_state()). `covariance` must have
/// size `num_states` by `num_states` and must be symmetric and positive
/// semi-definite.
void configure_random_state(
const Eigen::Ref<const Eigen::MatrixXd>& covariance);
/// Returns the configured default state. @see configure_default_state().
const VectorX<T>& get_default_state() const { return x0_; }
/// Returns the configured random state covariance.
const Eigen::MatrixXd get_random_state_covariance() const {
return Sqrt_Sigma_x0_ * Sqrt_Sigma_x0_;
}
double time_period() const { return time_period_; }
int num_states() const { return num_states_; }
int num_inputs() const { return num_inputs_; }
int num_outputs() const { return num_outputs_; }
protected:
/// Constructor.
///
/// @param converter scalar-type conversion support helper (i.e., AutoDiff,
/// etc.); pass a default-constructed object if such support is not desired.
/// See @ref system_scalar_conversion for detailed background and examples
/// related to scalar-type conversion support.
/// @param num_states size of the system's state vector
/// @param num_inputs size of the system's input vector
/// @param num_outputs size of the system's output vector
/// @param time_period discrete update period, or 0.0 to use continuous time
TimeVaryingAffineSystem(SystemScalarConverter converter, int num_states,
int num_inputs, int num_outputs, double time_period);
/// Helper method. Derived classes should call this from the
/// scalar-converting copy constructor.
template <typename U>
void ConfigureDefaultAndRandomStateFrom(
const TimeVaryingAffineSystem<U>& other);
/// Computes @f[ y(t) = C(t) x(t) + D(t) u(t) + y_0(t), @f] with by calling
/// `C(t)`, `D(t)`, and `y0(t)` with runtime size checks. Derived classes
/// may override this for performance reasons.
virtual void CalcOutputY(const Context<T>& context,
BasicVector<T>* output_vector) const;
/// Computes @f[ \dot{x}(t) = A(t) x(t) + B(t) u(t) + f_0(t), @f] with by
/// calling `A(t)`, `B(t)`, and `f0(t)` with runtime size checks. Derived
/// classes may override this for performance reasons.
void DoCalcTimeDerivatives(const Context<T>& context,
ContinuousState<T>* derivatives) const override;
/// Computes @f[ x(t+h) = A(t) x(t) + B(t) u(t) + f_0(t), @f] with by calling
/// `A(t)`, `B(t)`, and `f0(t)` with runtime size checks. This is the event
/// handler for the periodic and forced discrete update events. Derived
/// classes may override this for performance reasons.
virtual EventStatus CalcDiscreteUpdate(const Context<T>& context,
DiscreteValues<T>* updates) const;
/// Sets the initial conditions.
void SetDefaultState(const Context<T>& context,
State<T>* state) const override;
/// Sets the random initial conditions.
void SetRandomState(const Context<T>& context, State<T>* state,
RandomGenerator* generator) const override;
private:
// For use by DRAKE_DEFINE_FUNCTION_TEMPLATE_INSTANTIATIONS... because the
// function it needs to instantiate is protected.
template <typename, typename>
friend constexpr auto Make_Function_Pointers();
const int num_states_{0};
const int num_inputs_{0};
const int num_outputs_{0};
const double time_period_{0.0};
VectorX<T> x0_; // Default state.
Eigen::MatrixXd Sqrt_Sigma_x0_; // Square root of state covariance matrix.
};
/// A discrete OR continuous affine system (with constant coefficients).
///
/// @system
/// name: AffineSystem
/// input_ports:
/// - u0
/// output_ports:
/// - y0
/// @endsystem
///
/// Let `u` denote the input vector, `x` denote the state vector, and
/// `y` denote the output vector.
///
/// If `time_period > 0.0`, the affine system will have the following
/// discrete-time state update:
/// @f[ x(t+h) = A x(t) + B u(t) + f_0, @f]
/// where `h` is the time_period.
/// If `time_period == 0.0`, the affine system will have the following
/// continuous-time state update:
/// @f[\dot{x} = A x + B u + f_0. @f]
///
/// In both cases, the system will have the output:
/// @f[y = C x + D u + y_0, @f]
///
/// @tparam_default_scalar
///
/// @ingroup primitive_systems
///
/// @see LinearSystem
/// @see MatrixGain
template <typename T>
class AffineSystem : public TimeVaryingAffineSystem<T> {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(AffineSystem);
/// Constructs an Affine system with a fixed set of coefficient matrices `A`,
/// `B`,`C`, and `D` as well as fixed initial velocity offset `xDot0` and
/// output offset `y0`.
/// The coefficient matrices must obey the following dimensions :
/// | Matrix | Num Rows | Num Columns |
/// |:-------:|:-----------:|:-----------:|
/// | A | num states | num states |
/// | B | num states | num inputs |
/// | f0 | num_states | 1 |
/// | C | num outputs | num states |
/// | D | num outputs | num inputs |
/// | y0 | num_outputs | 1 |
///
/// Empty matrices are treated as zero matrices with the appropriate number
/// of rows and columns.
///
/// @param time_period Defines the period of the discrete time system; use
/// time_period=0.0 to denote a continuous time system. @default 0.0
///
/// Subclasses must use the protected constructor, not this one.
explicit AffineSystem(
const Eigen::Ref<const Eigen::MatrixXd>& A = Eigen::MatrixXd(),
const Eigen::Ref<const Eigen::MatrixXd>& B = Eigen::MatrixXd(),
const Eigen::Ref<const Eigen::VectorXd>& f0 = Eigen::VectorXd(),
const Eigen::Ref<const Eigen::MatrixXd>& C = Eigen::MatrixXd(),
const Eigen::Ref<const Eigen::MatrixXd>& D = Eigen::MatrixXd(),
const Eigen::Ref<const Eigen::VectorXd>& y0 = Eigen::VectorXd(),
double time_period = 0.0);
/// Scalar-converting copy constructor. See @ref system_scalar_conversion.
template <typename U>
explicit AffineSystem(const AffineSystem<U>&);
/// Creates a unique pointer to AffineSystem<T> by decomposing @p dynamics and
/// @p outputs using @p state_vars and @p input_vars.
///
/// @throws std::exception if either @p dynamics or @p outputs is not
/// affine in @p state_vars and @p input_vars.
static std::unique_ptr<AffineSystem<T>> MakeAffineSystem(
const Eigen::Ref<const VectorX<symbolic::Expression>>& dynamics,
const Eigen::Ref<const VectorX<symbolic::Expression>>& output,
const Eigen::Ref<const VectorX<symbolic::Variable>>& state_vars,
const Eigen::Ref<const VectorX<symbolic::Variable>>& input_vars,
double time_period = 0.0);
/// @name Helper getter methods.
/// @{
const Eigen::MatrixXd& A() const { return A_; }
const Eigen::MatrixXd& B() const { return B_; }
const Eigen::VectorXd& f0() const { return f0_; }
const Eigen::MatrixXd& C() const { return C_; }
const Eigen::MatrixXd& D() const { return D_; }
const Eigen::VectorXd& y0() const { return y0_; }
/// @}
/// @name Implementations of TimeVaryingAffineSystem<T>'s pure virtual
/// methods.
/// @{
MatrixX<T> A(const T&) const final { return MatrixX<T>(A_); }
MatrixX<T> B(const T&) const final { return MatrixX<T>(B_); }
VectorX<T> f0(const T&) const final { return VectorX<T>(f0_); }
MatrixX<T> C(const T&) const final { return MatrixX<T>(C_); }
MatrixX<T> D(const T&) const final { return MatrixX<T>(D_); }
VectorX<T> y0(const T&) const final { return VectorX<T>(y0_); }
/// @}
/// Updates the coefficients of the affine system. The new coefficients must
/// have the same size as existing coefficients.
void UpdateCoefficients(const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,
const Eigen::Ref<const Eigen::VectorXd>& f0,
const Eigen::Ref<const Eigen::MatrixXd>& C,
const Eigen::Ref<const Eigen::MatrixXd>& D,
const Eigen::Ref<const Eigen::VectorXd>& y0);
protected:
/// Constructor that specifies scalar-type conversion support.
/// @param converter scalar-type conversion support helper (i.e., AutoDiff,
/// etc.); pass a default-constructed object if such support is not desired.
/// See @ref system_scalar_conversion for detailed background and examples
/// related to scalar-type conversion support.
AffineSystem(SystemScalarConverter converter,
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,
const Eigen::Ref<const Eigen::VectorXd>& f0,
const Eigen::Ref<const Eigen::MatrixXd>& C,
const Eigen::Ref<const Eigen::MatrixXd>& D,
const Eigen::Ref<const Eigen::VectorXd>& y0, double time_period);
private:
void CalcOutputY(const Context<T>& context,
BasicVector<T>* output_vector) const final;
void DoCalcTimeDerivatives(const Context<T>& context,
ContinuousState<T>* derivatives) const final;
// We can simplify the discrete update event handler here.
EventStatus CalcDiscreteUpdate(const Context<T>& context,
DiscreteValues<T>* updates) const final;
Eigen::MatrixXd A_;
Eigen::MatrixXd B_;
Eigen::VectorXd f0_;
Eigen::MatrixXd C_;
Eigen::MatrixXd D_;
Eigen::VectorXd y0_;
bool has_meaningful_C_{};
bool has_meaningful_D_{};
};
} // namespace systems
} // namespace drake