Skip to content

Commit

Permalink
N Slit Diffraction
Browse files Browse the repository at this point in the history
  • Loading branch information
TheTrustyPwo committed Jun 27, 2024
1 parent 902c74e commit bf178ab
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 3 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ <h2>This is a website to teach you quantum physics!</h2>
<a href="sim3.html">Simulation 3 - 2D Wavefront (Aborted)</a> <br>
<a href="sim4.html">Simulation 4 - Ripple Single Slit Diffraction</a> <br>
<a href="sim5.html">Simulation 5 - Ripple Double Slit Diffraction</a> <br>
<a href="sim6.html">Simulation 6 - Ripple N Slit Diffraction</a> <br>
</body>
</html>
34 changes: 34 additions & 0 deletions sim6.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sim 6 - N Slit Interference Ripple Sim</title>
<style>
canvas {
background-color: black;
}
</style>
</head>
<body>
<canvas width="1000px" height="500px"></canvas>

<div class="slits">
<input type="range" min="1" max="20" step="1" value="3" class="slider" id="slitsInput">
Slits: <span id="slitsValue">3</span>
</div>
<div class="slitWidth">
<input type="range" min="200" max="1000" step="100" value="500" class="slider" id="slitWidthInput">
Slit Width: <span id="slitWidthValue">500</span> μm
</div>
<div class="slitSeparation">
<input type="range" min="20" max="100" step="10" value="50" class="slider" id="slitSeparationInput">
Slit Separation: <span id="slitSeparationValue">50</span> μm
</div>
<div class="wavelength">
<input type="range" min="380" max="780" step="10" value="500" class="slider" id="wavelengthInput">
Wavelength: <span id="wavelengthValue">500</span> nm
</div>

<script type="module" src="static/js/sim6.js"></script>
</body>
</html>
39 changes: 36 additions & 3 deletions static/js/shared/slit.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,47 @@ class DoubleSlit {
this.c.strokeStyle = SLITS.COLOR;
this.c.lineWidth = SLITS.WIDTH;
this.c.moveTo(this.x, this.y - this.h / 2);
this.c.lineTo(this.x, this.y - this.width / 2 - this.separation / 2);
this.c.lineTo(this.x, this.y - this.width - this.separation / 2);
this.c.moveTo(this.x, this.y - this.separation / 2);
this.c.lineTo(this.x, this.y + this.separation / 2);
this.c.moveTo(this.x, this.y + this.separation / 2 + this.width / 2);
this.c.moveTo(this.x, this.y + this.separation / 2 + this.width);
this.c.lineTo(this.x, this.y + this.h / 2);
this.c.closePath();
this.c.stroke();
}
}

export { Slit, DoubleSlit };
class NSlit {
constructor(cvs, c, x, y, h, width, separation, slits) {
this.cvs = cvs;
this.c = c;
this.x = x;
this.y = y;
this.h = h;
this.width = width;
this.separation = separation;
this.slits = slits;
}

draw = () => {
this.c.beginPath();
this.c.strokeStyle = SLITS.COLOR;
this.c.lineWidth = SLITS.WIDTH;
this.c.moveTo(this.x, this.y - this.h / 2);
let dist = this.y - (this.slits * this.width) / 2 - ((this.slits - 1) * this.separation) / 2;
this.c.lineTo(this.x, dist);
for (let i = 1; i <= this.slits; i++) {
dist += this.width;
this.c.moveTo(this.x, dist);
if (i < this.slits) {
dist += this.separation;
this.c.lineTo(this.x, dist);
}
}
this.c.lineTo(this.x, this.y + this.h / 2);
this.c.closePath();
this.c.stroke();
}
}

export { Slit, DoubleSlit, NSlit };
42 changes: 42 additions & 0 deletions static/js/sim6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { NSlitSimulation } from "./simulations/nSlit.js"

const fps = 60;

const cvs = document.querySelector('canvas');
const c = cvs.getContext('2d');
const slitsInput = document.getElementById("slitsInput");
const wavelengthInput = document.getElementById("wavelengthInput");
const slitWidthInput = document.getElementById("slitWidthInput");
const slitSeparationInput = document.getElementById("slitSeparationInput");

const simulation = new NSlitSimulation(cvs, c)
const animate = () => {
simulation.update();

setTimeout(() => {
requestAnimationFrame(animate);
}, 1000 / fps);
}

wavelengthInput.oninput = () => {
document.getElementById("wavelengthValue").innerText = wavelengthInput.value;
simulation.setWavelength(wavelengthInput.value / 1_000_000_000);
}

slitWidthInput.oninput = () => {
document.getElementById("slitWidthValue").innerText = slitWidthInput.value;
simulation.setSlitWidth(slitWidthInput.value / 1_000_000);
}

slitSeparationInput.oninput = () => {
document.getElementById("slitSeparationValue").innerText = slitSeparationInput.value;
simulation.setSlitSeparation(slitSeparationInput.value / 1_000_000);
}

slitsInput.oninput = () => {
document.getElementById("slitsValue").innerText = slitsInput.value;
simulation.setSlits(slitsInput.value);
}


animate()
143 changes: 143 additions & 0 deletions static/js/simulations/nSlit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {Simulation} from "./index.js";
import {Screen} from "../shared/screen.js";
import {interpolate, w2h} from "../utils/color.js";
import {distance} from "../utils/math.js";
import {DoubleSlit, NSlit, Slit} from "../shared/slit.js";

class NSlitSimulation extends Simulation {
constructor(cvs, c, wavelength = 500 / 1_000_000_000 , slitWidth = 500 / 1_000_000, slitSeparation = 50 / 1_000_000, slits = 3) {
super(cvs, c);
this.wavelength = wavelength;
this.screen = new Screen(cvs, c, 0.85 * cvs.width, cvs.height / 2, cvs.height - 50);
this.slit = new NSlit(cvs, c, 0.15 * cvs.width, cvs.height / 2, cvs.height - 50, slitWidth / this.ypx2m, slitSeparation / this.ypx2m, slits);

this.t = 0;
this.dt = 1 / 60;
this.cache = {};
this.redraw = true;
}

evaluate = (theta) => {
theta = Math.round(theta * 1_000_000) / 1_000_000;
if (theta in this.cache) return this.cache[theta];
let sine = Math.sin(theta);
let beta = Math.PI * this.slit.width * this.ypx2m * sine / this.wavelength;
let alpha = Math.PI * (this.slit.width + this.slit.separation) * this.ypx2m * sine / this.wavelength;
let tmp = Math.sin(beta) / beta * Math.sin(this.slit.slits * alpha) / Math.sin(alpha);
this.cache[theta] = tmp * tmp / this.slit.slits / this.slit.slits;
return this.cache[theta];
}

update = () => {
this.t += this.dt;

if (this.redraw) {
this.c.clearRect(0, 0, this.cvs.width, this.cvs.height);
this.screen.draw();
this.slit.draw();
this.plotIntensity();
this.redraw = false;
} else this.c.clearRect(this.slit.x + 2.5, 0, this.screen.x - this.slit.x - 5, this.cvs.height);


this.c.save();
this.displayMeasurements();
for (let x = 0; x < this.screen.x - 3; x += 5) {
for (let y = 0; y <= this.cvs.height; y += 5) {
this.c.globalAlpha = this.intensityAt(x, y);
this.c.fillStyle = this.colorAt(x, y);
this.c.fillRect(x, y, 3, 3);
}
}
this.c.restore();
}

plotIntensity = () => {
this.c.beginPath();
this.c.lineWidth = 3;
this.c.strokeStyle = this.color;
for (let y = 0; y <= this.cvs.height; y++) {
const theta = Math.atan2((y - this.slit.y) * this.ypx2m, (this.screen.x - this.slit.x) * this.xpx2m);
const intensity = this.evaluate(theta) * 100;
if (y === 0) this.c.moveTo(this.screen.x + 5 + intensity, y);
else this.c.lineTo(this.screen.x + 5 + intensity, y);
}
this.c.stroke();
}

displayMeasurements = () => {
this.c.save();
this.c.beginPath();
this.c.moveTo(this.slit.x, this.cvs.height * 0.9);
this.c.lineTo(this.screen.x, this.cvs.height * 0.9);
this.c.strokeStyle = "#179e7e";
this.c.stroke();
this.c.translate((this.slit.x + this.screen.x) / 2, this.cvs.height * 0.9 - 18);
this.c.font = "20px arial";
this.c.textAlign = "center";
this.c.fillStyle = "#179e7e";
const dist = Math.round((this.screen.x - this.slit.x) * this.xpx2m * 1000) / 10;
this.c.fillText(`${dist} cm`, 0, 10);
this.c.restore();
}

setWavelength = (wavelength) => {
this.wavelength = wavelength;
this.redraw = true;
this.cache = {};
}

setSlitWidth = (slitWidth) => {
this.slit.width = slitWidth / this.ypx2m;
this.redraw = true;
this.cache = {};
}

setSlitSeparation = (slitSeparation) => {
this.slit.separation = slitSeparation / this.ypx2m;
this.redraw = true;
this.cache = {};
}

setSlits = (slits) => {
this.slit.slits = slits;
this.redraw = true;
this.cache = {};
}

intensityAt = (x, y) => {
if (x < this.slit.x) return 1;
const theta = Math.atan2((y - this.slit.y) * this.ypx2m, (x - this.slit.x) * this.xpx2m);
return this.evaluate(theta);
}

colorAt = (x, y) => {
const dist = (x < this.slit.x ? x : distance(this.slit.x, this.slit.y, x , y));
const v = 2 * dist / (this.wavelength * 50000000) - 10 * this.t;
const factor = (1 + Math.cos(v)) / 2;
return interpolate("#000000", this.color, factor);
}

mouseDown = (event) => {};

mouseUp = (event) => {};

mouseMove = (event, x, y) => {
this.screen.x = Math.max(Math.min(x, this.screen.maxX), this.screen.minX);
this.redraw = true;
}

get xpx2m() {
return 2 / (this.screen.maxX - this.slit.x);
}

get ypx2m() {
return 1 / 1_000_00;
}

get color() {
return w2h(this.wavelength);
}
}

export { NSlitSimulation };

0 comments on commit bf178ab

Please sign in to comment.