From f0e1debd543f04059fdb47973e452fada9a88aa4 Mon Sep 17 00:00:00 2001 From: TheTrustyPwo Date: Sun, 12 May 2024 11:07:23 +0800 Subject: [PATCH] Update double slit sim --- sim5.html | 12 ++-- static/js/sim4.js | 2 +- static/js/sim5.js | 5 +- static/js/simulations/doubleSlit.js | 94 ++++++++++++++++++++++------- static/js/simulations/singleSlit.js | 2 +- 5 files changed, 82 insertions(+), 33 deletions(-) diff --git a/sim5.html b/sim5.html index b941d9d..30f1d05 100644 --- a/sim5.html +++ b/sim5.html @@ -13,16 +13,16 @@
- - Slit Width: 50 px + + Slit Width: 2.0 μm
- - Slit Separation: 100 px + + Slit Separation: 4.0 μm
- - Wavelength: 10 px + + Wavelength: 500 nm
diff --git a/static/js/sim4.js b/static/js/sim4.js index a46cdf3..962d7eb 100644 --- a/static/js/sim4.js +++ b/static/js/sim4.js @@ -7,7 +7,7 @@ const c = cvs.getContext('2d'); const wavelengthInput = document.getElementById("wavelengthInput"); const slitWidthInput = document.getElementById("slitWidthInput"); -const simulation = new SingleSlitSimulation(cvs, c, wavelengthInput.value, slitWidthInput.value * 1000); +const simulation = new SingleSlitSimulation(cvs, c); const animate = () => { simulation.update(); diff --git a/static/js/sim5.js b/static/js/sim5.js index 78c5cfa..f297525 100644 --- a/static/js/sim5.js +++ b/static/js/sim5.js @@ -10,7 +10,6 @@ const slitSeparationInput = document.getElementById("slitSeparationInput"); const simulation = new DoubleSlitSimulation(cvs, c) const animate = () => { - c.clearRect(0, 0, cvs.width, cvs.height); simulation.update(); setTimeout(() => { @@ -25,12 +24,12 @@ wavelengthInput.oninput = () => { slitWidthInput.oninput = () => { document.getElementById("slitWidthValue").innerText = slitWidthInput.value; - simulation.setSlitWidth(slitWidthInput.value); + simulation.setSlitWidth(slitWidthInput.value * 1000); } slitSeparationInput.oninput = () => { document.getElementById("slitSeparationValue").innerText = slitSeparationInput.value; - simulation.setSlitSeparation(slitSeparationInput.value); + simulation.setSlitSeparation(slitSeparationInput.value * 1000); } diff --git a/static/js/simulations/doubleSlit.js b/static/js/simulations/doubleSlit.js index 43e2317..1a530b3 100644 --- a/static/js/simulations/doubleSlit.js +++ b/static/js/simulations/doubleSlit.js @@ -1,48 +1,51 @@ import {Simulation} from "./index.js"; import {Screen} from "../shared/screen.js"; -import {interpolate} from "../utils/color.js"; +import {interpolate, w2h} from "../utils/color.js"; import {distance} from "../utils/math.js"; import {DoubleSlit} from "../shared/slit.js"; class DoubleSlitSimulation extends Simulation { - constructor(cvs, c, wavelength = 20) { + constructor(cvs, c, wavelength = 500, slitWidth = 2000, slitSeparation = 4000) { 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 DoubleSlit(cvs, c, 0.15 * cvs.width, cvs.height / 2, cvs.height - 50, 50, 100); - - this.waveColor1 = "#ce2b15"; - this.waveColor2 = "#000000"; + this.slit = new DoubleSlit(cvs, c, 0.15 * cvs.width, cvs.height / 2, cvs.height - 50, slitWidth / this.ypx2nm, slitSeparation / this.ypx2nm); this.t = 0; this.dt = 1 / 60; - - this.cache = {} + this.cache = {}; + this.redraw = true; } evaluate = (theta) => { theta = Math.round(theta * 1000) / 1000; if (theta in this.cache) return this.cache[theta]; const sine = Math.sin(theta); - const cs = Math.cos(Math.PI * this.slit.separation * sine / this.wavelength); - const tmp = Math.sin(Math.PI * this.slit.width * sine / this.wavelength) / (Math.PI * this.slit.width * sine / this.wavelength); + const cs = Math.cos(Math.PI * this.slit.separation * this.ypx2nm * sine / this.wavelength); + const a = Math.PI * this.slit.width * this.ypx2nm * sine / this.wavelength + const tmp = Math.sin(a) / a; this.cache[theta] = cs * cs * tmp * tmp; return this.cache[theta]; } update = () => { this.t += this.dt; - this.screen.draw(); - this.slit.draw(); - this.plotIntensity(); + + 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(); - for (let x = this.slit.x; x <= this.screen.x - 10; x += 5) { + this.displayMeasurements(); + for (let x = 0; x < this.screen.x - 3; x += 5) { for (let y = 0; y <= this.cvs.height; y += 5) { - const theta = Math.atan2(y - this.slit.y, x - this.slit.x); - this.c.globalAlpha = Math.max(Math.min(1.5 * this.evaluate(theta), 1), 0.15); - const dist = distance(this.slit.x, this.slit.y, x, y); - this.c.fillStyle = interpolate(this.waveColor1, this.waveColor2, (1 + (Math.sin(dist / this.wavelength - 8 * this.t))) / 2); + this.c.globalAlpha = this.intensityAt(x, y); + this.c.fillStyle = this.colorAt(x, y); this.c.fillRect(x, y, 3, 3); } } @@ -51,10 +54,10 @@ class DoubleSlitSimulation extends Simulation { plotIntensity = () => { this.c.beginPath(); - this.c.strokeStyle = "#d94444"; 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.screen.x - this.slit.x); + const theta = Math.atan2((y - this.slit.y) * this.ypx2nm, (this.screen.x - this.slit.x) * this.xpx2nm); 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); @@ -62,27 +65,74 @@ class DoubleSlitSimulation extends Simulation { 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"; + this.c.fillText(`${(this.screen.x - this.slit.x) * this.xpx2nm} nm`, 0, 10); + this.c.restore(); + } + setWavelength = (wavelength) => { this.wavelength = wavelength; + this.redraw = true; this.cache = {}; } setSlitWidth = (slitWidth) => { - this.slit.width = slitWidth; + this.slit.width = slitWidth / this.ypx2nm; + this.redraw = true; this.cache = {}; } setSlitSeparation = (slitSeparation) => { - this.slit.separation = slitSeparation; + this.slit.separation = slitSeparation / this.ypx2nm; + this.redraw = true; this.cache = {}; } + intensityAt = (x, y) => { + if (x < this.slit.x) return 1; + const theta = Math.atan2((y - this.slit.y) * this.ypx2nm, (x - this.slit.x) * this.xpx2nm); + let intensity = this.evaluate(theta); + // Following line is unscientific, only for visual effects + if (Math.abs(theta) > Math.asin(this.wavelength / this.slit.width / this.ypx2nm)) intensity *= 3; + return intensity; + } + + colorAt = (x, y) => { + const dist = (x < this.slit.x ? x * this.xpx2nm : distance(this.slit.x * this.xpx2nm, this.slit.y * this.ypx2nm, x * this.xpx2nm, y * this.ypx2nm)); + const v = 2 * dist / this.wavelength - 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 xpx2nm() { + return 20; + } + + get ypx2nm() { + return 20; + } + + get color() { + return w2h(this.wavelength); } } diff --git a/static/js/simulations/singleSlit.js b/static/js/simulations/singleSlit.js index 8ae70f1..b0e0afa 100644 --- a/static/js/simulations/singleSlit.js +++ b/static/js/simulations/singleSlit.js @@ -5,7 +5,7 @@ import {distance} from "../utils/math.js"; import {Slit} from "../shared/slit.js"; class SingleSlitSimulation extends Simulation { - constructor(cvs, c, wavelength = 300, slitWidth = 50) { + constructor(cvs, c, wavelength = 500, slitWidth = 2000) { super(cvs, c); this.wavelength = wavelength; this.screen = new Screen(cvs, c, 0.85 * cvs.width, cvs.height / 2, cvs.height - 20);