FourierSeries

Learning Maths using simulations made with Javascript

Posted on Posted in Blogs, Technology




A few days ago I saw a video on SmarterEveryday, a youtube channel which makes science related videos. That video illustrates how we can understand Fourier Series with the help of animations of sinusoidal waves. The original creator made the animations using a different software/language. But I thought I can make it in javascript and run it on a browser, and host it in my website. Then a couple of days later I saw a video on TheCodingTrain, where Daniel Shiffman did the exact animation using a javascript library called p5.js

Although it was fun to watch, I wanted to do it in plain javascript, without using any third party libraries. I used the basic algorithm Daniel used, but didn’t use his library. In terms of lines of code, it wasn’t a lot of extra code. But the animation was smoother using the p5.js library. Anyway, lets look at how this animation can be done.

The link to my animation is: https://sudipta-pran.github.io/index.html

First of all lets talk about html5 canvas. The canvas element is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. The scripting is done with javascript, with which we can draw shapes and move them around. The trick with movement is achieved because the browser refreshes itself at a certain frequency and renders the html again and again. If we change the position of an element slightly everytime the browser refreshes, we can see a smooth movement of the element.

This type of animation can even be achieved using just CSS, without any canvas. Lets look at this example.

HTML:
<div class="box-container">
<div class="box"></div>
</div>   

CSS:

.box-container{
width:100%;
height:200px;
}
.box{
width:100px;
height:100px;
background-color: #DC143C;
position: relative;
animation: myroll 3s ;
animation-iteration-count: infinite;
-webkit-animation: myroll 3s ;
-webkit-animation-iteration-count: infinite;
}
@keyframes myroll {
0% {left:0;}
50% {left:50%;}
100% {left:0}
}
@-webkit-keyframes myroll {
0% {left:0;}
50% {left:50%;}
100% {left:0}
}

But using canvas and javascript gives us a lot of options to do things. We can make games like pong, snakes and even super mario!!! The trick is to simulate physics using equations of motion. For example to simulate gravity, we give the falling body a certain acceleration with time in the downward direction. To move a body with time, we add a number of pixels to the position of the body on every screen refresh. This is called velocity. Say a box is at position 100px from left of screen. At every screen refresh we add 5px to its position. So its velocity is 5. This lets us observe a movement of the body in the x-direction.

As acceleration is velocity divided by time, we can multiple the velocity with delta time, which is the time between rendering two frames. Javascript web-API offers a function called requestAnimationFrame that recursively calls a callback function at each refresh, which can be used to calculate delta time and do all the animation logic. Thus we can simulate gravity and all other physical phenomenon.

But let us keep it simple for now, and look at sinusoidal wave and how the locus of a point on the circumference of a circle generates a sinusoidal wave.

HTML:

<div id=”first”>
<canvasid=”sinusoidal”width=”700″height=”400″></canvas>
</div>

JS:


const sineCanvas = document.getElementById("sinusoidal")
sineCanvas.width = 700
sineCanvas.height = 400
const sineContext = sineCanvas.getContext('2d')
let angle = 0
let wave = []


function sineUpdate(){
sineContext.clearRect(0, 0, sineCanvas.width, sineCanvas.height)
sineContext.fillStyle = "#000000"
sineContext.fillRect(0, 0, sineCanvas.width, sineCanvas.height)
let x = 180
let y = 200
sineContext.strokeStyle = "#ffffff"
let radius = 75
x += radius * Math.cos(angle)
y += radius * Math.sin(angle)
sineContext.beginPath()
sineContext.arc(180, 200, radius, 0, 2 * Math.PI)
sineContext.stroke()
sineContext.beginPath()
sineContext.moveTo(x, y)
sineContext.lineTo(180, 200)
sineContext.stroke()
wave.unshift(y)
sineContext.beginPath()
sineContext.moveTo(x, y)
sineContext.lineTo(380, wave[0])
sineContext.stroke()
sineContext.fillStyle = "#ffffff"
for(let i = 0; i < wave.length; i++){ sineContext.fillRect(380 + i, wave[i], 2, 2) } if(wave.length > 300){
wave.pop()
}
angle -= 0.05
window.requestAnimationFrame(sineUpdate)
}
sineUpdate()

In the above code, first we initialize a canvas variable(sineCanvas) by selecting the DOM element with id “sinusoidal”, which is an HTML5 canvas. We set the width and height and a context object(sineContext) on it. The context object has a lot of function on it, to draw different shapes on the canvas. We declare the angle variable which increases with time, so that we can plot the locus of a point on the circumference. The method to find the x,y co-ordinate of this point at any given time is to convert from polar to cartesian co-ordinate system. The formula is:

{x = r cosθ}
{y = r sinθ}

The sineUpdate function is called recursively by the webAPI requestAnimationFrame which calls the callback function everytime the screen refreshes. We increase the angle slightly on each iteration and calculate the x,y co-ordinate of the point on the circumference. Then we push the y co-ordinate into an array wave with the unshift function, so that values are pushed to the beginning of the array. This is done so that we can plot the sinusoidal graph at 380px from the left of the canvas. At every iteration of the sineUpdate function, we plot all the points of the wave array. This might be harmful for performance, so we remove the last value from wave everytime it reaches 300th value.

We join the point on the circle and the first value (latest value) in wave with a straight line. The rest of the code is mainly syntax how to draw shapes on a canvas.

fourier series
Fourier series formula on wikipedia

To demonstrate Fourier series, we need to add more sine waves, i.e. more circles. But these waves have a certain relationship which should be followed to create a certain wave shape. Let us take the example of a square wave generated by adding harmonics of a sine wave. The amplitude of each harmonic is added at any instant. So in our circle, the locus of the original point becomes the center of the next harmonic. The same angle is made at any instant of time, i.e. these harmonics are in phase. So we get another point on the circumference of this new circle, which is the center of the next harmonic and so on. The y co-ordinate of point on the circumference of the last circle, gives the amplitude of the desired wave, so we push that to the wave array, and plot it. With a large number of harmonics, we can get a smooth square wave.

HTML:

<div id=”second”>
<canvasid=”squareWave”width=”700″height=”400″></canvas>
</div>

JS:


const canvas = document.getElementById("squareWave")
canvas.width = 700
canvas.height = 400
const context = canvas.getContext('2d')
let angle = 0
let wave = []
function update(){
context.clearRect(0, 0, canvas.width, canvas.height)
context.fillStyle = "#000000"
context.fillRect(0, 0, canvas.width, canvas.height)
let x = 180
let y = 200
context.strokeStyle = "#ffffff"
for(let i = 0; i < 5; i++)

{
let prevx = x
let prevy = y
let n = 2*i + 1
let radius = 75 * (4/(n * Math.PI))
x += radius * Math.cos(n * angle)
y += radius * Math.sin(n * angle)
context.beginPath()
context.arc(prevx, prevy, radius, 0, 2 * Math.PI)
context.stroke()
context.beginPath()
context.moveTo(x, y)
context.lineTo(prevx, prevy)
context.stroke()
}

wave.unshift(y)
context.beginPath()
context.moveTo(x, y)
context.lineTo(380, wave[0])
context.stroke()
context.fillStyle = "#ffffff"
for(let i = 0; i < wave.length; i++)

{ context.fillRect(380 + i, wave[i], 2, 2) }

if(wave.length > 300){
wave.pop()
}
angle -= 0.05
window.requestAnimationFrame(update)
}
update()

Inside the first for loop of the update function, we create 5 circles using the square-wave Fourier series formula from wikipedia. We keep a track of the center of each circle in each iteration with the variables prevx and prevy. The co-ordinate of the point on the circumference of the previous circle is set as prevx and prevy at the end of each for loop iteration. The y co-ordinate of the point on the last circle’s circumference is pushed to the wave array and then we draw the curve. This time the curve loops like a square wave.

We can similarly implement the sawtooth wave, using the second formula from wikipedia.

HTML5 canvas can be used to make incredible animations. This blog is not a standard resource to learn canvas, but there are tons of resources. Learning javascript with small animation projects will further increase your interest and programming skill in general.

If you want to have more fun with html5 canvas, check out this snake game made on canvas with plain javascript.





If you liked this article please comment and show your support and interest so that I’ll be motivated to continue this effort. Like our facebook page if you haven’t already. And if you have any questions please comment. I’ll try to reply all.

Comments

comments