Skip to content

Commit 5d407a1

Browse files
authored
Update nSlit.js
1 parent d549ad1 commit 5d407a1

File tree

1 file changed

+24
-68
lines changed

1 file changed

+24
-68
lines changed

src/javascript/simulations/nSlit.js

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Grating } from "../shared/slit.js";
22
import { i2h, interpolate, w2h } from "../utils/color.js";
33

4-
// ily please work
4+
// this is the very last attempt it will work
55

66
class GratingFFTSimulation {
77
constructor(cvs, ctx, density = 1000, wavelength = 500e-9, slitWidth = 2e-6, distanceToScreen = 2.0) {
@@ -133,52 +133,26 @@ class GratingFFTSimulation {
133133
return spec;
134134
}
135135

136-
// Calculate discrete diffraction orders using simplified approach
137-
// Peak width depends on number of slits and distance
138136
calculateDiffractionOrders() {
139-
const d = 1e-3 / this.density; // grating spacing in meters
140137
const orders = [];
141-
142-
// Fixed number of orders to always display
143138
const ordersToShow = [-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7];
144139

145140
for (const m of ordersToShow) {
146-
const sinTheta = m * this.wavelength / d;
147-
148-
// Even if sinTheta > 1 (physically impossible), we'll place it for visibility
149-
let theta;
150-
if (Math.abs(sinTheta) <= 1) {
151-
theta = Math.asin(sinTheta);
152-
} else {
153-
// Extrapolate beyond physical limits for visualization
154-
theta = Math.sign(sinTheta) * Math.PI / 2 * Math.min(Math.abs(sinTheta), 3);
155-
}
156-
157-
// Position on screen - scale to ensure visibility
158-
// Spacing depends on wavelength: longer wavelength = wider spacing
159-
// Using 500nm as baseline wavelength
160141
const wavelengthFactor = this.wavelength / 500e-9;
161-
const baseSpacing = 120 * wavelengthFactor; // spacing scales with wavelength
142+
const baseSpacing = 120 * Math.pow(wavelengthFactor, 0.5);
162143
const xPos = this.cvs.width/2 + m * baseSpacing * (this.distanceToScreen / 1.5);
163144

164-
// Calculate envelope intensity for this position - ALL orders touch envelope
165145
const centerX = this.cvs.width / 2;
166146
const dx = (xPos - centerX) / (this.cvs.width * 0.3);
167147
const envelopeIntensity = Math.exp(-dx * dx);
168148

169-
// All orders match envelope height
170-
const intensity = envelopeIntensity;
171-
172-
// Peak width depends on:
173-
// 1. Number of slits (more slits = narrower peaks) - increased sensitivity
174-
// 2. Distance (farther = wider peaks due to diffraction spreading) - increased sensitivity
175149
const effectiveSlits = this.illuminatedWidthPx / (1000 / this.density);
176-
const slitFactor = 50 / Math.sqrt(effectiveSlits); // Increased from 30 for more pronounced effect
177-
const distanceFactor = Math.pow(this.distanceToScreen / 1.0, 1.2); // Increased exponent and adjusted baseline for more visible change
178-
const peakWidth = Math.max(3, slitFactor * distanceFactor);
150+
const slitFactor = 20 / Math.sqrt(effectiveSlits);
151+
const distanceFactor = Math.pow(this.distanceToScreen / 1.0, 0.6);
152+
const peakWidth = Math.max(2, slitFactor * distanceFactor);
179153

180154
if (xPos >= -50 && xPos < this.cvs.width + 50) {
181-
orders.push({ order: m, x: xPos, intensity: intensity, width: peakWidth });
155+
orders.push({ order: m, x: xPos, intensity: envelopeIntensity, width: peakWidth });
182156
}
183157
}
184158

@@ -190,21 +164,15 @@ class GratingFFTSimulation {
190164
const screenIntensity = new Float32Array(this.cvs.width);
191165
screenIntensity.fill(0);
192166

193-
// Use discrete orders with simplified positioning
194167
this.diffractionOrders = this.calculateDiffractionOrders();
195168

196-
// Apply density effect: higher density = wider spacing
197-
const densityFactor = this.density / 700; // normalized to 700 lines/mm baseline
198-
199-
// Apply distance effect: farther = wider spacing (very subtle - only 10% range)
200-
// Scale from 1.0 to 2.0 meters -> factor from 0.95 to 1.05 (10% range)
201-
const distanceFactor = 0.95 + (this.distanceToScreen - 1.0) * 0.1;
169+
const densityFactor = Math.pow(this.density / 700, 0.5);
170+
const distanceFactor = 0.95 + (this.distanceToScreen - 1.0) * 0.05;
202171

203172
for (const order of this.diffractionOrders) {
204-
// Adjust position based on density and distance
205173
const adjustedX = this.cvs.width/2 + (order.x - this.cvs.width/2) * densityFactor * distanceFactor;
206174

207-
const width = order.width; // Use calculated width based on number of slits
175+
const width = order.width;
208176
for (let dx = -width*2; dx <= width*2; dx++) {
209177
const x = Math.round(adjustedX + dx);
210178
if (x >= 0 && x < this.cvs.width) {
@@ -214,13 +182,11 @@ class GratingFFTSimulation {
214182
}
215183
}
216184

217-
// Store adjusted positions for rendering
218185
this.diffractionOrders = this.diffractionOrders.map(order => ({
219186
...order,
220187
x: this.cvs.width/2 + (order.x - this.cvs.width/2) * densityFactor * distanceFactor
221188
}));
222189

223-
// normalize
224190
let max = 0;
225191
for (let i = 0; i < screenIntensity.length; i++) if (screenIntensity[i] > max) max = screenIntensity[i];
226192
if (max > 0) for (let i = 0; i < screenIntensity.length; i++) screenIntensity[i] /= max;
@@ -273,28 +239,21 @@ class GratingFFTSimulation {
273239
const centerX = this.cvs.width / 2;
274240
const normalizedX = (x - centerX) / envelopeWidth;
275241

276-
// Use sinc function to create proper zeros between lobes
277-
// sinc(x) = sin(πx)/(πx), and intensity is sinc²(x)
278-
const beta = normalizedX * 1.5; // Reduced from 1.8 to make lobes wider
242+
const beta = normalizedX * 1.8;
279243

280244
let sincValue;
281245
if (Math.abs(beta) < 0.001) {
282-
sincValue = 1; // Limit as beta approaches 0
246+
sincValue = 1;
283247
} else {
284248
sincValue = Math.sin(Math.PI * beta) / (Math.PI * beta);
285249
}
286250

287-
// Square the sinc to get intensity, and scale to get proper side lobe heights
288251
let intensity = sincValue * sincValue;
289252

290-
// Scale to make side lobes about 50% of main lobe
291-
// Natural sinc² gives ~4.5% for first side lobe, so we boost it
292253
if (Math.abs(beta) > 1.0 && Math.abs(beta) < 2.0) {
293-
// First side lobes
294-
intensity *= 11; // Boost to ~50%
254+
intensity *= 3;
295255
} else if (Math.abs(beta) >= 2.0 && Math.abs(beta) < 3.0) {
296-
// Second side lobes
297-
intensity *= 8; // Boost to ~35%
256+
intensity *= 2;
298257
}
299258

300259
return Math.max(0, intensity);
@@ -305,9 +264,9 @@ class GratingFFTSimulation {
305264
const envelopeIntensity = singleSlitEnvelope(order.x);
306265
return {
307266
x: order.x,
308-
height: envelopeIntensity * maxHeight * 0.98, // Scale to 98% to stay below envelope
267+
height: envelopeIntensity * maxHeight * 0.98,
309268
order: order.order,
310-
envelopeHeight: envelopeIntensity * maxHeight // Store full envelope height for comparison
269+
envelopeHeight: envelopeIntensity * maxHeight
311270
};
312271
});
313272

@@ -333,7 +292,7 @@ class GratingFFTSimulation {
333292
// Helper function to clamp y value to envelope
334293
const clampToEnvelope = (x, y) => {
335294
const envelopeY = screenY - singleSlitEnvelope(x) * maxHeight;
336-
return Math.max(y, envelopeY); // Don't go above envelope (lower y = higher on screen)
295+
return Math.max(y, envelopeY);
337296
};
338297

339298
// Draw smooth sinusoidal curve through each peak
@@ -345,15 +304,14 @@ class GratingFFTSimulation {
345304
// Calculate spacing for first peak
346305
const firstSpacing = nextPeak ? (nextPeak.x - currentPeak.x) : (currentPeak.x - startX);
347306

348-
// Sharp rise approaching first peak - sample and clamp points along the curve
307+
// Sharp rise approaching first peak
349308
const approachX = currentPeak.x - firstSpacing * 0.06;
350309
const numSamples = 20;
351310

352311
for (let s = 0; s <= numSamples; s++) {
353312
const t = s / numSamples;
354313
const x = startX + t * (approachX - startX);
355314

356-
// Bezier calculation
357315
const controlX1 = startX + (approachX - startX) * 0.7;
358316
const controlY1 = screenY;
359317
const controlX2 = approachX - (approachX - startX) * 0.1;
@@ -368,7 +326,7 @@ class GratingFFTSimulation {
368326
else ctx.lineTo(bx, clampedY);
369327
}
370328

371-
// Rounded peak top - sample and clamp
329+
// Rounded peak top
372330
const peakStartX = approachX;
373331
const peakEndX = currentPeak.x + firstSpacing * 0.06;
374332

@@ -482,15 +440,14 @@ class GratingFFTSimulation {
482440
ctx.globalAlpha = 1.0;
483441
ctx.stroke();
484442

485-
// Draw smooth dotted white envelope curve OVER the peaks showing side lobes
443+
// Draw smooth dotted white envelope curve
486444
ctx.lineWidth = 2;
487445
ctx.strokeStyle = '#ffffff';
488446
ctx.globalAlpha = 0.7;
489447
ctx.setLineDash([5, 5]);
490448

491449
ctx.beginPath();
492450

493-
const centerX = this.cvs.width / 2;
494451
const numPoints = 400;
495452
let started = false;
496453

@@ -529,7 +486,7 @@ class GratingFFTSimulation {
529486
const x = Math.round(order.x);
530487
const v = order.intensity;
531488
const h = Math.round(v * (this.cvs.height * 0.45));
532-
const width = Math.round(order.width); // Use calculated width
489+
const width = Math.round(order.width);
533490

534491
if (h > 0) {
535492
for (let dx = -width; dx <= width; dx++) {
@@ -568,11 +525,11 @@ class GratingFFTSimulation {
568525
const envelopeWidthFactor = 1.0 + (this.distanceToScreen - 1.0) * 0.4;
569526
const envelopeWidth = this.cvs.width * 0.3 * envelopeWidthFactor;
570527

571-
// Single-slit envelope function (same as in drawIntensityPlot)
528+
// Single-slit envelope function
572529
const singleSlitEnvelope = (x) => {
573530
const centerX = this.cvs.width / 2;
574531
const normalizedX = (x - centerX) / envelopeWidth;
575-
const beta = normalizedX * 1.5;
532+
const beta = normalizedX * 1.8;
576533

577534
let sincValue;
578535
if (Math.abs(beta) < 0.001) {
@@ -584,9 +541,9 @@ class GratingFFTSimulation {
584541
let intensity = sincValue * sincValue;
585542

586543
if (Math.abs(beta) > 1.0 && Math.abs(beta) < 2.0) {
587-
intensity *= 11;
544+
intensity *= 3;
588545
} else if (Math.abs(beta) >= 2.0 && Math.abs(beta) < 3.0) {
589-
intensity *= 8;
546+
intensity *= 2;
590547
}
591548

592549
return Math.max(0, intensity);
@@ -651,7 +608,6 @@ class GratingFFTSimulation {
651608
if (prevY === this.screen.y) return;
652609

653610
// Update distance based on new Y position
654-
// Y from maxY (0.75*height) = 1.0m to minY (0.25*height) = 2.0m
655611
const fraction = (this.screen.maxY - this.screen.y) / (this.screen.maxY - this.screen.minY);
656612
this.distanceToScreen = 1.0 + fraction * 1.0;
657613

0 commit comments

Comments
 (0)