Simbody
3.4 (development)
|
This is an implementation of the fixed-step Semi-Explicit Euler method, also known as Semi-Implicit Euler or Symplectic Euler. More...
#include <SemiExplicitEulerIntegrator.h>
Public Member Functions | |
SemiExplicitEulerIntegrator (const System &sys, Real stepSize) | |
Create a SemiExplicitEulerIntegrator for integrating a System with fixed size steps. |
This is an implementation of the fixed-step Semi-Explicit Euler method, also known as Semi-Implicit Euler or Symplectic Euler.
This method is very popular for game engines such as ODE, because it is a first order method that is more stable than Explicit Euler. However, the implementation used in gaming is fully explicit, which is only correct if there are no velocity-dependent force elements. Coriolis forces, damping, etc. would require an implicit solution which is generally too slow for real time simulation.
The correct implementation of this method is described in Geometric Numerical Integration, Hairer, Lubich & Wanner 2006, page 3. The method applies to a system of differential equations that can be partitioned like this:
udot = udot(q,u) qdot = qdot(q,u) = N(q)u in Simbody
Semi-Implicit Euler treats one variable implicitly, and the other explicitly, producing two different possible forms:
Form 1: q1 = q0 + h qdot(q1,u0) <-- implicit in q u1 = u0 + h udot(q1,u0) Form 2: u1 = u0 + h udot(q0,u1) <-- implicit in u q1 = q0 + h qdot(q0,u1)
If udot were udot(q) only, Form 2 would be
u1 = u0 + h udot(q0) <-- if no velocity dependence q1 = q0 + h N(q0)u1
That would be a correct, yet fully explicit implementation of Symplectic Euler. Instead, the standard gaming implementation is
u1 = u0 + h udot(q0,u0) <-- wrong; should be implicit in u q1 = q0 + h N(q0)u1
This differs from a true Symplectic Euler by however much the velocity- dependent forces change from u0 to u1. If they are very small, no great loss. That may be less likely in internal coordinates though. Making this implicit would be quite expensive since we don't have analytical partial derivatives of udot available.
Form 1 on the other hand could be implemented efficiently as a true semi-implicit method:
q1 = q0 + h N(q1)u0 <-- implicit in q u1 = u0 + h udot(q1,u0)
The directional partial derivatives D N(q)*u0 / D q are easily calculated for the block diagonal matrix N which in many cases is just an identity matrix. A disadvantage is that accelerations are unknown at (q0,u0) and (q1,u1); if those are needed (very common!) a second evaluation of the accelerations would be required. For that expense, a second order integration method could have been used instead. I also don't know whether this form would have the same stability properties in practice as the other one; it would be interesting to experiment. However, for now we use Form 2 in the gamer's fully-explicit style. This will not work well in the presence of huge damping forces and probably not for very high rotation rates either!
SimTK::SemiExplicitEulerIntegrator::SemiExplicitEulerIntegrator | ( | const System & | sys, |
Real | stepSize | ||
) |
Create a SemiExplicitEulerIntegrator for integrating a System with fixed size steps.