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.
Conception/drake-master/examples/fibonacci/fibonacci_difference_equati...

102 lines
3.5 KiB

#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