This is a animation of a simple pendulum. The animation can be stopped and restarted with a double click. While stopped, the mass point can be dragged to a new starting position. |
Here is an animation of a (chaotic) double pendulum. Again, the animation can be stopped and restarted with a double click. While stopped, the mass points can be dragged to new starting positions. |
The physics of a pendulum are explained in Eric's Treasure Troves. For the animation of the simple pendulum, we need several independent variables:
<PARAM NAME=INDEPENDENT_VARIABLES VALUE="{t->0, dt->0.02, l->1, m->1, g->9.81, th->0, dth->0, estimth->0, newth->0, newdth->0, x->1, y->0, oldx->0, oldy->0, oldt->0, isAnimating->0,isManipulating->0}">t is the iterator variable of the Animate command, dt is the length of a time step, l is the length of the pendulum, m its mass, g is the gravitational acceleration, th is the angle to the downward vertical, dth is the time derivative of th, estimth is an intermediate estimation of the next value of th, newth is the next value of th, newdth is the next value of dth, (x,y) is the position of the mass point, (oldx,oldy) is the position of the mass point in the last frame, isAnimating is a flag which indicates whether the animation is running, isManipulating indicates whether x or y has been manipulated by the user.
The independent variables are set in the list of dependent variables, which does not declare any new variables but is used to update the values of the independent variables.
<PARAM NAME=DEPENDENT_VARIABLES VALUE="{ isAnimating->If[t != oldt, True, False], isManipulating->If[x != oldx || y != oldy, True, False], th->If[isManipulating, ArcTan[-y, x], If[isAnimating, newth, th]], l->If[isManipulating, Sqrt[x * x + y * y], l], dth->If[isManipulating, 0, If[isAnimating, newdth, dth]], estimth->th + dth dt - 0.5 g / l Sin[th] dt dt, newdth->dth - g / l 0.5 (Sin[th] + Sin[estimth]) dt, newth->th + dth dt - 0.5 g / l 0.5 (Sin[th] + Sin[estimth]) dt dt, x->l*Sin[th], y->-l*Cos[th], oldx->x, oldy->y, oldt->t}">First, we set isAnimating and isManipulating by comparing the current values of t, x, and y with the saved values oldt, oldx, and oldy. If necessary, we update th, either to the user input or the calculated animation. Similarly, l and dth is updated. The calculation of the animation is a simple explicit integration performed in the rules for estimth, newdth, and newth. Then x and y are set according to the current value th (not the next value newth). Finally, the values of x, y, and t are saved in order to determine isAnimating and isManipulating in the next frame.
With these variables the actual Animate command is almost trivial:
<PARAM NAME=INPUT VALUE="Animate[Graphics3D[{ PointSize[0.01], Point[{0,0,0}], Line[{{0,0,0},{x,y,0}}], PointSize[0.03], Point[{x,y,0}]}, Boxed->False, ViewPoint->{0,0,10}, ViewVertical->{0,1,0}, PlotRange->{{-1,1},{-1,1},{-1,1}}], {t, 0, 1}]">Note the particular iterator of the Animate command: t is set only to values 0 and 1; this is sufficient because t is only used to set the isAnimating flag.
The double pendulum is a little more complicated (see Eric's description). However, the same techniques can be employed to compute the animation. (Unfortunately, a simple explicit integration is not accurate enough; therefore, velocities are slightly adjusted to conserve the total energy. See the source of this HTML page for the details.)
It would be interesting to extend the double pendulum example in order to allow for three-dimensional motion and to allow the user to manipulate the two masses.