The applet above is a gravitational simulator of orbits in space. The executable is in orb.jar and the code is in orbcode.jar. (If you prefer, the code is in Point.java, Eye.java, BVector.java, BMatrix.java, BInterpolate.java, Moon.java, Simulate.java, and Orbit.java.) The mouse lets it stop and start (by clicking without dragging), roll left or up (by clicking near the center and dragging), clockwise and zoom (by clicking far from the center and dragging). Moon colors, sizes, masses, positions, and velocities are applet parameters. Total momentum and and the center of gravity are automatically normalized to (0,0,0). Trajectories are plotted with a symmetric multistep method.

Here's a page that puts the applet through its paces, and another of neat orbits.

Parameters for the applet are:

- name="increment" value="0.2"
- The value is how big a step to take each refresh. There are 20 refreshes per second. Bigger values mean faster orbits and bigger errors.
- name="background" value="000000"
- The color of the background.
- name="work" value="5"
- The number of steps to do per increment. Increases accuracy, increases CPU usage.
- name="sleep" value="50"
- The number of milliseconds to wait after each display. This lets Java garbage collect, and allows the applet to avoid eating all your CPU. It does NOT give you accurate speed control.
- name="trail" value="yes"
- An optional parameter. Have all the moons leave trails. Zooming or rotating erases the trails.
- name="energy" value="yes"
- An optional parameter. Report (current-initial)/initial total energy and the number of times positions have been displayed. Calculating energy requires velocity, and my integration formulas don't track velocity, so I approximate it from the positions. For stable simulations (like the solar system), the error in approximating velocity overwhelms any real error in energy conservation. For unstable simulations (like the one above), close passes cause real errors in energy, position, you name it.
- name="eye" value="100.0 0.0 -0.3 0.0 300.0"
- Distance from center, left-rotation, up-rotation, clockwise-rotation, zoom. Rotations are specified in radians, and are applied in the order left, up, clockwise.
- name="stop" value="yes"
- An optional parameter. Bring up the applet with nothing happening. Clicking on the applet (without dragging the mouse) will start the action. To turn off, don't do value="no", just don't use this parameter.
- name="length" value="10.0"
- An optional parameter. The virtual length of time to run the simulation. There are 20 steps per second, if length=10 and interval=0.01 the simulation will run for 10/(0.01*20) = 50 seconds. The simulation stops once it hits its limit, then clicking on it will reinitialize the simulation and run it again.
- name="scalemass" value="1.0"
- An optional parameter. Scale all masses by this amount. I added it so that I could find the gravitational constant experimentally for my solar system simulation.
- name="moons" value="18"
- The number of moons, moon1 .. moon18. If there is a sun it will be moon1.
- name="moon1" value="p(0.0,0.0,0.0) v(0.0,0.0,0.0) 10.0 ffff00 5.0"
- Moon 1 is defined to have: position(x,y,z), velocity(x,y,z), mass,
color, size. name="moon2" would be moon 2, and so on.
Moons of weight 0 have an optimization that they're ignored when calculating the forces on all other objects. That means 1 sun with 1000 massless satellites takes O(n) to simulate instead of O(n

^{2}). It allows massless objects around binary stars or in globular clusters, too. - name="follow" value="17"
- An optional parameter. Keep the center on moon17. The default center is the center of gravity.
- name="noperspective" value="yes"
- An optional parameter. No perspective, treat all distances as the distance from the eye to the origin.

Here's an overview of the orbital applet.

Newton's Law of Gravity lets you deduce accelerations from positions and masses of moons (Simulate.accel()). The accelerations, positions, and velocities (Moon.velocity()) let you approximate the positions after a small time increment from the current time (Moon.step()). It's convenient to take several steps per display (Simulate.move()).

Applet parameters are interpreted by Orbit.java. Positions are three dimensional points (Point.java). The view is determined by a camera (Eye.java) that converts 3d model points into 3d points centered on the camera, then Eye.mapx, Eye.mapy convert those to the 2d points on the screen. Moon.java describes a moon and has routines for single-moon calculations. Simulate.java, specifically Simulate.move(), manages taking all the steps between display points.

I use an explicit symmetric multistep method for finding the next positions (Moon.step()). This has several odd consequences:

- The next position depends on the previous Moon.POINTS positions, not just the previous position. (That implies Moon.POINTS positions must be found by some other method before the multistep method can be used. See Simulate.getGoing(), described below.)
- Each of those Moon.POINTS positions has accumulated a different
error. Every Moon.POINTS position has about the same error. When
these errors get big, the moons appear to jitter in their orbits. I
call this problem
*jitter*. The program dynamically detects and dejitterizes jittery orbits (Simulate.dejitter(), Moon.dejitter()). - Velocities aren't computed or stored. Multistep methods use differences in previous positions instead of velocities. Thus Moon.velocity() for estimating the velocity from positions when we need it.

Since the multistep method needs Moon.degree previous positions,
Simulate.getGoing() uses a different method to find the first few
positions. First it uses the Verlet leapfrog method to make
Moon.POINTS steps 2^{-32}th the final size. Next it fills
Moon.history steps using the multistep method. Then it takes every
other position, doubles the stepsize, and generates Moon.history more
positions. This is repeated 32 times, bringing the time increment up
to the intended size.

Total energy is supposed to be conserved. Any gain or loss of
energy corresponds to errors in the integration
(Simulate.FindEnergy()). Total energy is kinetic+potential.
Potential energy is -mass/||distance||. That is always larger than
kinetic (mass*velocity^{2}/2) unless some objects have escape
velocity. Although Simulate.FindEnergy() could use the distances
between moons calculated in Simulate.accel(), accel() is called much
more often, so it turned out to be faster to have accel() simple and
FindEnergy() as a separate routine.

The routine Moon.dejitter() removes the jitter from a moon's path. It uses BInterpolate.java to build the interpolating polynomial, which in turn uses BMatrix and BVector to do the necessary linear algebra. Dejittering is done by finding the interpolating polynomial for the accelerations, integrating twice, and rederiving the positions. Velocity is found using two points known to have the same jitter error.

Itzu, or Crabs In Space

Why there are no perpetual
motion machines

Cryptographic Protocols

Table of Contents