If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Main content

Oscillation with angular velocity

An understanding of the concepts of oscillation, amplitude, and frequency/period is often required in the course of simulating real-world behaviors. However, there is a slightly easier way to rewrite the above example with the same result. Let’s take one more look at our oscillation formula:
var x = amplitude * sin(TWO_PI * frameCount / period);
And let’s rewrite it a slightly different way:
var x = amplitude * sin(some value that increments slowly);
If we care about precisely defining the period of oscillation in terms of frames of animation, we might need the formula the way we first wrote it, but we can just as easily rewrite our example using the concept of angular velocity (and acceleration) from the Angular Motion lesson. Assuming:
var angle = 0;
var aVelocity = 0.03;
...in draw(), we can simply say:
angle += aVelocity;
var x = amplitude * sin(angle);
...where angle is our “some value that increments slowly.”
Here's our modified program: 
Just because we’re not referencing it directly doesn’t mean that we’ve eliminated the concept of period. After all, the greater the angular velocity, the faster the circle will oscillate (therefore lowering the period). In fact, the number of times it takes to add up the angular velocity to get to TWO_PI is the period or:
period = TWO_PI / angular velocity
Let’s expand this example a bit more and create an Oscillator object. And let’s assume we want the oscillation to happen along both the x-axis (as above) and the y-axis. To do this, we’ll need two angles, two angular velocities, and two amplitudes (one for each axis). Another perfect opportunity for PVector!
Read through the code in the program below: 

This "Natural Simulations" course is a derivative of "The Nature of Code" by Daniel Shiffman, used under a Creative Commons Attribution-NonCommercial 3.0 Unported License.

Want to join the conversation?

  • male robot hal style avatar for user Ron Jensen
    The third step of "Challenge: Spaceship ride" says:
    "Spin the ships!
    Okay, now let's really give them a ride - calculate the angular acceleration based on how far away each ship is from the center, and rotate just the ship based on that. That means that your ship will need to keep track of its angular velocity and current angle, and each call to oscillate() will add to those values based on the angular acceleration that you calculate."

    Can I get a bigger hint about what that angular acceleration formula is supposed to look like?
    (6 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user JamesC64STR
    Here's a code dump for final code:
    angleMode = "radians";

    var Spaceship = function() {
    this.angle = new PVector();
    this.velocity = new PVector(random(-0.02, 0.02), random(-0.02, 0.02));
    this.amplitude = new PVector(random(20, width/2), random(20, width/2));
    this.position = new PVector(0, 0);
    this.aAngle = 0;
    this.aVelocity = 0;

    };

    Spaceship.prototype.oscillate = function() {
    this.angle.add(this.velocity);
    this.position.set(
    sin(this.angle.x) * this.amplitude.x,
    sin(this.angle.y) * this.amplitude.y);
    var s = dist(this.position.x, this.position.y, 0, 0);

    this.aAngle += s /10000;
    this.aAngle = constrain(this.aAngle, -0.1, 0.1);
    this.aVelocity += this.aAngle;



    };

    Spaceship.prototype.display = function() {
    pushMatrix();
    translate(width/2, height/2);
    stroke(181, 63, 0);
    strokeWeight(9);
    line(0, 0, this.position.x, this.position.y);
    translate(this.position.x, this.position.y);
    imageMode(CENTER);

    rotate(this.aVelocity);
    image(getImage("space/octopus"),
    0, 0,
    80, 100);
    popMatrix();
    };

    var ships = [];
    for (var i = 0; i < 10; i++) {
    ships.push(new Spaceship());
    }

    draw = function() {
    background(174, 218, 232);
    for (var i = 0; i < ships.length; i++) {
    ships[i].oscillate();
    ships[i].display();
    }
    };

    //Note that my aAngle, and aVelocity might be mixed around or not, I got kindve confused on this one. but I hope I can help people pass the constrain part.
    (10 votes)
    Default Khan Academy avatar avatar for user
  • duskpin tree style avatar for user oh_hello_there
    On Step 3 of the next challenge, where do you put the constrain function? Here is my code so far:


    angleMode = "radians";

    var Spaceship = function() {
    this.angle = new PVector();
    this.velocity = new PVector(random(-0.02, 0.22), random(-0.04, 0.13));
    this.amplitude = new PVector(random(20, width/2), random(20, width/2));
    this.position = new PVector(0, 0);
    this.aAccel = 0;
    this.aVel = 0;
    };

    Spaceship.prototype.oscillate = function() {
    this.angle.add(this.velocity);
    this.position.set(
    sin(this.angle.x) * this.amplitude.x,
    sin(this.angle.y) * this.amplitude.y
    );
    // Calculate the angular acceleration, based on distance
    var acceleration = dist(this.position.x, this.position.y, 0, 0);
    var acceleration = constrain(this.aVel, 0.5, 1.5);
    // Add it to your angVelocity property, scalling it
    // to a realistic amount
    this.aAccel += acceleration / 10000;
    this.aVel += this.aAccel;
    };

    Spaceship.prototype.display = function() {
    pushMatrix();
    translate(width/2, height/2);
    stroke(181, 63, 0);
    strokeWeight(9);
    line(0, 0, this.position.x, this.position.y);
    imageMode(CENTER);
    translate(this.position.x, this.position.y);
    rotate(this.aVel);
    image(getImage("space/octopus"),
    0, 0, 80, 100);
    popMatrix();

    };

    var ships = [];
    for (var i = 0; i < 10; i++) {
    ships.push(new Spaceship());
    }

    draw = function() {
    background(174, 218, 232);
    for (var i = 0; i < ships.length; i++) {
    ships[i].oscillate();
    ships[i].display();
    }
    };
    (10 votes)
    Default Khan Academy avatar avatar for user
  • male robot johnny style avatar for user techmasterau
    Why does KA get us to do challenges yet they haven't taught us how to do it yet?
    (7 votes)
    Default Khan Academy avatar avatar for user
  • aqualine seed style avatar for user K B
    In the step 3 of next challenge, I didn't get why it should be dist(this.position.x, this.position.y, 0, 0) instead of dist(this.position.x, this.position.y, width/2, height/2) as distance should be measured from the center?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • leaf red style avatar for user Grant Auleciems
    I've always wondered this but never got the answer: What in programs is " this. " ?
    Like for example: this.angle
    (2 votes)
    Default Khan Academy avatar avatar for user
  • aqualine tree style avatar for user SavannahRW01
    The "Challenge: Spaceship Ride" has me stumped. My code lets the ships rotate, but the grader won't let me pass. I've seen lots of people say, "Use dist(this.position.x, this.position.y, 0, 0)/10000;" but if I do that, the orange words say, "Can you divide it by a bigger number to make it more realistic?" and won't go away until I change the second 0 in dist(); to a 1. Adding "/10000" makes no difference. Here's my code:


    angleMode = "radians";

    var Spaceship = function() {
    this.angle = new PVector();
    this.velocity = new PVector(random(-0.02, 0.22), random(-0.04, 0.13));
    this.amplitude = new PVector(random(20, width/2), random(20, width/2));
    this.position = new PVector(0, 0);
    this.ro = 0;
    this.rot = 0;
    };

    Spaceship.prototype.oscillate = function() {
    this.angle.add(this.velocity);
    this.position.set(
    sin(this.angle.x) * this.amplitude.x,
    sin(this.angle.y) * this.amplitude.y);
    // Calculate the angular acceleration, based on distance
    var acceleration = dist(this.position.x, this.position.y, 1, 0);
    // Add it to your angVelocity property, scalling it
    // to a realistic amount
    this.ro += acceleration / 3;
    this.rot += this.ro;
    };

    Spaceship.prototype.display = function() {
    pushMatrix();
    translate(width/2, height/2);
    stroke(181, 63, 0);
    strokeWeight(9);
    line(0, 0, this.position.x, this.position.y);
    imageMode(CENTER);
    translate(this.position.x, this.position.y);
    //(I placed "this.rot" inside rotate();--before, there was "PI")
    rotate(this.rot);
    image(getImage("space/octopus"),
    0, 0, 80, 100);

    popMatrix();

    };

    var ships = [];
    for (var i = 0; i < 10; i++) {
    ships.push(new Spaceship());
    }

    draw = function() {
    background(174, 218, 232);
    for (var i = 0; i < ships.length; i++) {
    ships[i].oscillate();
    ships[i].display();
    }
    };
    (4 votes)
    Default Khan Academy avatar avatar for user
  • old spice man green style avatar for user Elijah Daniels
    I noticed in the above code this line
    this.angle = new PVector();
    What does not adding any parameters to PVector do?
    (3 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user manzurtipu
    For some reason, in the spaceship ride challenge 'constraining' the angular acceleration [dist(this.position.x,this.position.y,0,0)/10000 worked, as opposed to 'constraining' the angular velocity. Am I missing something? Is anyone feeling the same?
    (3 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user Giao Nguyen
    I finished the Spaceship ride challenge, and it says that I have completed all 3 steps. But nothing appears on the screen. Help! Here is my code;

    angleMode = "radians";

    var Spaceship = function() {
    this.angle = new PVector();
    this.velocity = new PVector(random(-0.1, 0.6), random(-0.06, 0.05));
    this.amplitude = new PVector(random(20, width/2), random(20, width/2));
    this.position = new PVector(0, 0);
    this.vel = 0;
    this.angl = 0;
    };

    Spaceship.prototype.oscillate = function() {
    pushMatrix();
    translate(width/2,height/2);
    var acceleration = dist(0,0,this.position.x,this.position.y);
    this.vel +=acceleration/10000;
    this.vel = constrain(this.vel,0.02,0.06);
    this.angl += this.vel;

    this.angle.add(this.velocity);
    this.position.set(
    sin(this.angle.x) * this.amplitude.x,
    sin(this.angle.y) * this.amplitude.y);






    };

    Spaceship.prototype.display = function() {
    pushMatrix();
    translate(width/2, height/2);
    stroke(181, 63, 0);
    strokeWeight(9);
    line(0, 0, this.position.x, this.position.y);
    imageMode(CENTER);
    translate(this.position.x, this.position.y);
    rotate(this.angl);
    image(getImage("space/octopus"),
    0, 0,
    80, 100);
    popMatrix();
    };

    var ships = [];
    for (var i = 0; i < 10; i++) {
    ships.push(new Spaceship());
    }

    draw = function() {
    background(174, 218, 232);
    for (var i = 0; i < ships.length; i++) {
    ships[i].oscillate();
    ships[i].display();
    }
    };
    (2 votes)
    Default Khan Academy avatar avatar for user
    • blobby green style avatar for user Huong Duong
      Hi, I know it's been two years since you asked for help but I hope my answer will reach you.

      The problem with your code is that you have translated to the wrong position in the oscillate function. You just need to remove the two lines
      pushMatrix();
      translate(width/2,height/2);
      (1 vote)