Class that stores a function that is able to help determine the time and state at which a step of the initial value problem integration of a System should end, which may be done for any number of purposes, including publishing or state reinitialization (i.e., event handling).
More...
template<class T>
class drake::systems::WitnessFunction< T >
Class that stores a function that is able to help determine the time and state at which a step of the initial value problem integration of a System should end, which may be done for any number of purposes, including publishing or state reinitialization (i.e., event handling).
System authors declare witness functions through LeafSystem::DeclareWitnessFunction().
For the ensuing discussion, consider two times (t₀
and t₁ > t₀
) and states corresponding to those times (x(t₀)
and x(t₁)
). A witness function, w(t, x)
, "triggers" only when it crosses zero at a time t*
where t₀ < t* ≤ t₁
. Note the half-open interval. For an example of a witness function, consider the "signed distance" (i.e., Euclidean distance when bodies are disjoint and minimum translational distance when bodies intersect) between two rigid bodies; this witness function can be used to determine both the time of impact for rigid bodies and their states at that time of impact.
Precision in the definition of the witness function is necessary, because we want the witness function to trigger only once if, for example, w(t₀, x(t₀)) ≠ 0
, w(t₁, x(t₁)) = 0
, and w(t₂, x(t₂)) ≠ 0
, for some t₂ > t₁. In other words, if the witness function is evaluated over the intervals [t₀, t₁] and [t₁, t₂], meaning that the zero occurs precisely at an interval endpoint, the witness function should trigger once. Similarly, the witness function should trigger exactly once if w(t₀, x(t₀)) ≠ 0
, w(t*, x(t*)) = 0
, and w(t₁, x(t₁)) = 0
, for t* ∈ (t₀, t₁)
. We can define the trigger condition formally over interval [t₀, t₁]
using the function:
T(w, t₀, x(t₀), t₁) = 1 if w(t₀, x(t₀)) ≠ 0 and
w(t₀, x(t₀))⋅w(t₁, x(t₁)) ≤ 0
0 if w(t₀, x(t₀)) = 0 or
w(t₀, x(t₀))⋅w(t₁, x(t₁)) > 0
We wish for the witness function to trigger if the trigger function evaluates to one. The trigger function can be further modified, if desired, to incorporate the constraint that the witness function should trigger only when crossing from positive values to negative values, or vice versa.
A good witness function should not cross zero repeatedly over a small interval of time (relative to the maximum designated integration step size) or over small changes in state; when a witness function has been "bracketed" over an interval of time (i.e., it changes sign), that witness function will ideally cross zero only once in that interval.
A witness function trigger time is isolated only to a small interval of time (as described in Simulator). The disadvantage of this scheme is that it always requires the length of the interval to be reduced to the requisite length and that each function evaluation (which requires numerical integration) is extraordinarily expensive. If, for example, the (slow) bisection algorithm were used to isolate the time interval, the number of integrations necessary to cut the interval from a length of ℓ to a length of ε will be log₂(ℓ / ε). Bisection is just one of several possible algorithms for isolating the time interval, though it's a reliable choice and always converges linearly.