forked from pz4kybsvg/Conception
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.5 KiB
102 lines
3.5 KiB
2 years ago
|
#pragma once
|
||
|
|
||
|
#include <cmath>
|
||
|
|
||
|
#include "drake/systems/framework/event.h"
|
||
|
#include "drake/systems/framework/leaf_system.h"
|
||
|
|
||
|
namespace drake {
|
||
|
namespace examples {
|
||
|
namespace fibonacci {
|
||
|
|
||
|
/** A pure discrete system that generates the Fibonacci sequence F_n using
|
||
|
a difference equation.
|
||
|
|
||
|
@system
|
||
|
name: FibonacciDifferenceEquation
|
||
|
output_ports:
|
||
|
- Fn
|
||
|
@endsystem
|
||
|
|
||
|
In general, a discrete system has a difference equation (update function),
|
||
|
output function, and (for simulation) an initial value:
|
||
|
- _update_ function `x_{n+1} = f(n, x_n, u_n)`, and
|
||
|
- _output_ function `y_n = g(n, x_n, u_n)`, and
|
||
|
- `x_0 ≜ x_init`.
|
||
|
|
||
|
where x is a vector of discrete variables, u is a vector of external inputs,
|
||
|
and y is a vector of values that constitute the desired output of the discrete
|
||
|
system. The subscript indicates the value of these variables at step n, where
|
||
|
n is an integer 0, 1, 2, ... .
|
||
|
|
||
|
The Fibonacci sequence is defined by the second-order difference equation
|
||
|
```
|
||
|
F_{n+1} = F_n + F_{n-1}, with F₀ ≜ 0, F₁ ≜ 1,
|
||
|
```
|
||
|
which uses no input.
|
||
|
|
||
|
We can write this second order system as a pair of first-order difference
|
||
|
equations, using two state variables `x = {x[0], x[1]}` (we're using square
|
||
|
brackets for indexing the 2-element vector x, _not_ for step number!). In this
|
||
|
case x_n[0] holds F_n (the value of F at step n) while x_n[1] holds F_{n-1} (the
|
||
|
previous value, i.e. the value of F at step n-1). Here is the discrete system:
|
||
|
```
|
||
|
x_{n+1} = {x_n[0] + x_n[1], x_n[0]} // f()
|
||
|
y_n = x_n[0] // g()
|
||
|
x₀ ≜ {0, 1} // x_init
|
||
|
```
|
||
|
|
||
|
We want to show how to emulate this difference equation in Drake's hybrid
|
||
|
simulator, which advances a continuous time variable t rather than a discrete
|
||
|
step number n. To do that, we pick an arbitrary discrete period h, and show that
|
||
|
publishing at `t = n*h` produces the expected result
|
||
|
```
|
||
|
n 0 1 2 3 4 5 6 7 8
|
||
|
F_n 0 1 1 2 3 5 8 13 21 ...
|
||
|
```
|
||
|
|
||
|
See run_fibonacci.cc for the code required to output the above sequence.
|
||
|
|
||
|
*/
|
||
|
class FibonacciDifferenceEquation : public systems::LeafSystem<double> {
|
||
|
public:
|
||
|
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(FibonacciDifferenceEquation)
|
||
|
|
||
|
FibonacciDifferenceEquation() {
|
||
|
// Set default initial conditions to produce the above sequence.
|
||
|
DeclareDiscreteState(Eigen::Vector2d(0., 1.));
|
||
|
|
||
|
// Update to x_{n+1}, using a Drake "discrete update" event (occurs
|
||
|
// at the beginning of step n+1).
|
||
|
DeclarePeriodicDiscreteUpdateEvent(kPeriod, 0., // First update is at t=0.
|
||
|
&FibonacciDifferenceEquation::Update);
|
||
|
|
||
|
// Output y_n. This will be the Fibonacci element F_n if queried at `t=n*h`.
|
||
|
DeclareVectorOutputPort("Fn", 1, &FibonacciDifferenceEquation::Output);
|
||
|
}
|
||
|
|
||
|
/// Update period (in seconds) for the system.
|
||
|
static constexpr double kPeriod = 0.25; // Arbitrary, e.g. 0.1234 works too!
|
||
|
|
||
|
private:
|
||
|
// Update function x_{n+1} = f(n, x_n).
|
||
|
void Update(const systems::Context<double>& context,
|
||
|
systems::DiscreteValues<double>* xd) const {
|
||
|
const auto& x_n = context.get_discrete_state();
|
||
|
(*xd)[0] = x_n[0] + x_n[1];
|
||
|
(*xd)[1] = x_n[0];
|
||
|
}
|
||
|
|
||
|
// Returns the result of the output function y_n = g(n, x_n) when the output
|
||
|
// port is evaluated at t=n*h.
|
||
|
void Output(const systems::Context<double>& context,
|
||
|
systems::BasicVector<double>* result) const {
|
||
|
const double F_n = context.get_discrete_state()[0]; // x_n[0]
|
||
|
(*result)[0] = F_n;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace fibonacci
|
||
|
} // namespace examples
|
||
|
} // namespace drake
|