Two-Particle Oscillator

At the end of class, on Monday, Feb. 7, we developed the code below. It illustrates:

Also below are two versions of the same model using our BVector class and Processing’s PVector class.

Implementation

// A nice simple two-particle oscillator.
// The two particles move horizontally and are
// connected by a spring.

final float DELTA_T = 0.05;

float x1;
float x2;
float y1; // this will just be a constant
float y2; // also a constant -- motion is horizontal

float v1x; // we don't need v1y -- motion is horizontal
float v2x; // we don't need v2y for same reason

final float m1 = 1;
final float m2 = 4;

void setup() {
  size(600, 400);
  x1 = width / 3; // start 1/3 of the way across
  x2 = 2 * width / 3; // start 2/3 of the way across
  y1 = height / 2.0;
  y2 = height / 2.0;
  background(0);
}

void draw() {
  background(0);
  // The first thing we need is the force of the spring.
  // It depends on how much the spring is stretched.
  // 150 is the resting length of the spring, when 
  // it is neither stretched nor compressed. The next line
  // is known as Hooke's Law. It is an idealization. If you
  // stretch or compress a spring too far, it will no longer
  // obey Hooke's Law.
  float f1x = (x2 - x1 - 150);
  // Newton's 3rd Law applied to our two-particle system:
  float f2x = -f1x;
  // Newton's 2nd Law applied to get the acceleration of each particle:
  float a1x = f1x / m1;
  float a2x = f2x / m2;
  // Now the usual update formulas:
  x1 += v1x * DELTA_T;
  x2 += v2x * DELTA_T;
  v1x += a1x * DELTA_T;
  v2x += a2x * DELTA_T;
  // Draw the particles
  ellipseMode(CENTER);
  stroke(255);
  fill(255);
  ellipse(x1, y1, 5, 5);
  // Draw the heavier one bigger
  ellipse(x2, y2, 10, 10);
}

Implementation with BVector

// Vector version of our two-particle oscillator
// using our BVector class.

final float DELTA_T = 0.05;

class BVector {

  float over;
  float down;

  BVector(float over, float down) {
    this.over = over;
    this.down = down;
  }

  void addWithScale(float scale, BVector otherVector) {
    this.over += scale * otherVector.over;
    this.down += scale * otherVector.down;
  }

}

BVector position1; // the y component will just be height/2
BVector position2; // the y component will just be height/2

BVector velocity1;
BVector velocity2;

final float m1 = 1;
final float m2 = 4; // particle 2 is four times as heavy as particle 1

void setup() {
  size(600, 400);
  position1 = new BVector(width/3.0, height/2.0);
  position2 = new BVector(2.0*width/3.0, height/2.0);
  velocity1 = new BVector(0.0, 0.0);
  velocity2 = new BVector(0.0, 0.0);
  background(0);
}

void draw() {
  background(0);
  // The first thing we need is the force of the spring.
  // It depends on how much the spring is stretched.
  // 150 is the resting length of the spring, when 
  // it is neither stretched nor compressed. The next line
  // is known as Hooke's Law. It is an idealization. If you
  // stretch or compress a spring too far, it will no longer
  // obey Hooke's Law.
  float f1x = (position2.over - position1.over - 150);
  // Newton's 3rd Law applied to our two-particle system:
  float f2x = -f1x;
  // Newton's 2nd Law applied to get the acceleration of each particle:
  float a1x = f1x / m1;
  float a2x = f2x / m2;
  // Put the accelerations into vectors
  BVector acceleration1 = new BVector(a1x, 0.0);
  BVector acceleration2 = new BVector(a2x, 0.0);
  // Now the usual update formulas:
  position1.addWithScale(DELTA_T, velocity1);
  position2.addWithScale(DELTA_T, velocity2);
  velocity1.addWithScale(DELTA_T, acceleration1);
  velocity2.addWithScale(DELTA_T, acceleration2);
  // Draw the particles
  ellipseMode(CENTER);
  stroke(255);
  fill(255);
  ellipse(position1.over, position1.down, 5, 5);
  // Draw the heavier one bigger
  ellipse(position2.over, position2.down, 10, 10);
}

Implementation with PVector

// Vector version of our two-particle oscillator
// using Processing's PVector class.

final float DELTA_T = 0.05;

PVector position1; // the y component will just be height/2
PVector position2; // the y component will just be height/2

PVector velocity1;
PVector velocity2;

final float m1 = 1;
final float m2 = 4; // particle 2 is four times as heavy as particle 1

void setup() {
  size(600, 400);
  position1 = new PVector(width/3.0, height/2.0);
  position2 = new PVector(2.0*width/3.0, height/2.0);
  velocity1 = new PVector();
  velocity2 = new PVector();
  background(0);
}

void draw() {
  background(0);
  // The first thing we need is the force of the spring.
  // It depends on how much the spring is stretched.
  // 150 is the resting length of the spring, when 
  // it is neither stretched nor compressed. The next line
  // is known as Hooke's Law. It is an idealization. If you
  // stretch or compress a spring too far, it will no longer
  // obey Hooke's Law.
  float f1x = (position2.x - position1.x - 150);
  // Newton's 3rd Law applied to our two-particle system:
  float f2x = -f1x;
  // Newton's 2nd Law applied to get the acceleration of each particle:
  float a1x = f1x / m1;
  float a2x = f2x / m2;
  // Put the accelerations into vectors
  PVector acceleration1 = new PVector(a1x, 0.0);
  PVector acceleration2 = new PVector(a2x, 0.0);
  // Now the usual update formulas, which are a little clumsier without
  // the pleasantly convenient addWithScale method we had in BVector.
  PVector a1dt = PVector.mult(acceleration1, DELTA_T);
  PVector a2dt = PVector.mult(acceleration2, DELTA_T);
  PVector v1dt = PVector.mult(velocity1, DELTA_T);
  PVector v2dt = PVector.mult(velocity2, DELTA_T);
  position1.add(v1dt);
  position2.add(v2dt);
  velocity1.add(a1dt);
  velocity2.add(a2dt);
  // Draw the particles
  ellipseMode(CENTER);
  stroke(255);
  fill(255);
  ellipse(position1.x, position1.y, 5, 5);
  // Draw the heavier one bigger
  ellipse(position2.x, position2.y, 10, 10);
}