Main content

## Computer programming - JavaScript and the web

### Course: Computer programming - JavaScript and the web > Unit 5

Lesson 7: Oscillations- Oscillation amplitude and period
- Challenge: Rainbow slinky
- Oscillation with angular velocity
- Challenge: Spaceship ride
- Waves
- Challenge: Many waves
- Trig and forces: the pendulum
- Challenge: Pendulum puppet
- Spring forces
- Project: Curling, crawling, circling creatures

© 2023 Khan AcademyTerms of usePrivacy PolicyCookie Notice

# Oscillation amplitude and period

Are you amazed yet? In the angular motion section, we saw some pretty great uses of tangent (for finding the angle of a vector) and sine and cosine (for converting from polar to Cartesian coordinates). We could stop right here and be satisfied. But we’re not going to. This is only the beginning. What sine and cosine can do for you goes beyond mathematical formulas and right triangles.

Let’s take a look at a graph of the sine function, where

*y = sine(x)*You’ll notice that the output of the sine function is a smooth curve alternating between –1 and 1. This type of a behavior is known as

**, a periodic movement between two points. Plucking a guitar string, swinging a pendulum, bouncing on a pogo stick—these are all examples of oscillating motion.***oscillation*And so we happily discover that we can simulate oscillation in a ProcessingJS program by assigning the output of the sine function to an object’s location. Note that this will follow the same methodology we applied to Perlin noise in the noise section.

Let’s begin with a really basic scenario. We want a circle to oscillate from the left side to the right side of our canvas.

This is what is known as

**(or, to be fancier, “the periodic sinusoidal oscillation of an object”). It’s going to be a simple program to write, but before we get into the code, let’s familiarize ourselves with some of the terminology of oscillation (and waves).***simple harmonic motion*Simple harmonic motion can be expressed as any location (in our case, the

`x`

location) as a function of time, with the following two elements:: The distance from the center of motion to either extreme*Amplitude*: The amount of time it takes for one complete cycle of motion*Period*

Looking at the graph of sine embedded above, we can see that the amplitude is 1 and the period is

`TWO_PI`

; the output of sine never rises above 1 or below -1; and every `TWO_PI`

radians (or 360 degrees) the wave pattern repeats.Now, in the ProcessingJS world we live in, what is amplitude and what is period? Amplitude can be measured rather easily in pixels. In the case of a window 200 pixels wide, we would oscillate from the center 100 pixels to the right and 100 pixels to the left. Therefore:

```
// Our amplitude measured in pixels
var amplitude = 100;
```

Period is the amount of time it takes for one cycle, but what is time in our ProcessingJS world? I mean, certainly we could say we want the circle to oscillate every three seconds. And we could track the milliseconds elapsed in our program (using

`millis()`

) and come up with an elaborate algorithm for oscillating an object according to real-world time.We have another option, however: we can use the fact that ProcessingJS programs have a notion of "frames", and that by default, a program attempts to run 30 "frames per second." ProcessingJS gives us the

`frameCount`

variable to find out what frame we're currently on, and the `frameRate()`

function to change the preferred frames per second. 30 FPS is the default frame rate, as that's a good rate to produce a smooth animation to trick the human brain, but it can sometimes be helpful to slow down that frame rate, like when debugging.We can thus decide to base our period on number of frames elapsed, as we've seen its closely related to real world time- we can say that the oscillating motion should repeat every 30 frames, or 50 frames, or 1000 frames, etc.

```
// Our period is measured in frames (our unit of time for animation)
var period = 120;
```

Once we have the amplitude and period, it’s time to write a formula to calculate

`x`

as a function of time, which we will substitute the current frame count for.`var x = amplitude * sin(TWO_PI * frameCount / period);`

Let’s dissect the formula a bit more and try to understand each component. The first is probably the easiest. Whatever comes out of the sine function we multiply by amplitude. We know that sine will oscillate between -1 and 1. If we take that value and multiply it by amplitude then we’ll get the desired result: a value oscillating between -amplitude and amplitude. (Note: this is also a place where we could use ProcessingJS’s

`map()`

function to map the output of sine to a custom range.)Now, let’s look at what is inside the sine function:

**TWO_PI * frameCount / period**

What’s going on here? Let’s start with what we know. We know that sine will repeat every 2*PI radians—i.e. it will start at 0 and repeat at 2*PI, 4*PI, 6*PI, etc. If the period is 120 frames, then we want the oscillating motion to repeat when the

`frameCount`

is at 120 frames, 240 frames, 360 frames, etc. `frameCount`

is really the only variable; it starts at 0 and counts upward. Let’s take a look at what the formula yields with those values.frameCount | frameCount / period | TWO_PI * frameCount / period |
---|---|---|

0 | 0 | 0 |

60 | 0.5 | PI |

120 | 1 | TWO_PI |

240 | 2 | 2 * TWO_PI (or 4 * PI) |

etc. |

`frameCount`

divided by period tells us how many cycles we’ve completed—are we halfway through the first cycle? Have we completed two cycles? By multiplying that number by `TWO_PI`

, we get the result we want, since `TWO_PI`

is the number of radians required for one sine to complete one cycle.Wrapping this all up, here’s the program that oscillates the

`x`

position of a circle with an amplitude of 100 pixels and a period of 120 frames.It’s also worth mentioning the term

**: the number of cycles per time unit. Frequency is equal to 1 divided by period. If the period is 120 frames, then only 1/120th of a cycle is completed in one frame, and so frequency = 1/120 cycles/frame. In the above example, we simply chose to define the rate of oscillation in terms of period and therefore did not need a variable for frequency.***frequency*Note that we worked through all of that using the sine function (

`sin()`

in ProcessingJS), but the same ideas apply to using the cosine function. The period is the same for both, and the main difference is just whether the beginning amplitude starts at 1 or at 0.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?

- How does the map(y,-1,1,100,200) work?(2 votes)
- Imagine a line stretching from -1 to 1. There's a dot somewhere on that line, called "y".

The`map`

function stretches that line out like a rubber band so that it starts at 100 and ends at 200.

That means the point "y" moved as well. That's the value the`map`

function returns.(13 votes)

- Does anybody know why my buttons does not work on browser? Here on Khan academy everything is fine but when I wanted to put my proccessing js code on my own website, interaction with keyboard buttons does not work. Interaction with mouse work well.(5 votes)
- You'll need to load the Processing JS library into the HTML. There's a template for it here:

https://www.khanacademy.org/computer-programming/processingjs-inside-webpages-template/5157014494511104

Also, the version of Processing JS used on Khan Academy is slightly different, so you might want to review the "official" documentation on processingjs.org(6 votes)

- I'm sort of stuck on Step 1. Can anyone help? I'm a little confused. PLEASE RESPOND.(3 votes)
- The hint show three lines of code with three different colored boxes:
`var orange = sin(TWO_PI * frameCount / pink);`

var blue = map(...);

drawSlinky(width/2, 10, blue);

Working backwards, the blue box needs to be the Y coordinate that is the third parameter to`drawSlinky`

. So line 2 simply declares a variable to hold that blue value. How? By mapping the the value of the orange box in line one.

Since the value of the orange box is the results of the`sin`

function, it is guaranteed to be between -1 and +1.

The pink box in line one is a constant and a bizarre attempt to help you convert degrees to radians.(6 votes)

- what does the overlap variable actually do in the next challenge?(3 votes)
- The overlap variable is not a special JS command like draw, it could be named anything! How it's value is used is what counts here. When it is used to multiply "space" in the y value of the ellipse function, it causes the y positions to be drawn at .8 their original value, which means a little higher up the screen than normal, or multiplying it by 1. It is also used to define space by dividing endY by overlap. This just makes the slinky a little longer. If you remove overlap here, the slinky will shrinky.

The way the slinky actually bounces is by dynamically changing the width using the periodic sine function. As space is defined by passing in the endY argument, and the endY argument passed in is a sin function, the y position also dynamically changes with each period!(2 votes)

- OK I think that I am officially confused, I am trying to do the next challenge "Rainbow Slinky" and I got it to work, but I can't move on. I keep getting an error saying "Use the sin() function to calculate the y position of the bottom of the slinky, and map() to convert it to a reasonable value." Is there something wrong with my code?

angleMode = "radians";

var period = 120;

var amplitude = 100;

var drawSlinky = function(centerX, startY, endY) {

noFill();

colorMode(HSB);

strokeWeight(2);

ellipseMode(CENTER);

var overlap = 0.8;

var space = (endY/overlap - startY)/30;

for (var i = 0; i < 30; i++) {

stroke(i*9, 200, 255);

ellipse(centerX, i*space*overlap + startY, 60, space);

}

};

draw = function() {

background(255);

var x = amplitude * sin(TWO_PI * frameCount / period);

var y = map(x, -1, 1, 100, 105);

drawSlinky(width/2, 10, y);

};(2 votes)- What values will your x have?

What values for x is the map function call presuming to be used?(2 votes)

- Are their examples of oscillating motion correct? With the guitar pick ("plucking") and pogo stick examples it seems they are conflating oscillating motion - back and forth swinging around a point - with reciprocating motion - back and forth movement along a line.

(I imagine a plucked guitar string might show something like oscillating motion but most of the motion would be reciprocating.)(3 votes)- hello I'm a programmer who want inspiration for coding so if you have any ideas please share them with me thank you.(0 votes)

- How can I calculate the maximum range of an oscillation? Most webpages talk about the calculation of the amplitude but I have not been able to find the steps on calculating the maximum range of a wave that is irregular.(2 votes)
- Please look out my code and tell me what is wrong with it and where. It's saying 'Think about the output of the sin() function, and what you pass as the start and end of the original range for map()'.

CODE:

angleMode = "radians";

var drawSlinky = function(centerX, startY, endY) {

noFill();

colorMode(HSB);

strokeWeight(2);

ellipseMode(CENTER);

var overlap = 0.8;

var space = (endY/overlap - startY)/30;

for (var i = 0; i < 30; i++) {

stroke(i*9, 200, 255);

ellipse(centerX, i*space*overlap + startY, 60, space);

}

};

draw = function() {

background(255);

var a = sin(TWO_PI * frameCount /2 );

var b = map(0, 0, 0, 0, 20);

drawSlinky(width/2, 10, b);

};

Thanks.(1 vote)

Seems like a long winded way to assign a NaN to`var b = map(0, 0, 0, 0, 20);`

`b`

.

Do you know the*range*of the sine function?(2 votes)

- I don't really understand the
`TWO_PI`

. Can someone explain a bit better?(1 vote)- TWO_PI is 2*PI. The angle measure is a complete circle is two pi radians (or 360°). The value is also referred to as "tau" or τ.(2 votes)

- Why do they change the angle mode and translate the canvas?(1 vote)
- As they state at the end of the tutorial, it is derived from sources outside of Khan Academy.

The rest of the world (indeed, the universe, nature, your god(s)) use radians as angle measures. Only Khan Academy supports degrees and the ill-architected`angleMode`

. So to readily port the outside code, they need to use radians, ...naturally...

The translation moves the origin to the center of the canvas, something our Algebra teachers would approve of...(2 votes)