
Generated p5.js prompts eval
Prompt
Create a p5.js animation that illustrates the principles of quantum mechanics by simulating the behavior of particles in a potential well, allowing the user to adjust the depth and width of the well, as well as the energy of the particles, to visualize the resulting probability distributions and wave functions.
A system prompt was added to support web rendering
Here is a p5.js animation that simulates a quantum particle in a potential well. You can adjust the properties of the well and the particle's energy to explore fundamental quantum phenomena. ### How to Use: * **Well Width & Depth Sliders:** These control the size of the potential well, which is the gray region where the potential energy `V` is zero. Outside the well, the potential is `V₀`. * **Particle Energy Slider:** This sets the energy level `E` of the particle, represented by the dashed red line. * **Find Stable States:** The core principle of quantum mechanics illustrated here is **quantization**. Only specific, discrete energy levels (`E`) are "allowed" for a particle trapped in the well. * Adjust the **Particle Energy** slider until the blue wave a a a a function (`ψ`) decays towards zero on both sides of the well, instead of flying off to positive or negative infinity. * When you find such a state, you have discovered a quantized energy level. Notice how these stable states have a whole number of half-wavelengths inside the well (1, 2, 3, ...). * **Wave Function (`ψ`):** The blue line shows the wave function. Its amplitude relates to the particle's presence. * **Probability Density (`ψ²`):** The orange area shows where the particle is most likely to be found. * **Quantum Tunneling:** Set the particle energy `E` to be greater than 0 but less than the well depth `V₀`. Observe that the wave function is not zero outside the well. This "leaking" into the barrier is a purely quantum effect related to tunneling. ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Well Simulator</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script> <style> body { padding: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; overflow: hidden; /* Prevent scrollbars from sliders */ background-color: #f8f9fa; } .main-container { display: flex; flex-direction: column; align-items: center; padding: 20px; } .controls { padding: 15px; background-color: #ffffff; border: 1px solid #dee2e6; border-radius: 8px; margin-top: 20px; width: 800px; box-sizing: border-box; } .slider-container { display: flex; align-items: center; margin: 10px 0; } label { min-width: 180px; display: inline-block; font-size: 14px; color: #343a40; } input[type=range] { width: 300px; } .checkbox-container { margin-top: 15px; } .info-text { font-size: 13px; color: #6c757d; margin-top: 15px; line-height: 1.5; } </style> </head> <body> <div class="main-container"> <div id="canvas-container"></div> <div id="controls-container"></div> </div> <script> // --- p5.js Sketch Starts Here --- let wellWidthSlider, wellDepthSlider, energySlider; let showWaveCheckbox, showProbCheckbox; let labelWidth, labelDepth, labelEnergy; let wavePoints = []; const amplitudeScale = 40; // Scales the amplitude of the wave for visibility const calculationStep = 0.5; // Precision of the calculation (smaller is more accurate) const energyScale = 20; // Pixels per unit of energy function setup() { let canvas = createCanvas(800, 450); canvas.parent('canvas-container'); let controlsDiv = createDiv().addClass('controls').id('controls'); controlsDiv.parent('controls-container'); // Well Width Slider let div1 = createDiv().parent(controlsDiv).addClass('slider-container'); labelWidth = createSpan('Well Width (L): ').parent(div1).attribute('for', 'wellWidth'); wellWidthSlider = createSlider(150, 500, 300, 5).parent(div1).id('wellWidth'); // Well Depth Slider let div2 = createDiv().parent(controlsDiv).addClass('slider-container'); labelDepth = createSpan('Well Depth (V₀): ').parent(div2).attribute('for', 'wellDepth'); wellDepthSlider = createSlider(1, 15, 10, 0.1).parent(div2).id('wellDepth'); // Particle Energy Slider let div3 = createDiv().parent(controlsDiv).addClass('slider-container'); labelEnergy = createSpan('Particle Energy (E): ').parent(div3).attribute('for', 'energy'); energySlider = createSlider(0.1, 15, 1.0, 0.01).parent(div3).id('energy'); // Checkboxes let div4 = createDiv().parent(controlsDiv).addClass('checkbox-container'); showWaveCheckbox = createCheckbox(' Show Wave Function (ψ)', true).parent(div4); showProbCheckbox = createCheckbox(' Show Probability Density (ψ²)', true).parent(div4); // Info text createP('<b>Instructions:</b> Adjust the sliders to see their effect. Try to tune the <b>Particle Energy</b> to find stable states where the wave function decays to zero on both sides of the well. These are the allowed quantized energy levels.').parent(controlsDiv).addClass('info-text'); } function draw() { background(250, 251, 252); // Get values from sliders let w = wellWidthSlider.value(); let V0 = wellDepthSlider.value(); let E = energySlider.value(); // Calculate the wave function using a numerical method calculateWaveFunction(w, V0, E); // Draw visualization elements drawPotentialWell(w, V0); drawEnergyLevel(E); if (showProbCheckbox.checked()) { drawProbabilityDensity(E); } if (showWaveCheckbox.checked()) { drawWaveFunction(E); } drawLabels(w, V0, E); } function calculateWaveFunction(wellWidth, V0, E) { wavePoints = []; let psi = 0.001; // Initial wave function value (small, non-zero) let phi = 0; // Initial derivative d(psi)/dx // Set initial state based on energy (for the shooting method) let startPotential = V0; // We start in the potential barrier V0 if (E < startPotential) { // If in a classically forbidden region, start with an exponential decay form let kappa = sqrt(startPotential - E); // We set 2m/ħ² = 1 for simplicity phi = kappa * psi; } let maxPsi = 0; for (let x = 0; x < width; x += calculationStep) { let well_x_start = (width - wellWidth) / 2; let well_x_end = (width + wellWidth) / 2; // Define the potential V at position x let V = (x > well_x_start && x < well_x_end) ? 0 : V0; // Time-Independent Schrödinger Equation: d²ψ/dx² = (V - E)ψ let d2psi = (V - E) * psi; // Euler's method to integrate twice phi += d2psi * calculationStep; psi += phi * calculationStep; wavePoints.push({x: x, y: psi}); if (abs(psi) > maxPsi) { maxPsi = abs(psi); } } // Normalize the wave function to fit the screen nicely // Cap the normalization factor if the wave diverges to prevent flickering let normalizationFactor = amplitudeScale / min(maxPsi, 500); for (let i = 0; i < wavePoints.length; i++) { wavePoints[i].y *= normalizationFactor; } } function getEnergyY(E) { // Invert y-axis for drawing return height - 50 - (E * energyScale); } function drawPotentialWell(w, V0) { let well_x = (width - w) / 2; let y_potential_top = getEnergyY(V0); let y_potential_bottom = height; // Shade the potential barrier region fill(220, 225, 230, 150); noStroke(); rect(0, 0, width, y_potential_top); // Draw the outline of the well stroke(100, 110, 120); strokeWeight(2); line(0, y_potential_top, well_x, y_potential_top); line(well_x, y_potential_top, well_x, getEnergyY(0)); line(well_x, getEnergyY(0), well_x + w, getEnergyY(0)); line(well_x + w, getEnergyY(0), well_x + w, y_potential_top); line(well_x + w, y_potential_top, width, y_potential_top); } function drawEnergyLevel(E) { let y_level = getEnergyY(E); stroke(255, 0, 0, 180); strokeWeight(2); drawingContext.setLineDash([6, 6]); line(0, y_level, width, y_level); drawingContext.setLineDash([]); // Reset line dash } function drawWaveFunction(E) { let y_level = getEnergyY(E); noFill(); stroke(0, 123, 255); strokeWeight(2); beginShape(); for (let pt of wavePoints) { vertex(pt.x, y_level - pt.y); } endShape(); } function drawProbabilityDensity(E) { let y_level = getEnergyY(E); fill(255, 193, 7, 100); stroke(255, 193, 7); strokeWeight(1); beginShape(); vertex(0, y_level); for (let pt of wavePoints) { // Probability is proportional to ψ², so it's always positive vertex(pt.x, y_level - (pt.y * pt.y) / amplitudeScale); } vertex(width, y_level); endShape(CLOSE); } function drawLabels(w, V0, E) { noStroke(); textSize(14); // Update slider labels labelWidth.html(`Well Width (L): <b>${w.toFixed(0)}</b>`); labelDepth.html(`Well Depth (V₀): <b>${V0.toFixed(2)}</b>`); labelEnergy.html(`Particle Energy (E): <b>${E.toFixed(2)}</b>`); // Draw axis labels textAlign(LEFT, CENTER); fill(255, 0, 0); text('E', 10, getEnergyY(E)); fill(100, 110, 120); text('V₀', 10, getEnergyY(V0) - 10); // Legend textAlign(RIGHT, CENTER); let legendX = width - 15; let legendY = 20; if(showWaveCheckbox.checked()) { fill(0, 123, 255); text('Wave Function (ψ)', legendX, legendY); legendY += 20; } if(showProbCheckbox.checked()) { fill(255, 193, 7); text('Probability Density (ψ²)', legendX, legendY); } // Display warning if the wave function is divergent (not a stable state) let lastPointY = wavePoints[wavePoints.length - 1].y; if (abs(lastPointY) > amplitudeScale * 1.2) { textAlign(CENTER, CENTER); // Fade in the warning text as divergence increases let alpha = map(abs(lastPointY), amplitudeScale * 1.2, amplitudeScale * 5, 50, 255, true); fill(220, 53, 69, alpha); textSize(24); textFont('Georgia'); text("Not a stable energy state (wave function diverges)", width / 2, 40); textFont('sans-serif'); // Reset font } } // --- p5.js Sketch Ends Here --- </script> </body> </html> ```
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Quantum Well Simulation (p5.js)</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script> <style> body { background: #181c20; color: #eee; font-family: sans-serif; } .container { max-width: 760px; margin: 20px auto; background: #22262a; border-radius: 10px; padding: 20px 30px 40px 30px; box-shadow: 0 6px 25px rgba(0,0,0,0.5); } h2 { color: #84caf2; text-align: center; margin-top: 0; } .controls { display: flex; flex-wrap: wrap; gap: 23px; justify-content: center; margin-bottom: 20px; margin-top: 15px; } label { font-size: 15px; margin-right: 8px; } @media (max-width: 800px) { .container { padding: 10px; } .controls { flex-direction: column; gap: 14px; align-items: flex-start;} } </style> </head> <body> <div class="container"> <h2>Quantum Particle in a 1D Potential Well</h2> <div class="controls" id="controls"></div> <div id="canvas-holder"></div> <p style="font-size:15px;color:#c3e4ff;text-align:center;"> Adjust the <b>well depth</b>, <b>width</b>, and <b>energy level</b> to explore wave functions (ψ) and probability densities (|ψ|<sup>2</sup>) for a quantum particle in a finite well.<br> <span style="color:#7ac279;">Green:</span> Wavefunction ψ(x) <span style="color:#5091e4;">Blue:</span> Probability density |ψ(x)|<sup>2</sup> <span style="color:#ff4476;">Red:</span> Potential well </p> </div> <script> // Set up sliders & UI outside of p5 so they're not in the sketch let wellDepthSlider, wellWidthSlider, energySlider, showPsiCheck, showProbCheck; let labels = []; function createControlUI() { let parent = document.getElementById('controls'); // Well Depth let lbl1 = document.createElement('label'); lbl1.htmlFor = "wellDepth"; lbl1.innerHTML = "Well Depth (V<sub>0</sub>):"; parent.appendChild(lbl1); wellDepthSlider = document.createElement('input'); wellDepthSlider.type = 'range'; wellDepthSlider.id = 'wellDepth'; wellDepthSlider.min = 10; wellDepthSlider.max = 200; wellDepthSlider.value = 80; wellDepthSlider.style.width = '120px'; parent.appendChild(wellDepthSlider); let wd_val = document.createElement('span'); wd_val.innerHTML = wellDepthSlider.value; parent.appendChild(wd_val); // Well Width let lbl2 = document.createElement('label'); lbl2.htmlFor = "wellWidth"; lbl2.innerHTML = "Well Width (a):"; parent.appendChild(lbl2); wellWidthSlider = document.createElement('input'); wellWidthSlider.type = 'range'; wellWidthSlider.id = 'wellWidth'; wellWidthSlider.min = 100; wellWidthSlider.max = 400; wellWidthSlider.value = 300; wellWidthSlider.style.width = '120px'; parent.appendChild(wellWidthSlider); let ww_val = document.createElement('span'); ww_val.innerHTML = wellWidthSlider.value; parent.appendChild(ww_val); // Energy level let lbl3 = document.createElement('label'); lbl3.htmlFor = "energy"; lbl3.innerHTML = "Energy Level (n):"; parent.appendChild(lbl3); energySlider = document.createElement('input'); energySlider.type = 'range'; energySlider.id = 'energy'; energySlider.min = 1; energySlider.max = 5; energySlider.value = 1; energySlider.style.width = '80px'; parent.appendChild(energySlider); let en_val = document.createElement('span'); en_val.innerHTML = energySlider.value; parent.appendChild(en_val); // Visibility checkboxes let lblC1 = document.createElement('label'); lblC1.innerHTML = '<input type="checkbox" checked id="showPsi"> Show ψ(x)'; parent.appendChild(lblC1); let lblC2 = document.createElement('label'); lblC2.innerHTML = '<input type="checkbox" checked id="showProb"> Show |ψ(x)|<sup>2</sup>'; parent.appendChild(lblC2); // Update value text wellDepthSlider.addEventListener('input', () => { wd_val.innerHTML = wellDepthSlider.value; }); wellWidthSlider.addEventListener('input', () => { ww_val.innerHTML = wellWidthSlider.value; }); energySlider.addEventListener('input', () => {en_val.innerHTML = energySlider.value;}); } createControlUI(); // p5.js sketch in an encapsulated instance let sketch = function(p) { // Constants (arbitrary units) let m = 1; // mass let hbar = 1; let Npts = 600; let xvals = []; let psi = []; let prob = []; let norm = 0; let canvasW = 650, canvasH = 360, margin = 60; let potential = []; // Parameters let V0 = 80; // Well depth let a = 300; // Well width (in pixels, mapping to world units) let n = 1; // Energy level // UI state let showPsi = true; let showProb = true; function getInputs() { V0 = parseFloat(wellDepthSlider.value); a = parseFloat(wellWidthSlider.value); n = parseInt(energySlider.value); showPsi = document.getElementById("showPsi").checked; showProb = document.getElementById("showProb").checked; } // Map x in [0, canvasW] to [-L, L], with L chosen to show outside well function setupDomain() { let L = Math.max(a * 1.3/2, 140); xvals = []; for (let i=0; i<Npts; i++) { let x = p.map(i, 0, Npts-1, -L, L); xvals.push(x); } return L; } // Calculate the finite well's bound state solution numerically function computeWavefunction() { psi = new Array(Npts).fill(0); prob = new Array(Npts).fill(0); // Reduced units: hbar^2/(2m)=1 // The well is -V0 for |x|<a/2, 0 otherwise // Numerically solve "matching" for allowed energies // Allow for up to 5 bound states (n) let L = Math.max(a * 1.3/2, 140); let halfWidth = a/2; // Setup potential for visualization potential = []; for (let i=0; i<Npts; i++) { let x = xvals[i]; potential.push((Math.abs(x) < halfWidth) ? -V0 : 0); } // Numerically find energy for nth state // Guess energy range: 0 to V0 (bound states) let E_guess = []; let maxStates = Math.floor(a/Math.PI * Math.sqrt(2*m*V0)/hbar); if (maxStates<1) maxStates = 1; // Compute E numerically via transcendental equation: // For even: // k = sqrt(2m(E+V0))/hbar, alpha = sqrt(2m(-E))/hbar // k*tan(k*a/2) = alpha // For odd: // -k*cot(k*a/2) = alpha // Use units so hbar^2/2m = 1 function match(E, parity) { let k = Math.sqrt(E+V0); let alpha = Math.sqrt(-E); let ka2 = k*halfWidth; if (parity==0) { // even return (k*Math.tan(ka2)) - alpha; } else { // odd return (-k/Math.tan(ka2)) - alpha; } } // Use bisection within allowed intervals function rootBisection(f, lo, hi, tol=1e-6, itmax=100) { let flo = f(lo), fhi = f(hi); if (Math.sign(flo)==Math.sign(fhi)) return null; let mid; for (let i=0; i<itmax; i++) { mid = (lo+hi)/2; let fmid = f(mid); if (Math.abs(fmid) < tol) break; if (Math.sign(fmid)==Math.sign(flo)) { lo = mid; flo = fmid; } else { hi = mid; } } return mid; } let foundE = []; let parity, k, alpha, E, stateCount=0; for (let mode=0; mode<10; mode++) { // Parity even for mode=0,2,4... odd=1,3,5... parity = mode%2; // Allowed ka/2 intervals: // for even: [m*PI/2, (m+1)*PI/2] for m even // for odd: [m*PI/2, (m+1)*PI/2] for m odd let m = Math.floor(mode/2); let lo = m * Math.PI; let hi = (m+1) * Math.PI; // E vs k: E = k^2 - V0, ka/2 = in [lo,hi] // So k = ka2/halfWidth, E(k) = k^2-V0, for k in [lo/halfWidth,hi/halfWidth] let klo = lo/halfWidth, khi = hi/halfWidth; function fE(E) { if (E<-V0+0.0001 || E>-0.0001) return 1e12; let k = Math.sqrt(E+V0); let ka2 = k*halfWidth; if (isNaN(k)) return 1e12; if (parity==0) return (k*Math.tan(ka2) - Math.sqrt(-E)); else return ((-k/Math.tan(ka2)) - Math.sqrt(-E)); } let Elo = -V0+0.001, Ehi = -0.001; let found = null, evals = 50; let dE = (Ehi-Elo)/evals; let signLast = null; let lastE = Elo, lastf = fE(Elo); for (let j=1; j<=evals; j++) { let thisE = Elo + dE*j; let thisf = fE(thisE); if (Math.sign(lastf)!=Math.sign(thisf)) { // root in [lastE, thisE] found = rootBisection(fE, lastE, thisE); if (found!==null && foundE.length<n) foundE.push(found); } lastE = thisE; lastf = thisf; if (foundE.length==n) break; } if (foundE.length==n) break; } // If not enough states found, stop if (foundE.length==0) return; E = foundE[n-1]; k = Math.sqrt(E+V0); alpha = Math.sqrt(-E); let normFac = 0; // Compute matching constant B/A from BCs let A, B; // For even: psi(x) = A cos(kx) in well, psi(x) = F exp(-alpha x) outside // For odd: psi(x) = A sin(kx) in well, psi(x) = F sign(x) exp(-alpha x) if ((n-1)%2==0) { // even A = 1; // Match at x=a/2 let xw = halfWidth; let coskw = Math.cos(k*xw); let F = A * coskw; // Normalization: // int_{-a/2}^{a/2} cos^2(kx) dx + 2*int_{a/2}^L F^2*exp(-2alpha(x-xw)) dx // = A^2*(a/2 + sin(ka)/(2k)) + F^2 / (alpha) let S1 = A*A*(halfWidth + Math.sin(k*halfWidth)/k)/2; let S2 = (F*F) * Math.exp(-2*alpha*0)/(2*alpha) * (Math.exp(-2*alpha*(L-halfWidth))); // It's enough to numerically integrate for our display normFac = 0; for (let i=0; i<Npts; i++) { let x = xvals[i]; let val; if (Math.abs(x) <= halfWidth) { val = A*Math.cos(k*x); } else { val = A*Math.cos(k*halfWidth) * Math.exp(-alpha*(Math.abs(x)-halfWidth)); if (x<0 && Math.abs(x)>halfWidth) val *= 1.0; } psi[i] = val; normFac += val*val; } normFac = Math.sqrt(normFac/(Npts)); for (let i=0; i<Npts; i++) psi[i] /= normFac; } else { // odd A = 1; let xw = halfWidth; let sinkw = Math.sin(k*xw); let F = A * sinkw; normFac = 0; for (let i=0; i<Npts; i++) { let x = xvals[i]; let val; if (Math.abs(x) <= halfWidth) { val = A*Math.sin(k*x); } else { val = (x>0?1:-1)*A*Math.sin(k*halfWidth) * Math.exp(-alpha*(Math.abs(x)-halfWidth)); } psi[i] = val; normFac += val*val; } normFac = Math.sqrt(normFac/(Npts)); for (let i=0; i<Npts; i++) psi[i] /= normFac; } // Probability density for (let i=0; i<Npts; i++) { prob[i] = psi[i]*psi[i]; } // Save energy for display p.energy_state = E; } p.setup = function() { let cnv = p.createCanvas(canvasW, canvasH); cnv.parent('canvas-holder'); p.frameRate(32); computeWavefunction(); }; let sTime = 0; p.draw = function() { getInputs(); let L = setupDomain(); // If user changed state, recompute if (p.lastV0!==V0 || p.lasta!==a || p.lastn!==n) { computeWavefunction(); p.lastV0 = V0; p.lasta=a; p.lastn=n; } // Draw potential, wave function, probability p.background(28,36,44); p.push(); p.translate(margin, margin/2); // draw axis p.stroke(180); p.strokeWeight(1); p.line(0, 0, 0, canvasH-margin); // y axis p.line(0, canvasH-margin/2, canvasW-2*margin, canvasH-margin/2); // x axis // Draw potential well p.noFill(); p.strokeWeight(3); p.stroke(255,80,90,180); p.beginShape(); for (let i=0; i<Npts; i++) { let x = p.map(xvals[i], -L, L, 0, canvasW-2*margin); let V = potential[i]; let y = canvasH-margin/2 - V*(canvasH-margin/2-10)/V0; p.vertex(x, y); } p.endShape(); // Draw well boundaries p.stroke(255,50,50,38); p.strokeWeight(10); p.noFill(); let leftW = p.map(-a/2, -L, L, 0, canvasW-2*margin); let rightW = p.map(a/2, -L, L, 0, canvasW-2*margin); p.line(leftW, 0, leftW, canvasH-margin); p.line(rightW, 0, rightW, canvasH-margin); // Draw probability density |psi|^2 if (showProb) { p.noFill(); p.stroke(80,150,255); p.strokeWeight(2); p.beginShape(); for (let i=0; i<Npts; i++) { let x = p.map(xvals[i], -L, L, 0, canvasW-2*margin); // Vertical scaling let y = canvasH-margin/2 - prob[i]*140; p.vertex(x, y); } p.endShape(); } // Draw wavefunction psi(x) and animate phase if (showPsi) { sTime += 0.018; p.noFill(); p.stroke(120,220,120); p.strokeWeight(2.2); p.beginShape(); // Animate phase if E>0 (for excited), else static let ephase = Math.sqrt(Math.abs(p.energy_state)); let phase = sTime*ephase; // for time-dependent psi(x,t) = psi(x)*exp(-iEt/hbar) for (let i=0; i<Npts; i++) { let x = p.map(xvals[i], -L, L, 0, canvasW-2*margin); let py = canvasH-margin/2 - psi[i]*82*Math.cos(phase); p.vertex(x, py); } p.endShape(); } // Well lines again (overlay) p.stroke(255,80,80,90); p.strokeWeight(1.7); p.line(leftW, 0, leftW, canvasH-margin); p.line(rightW, 0, rightW, canvasH-margin); // Axis ticks p.stroke(170,170,190,120); p.strokeWeight(1.2); for (let i=0; i<=8; i++) { let x = p.map(i,0,8,0,canvasW-2*margin); p.line(x, canvasH-margin/2+2, x, canvasH-margin/2-2); let xx = p.map(i,0,8,-L, L); let lbl = ''; if (Math.abs(xx)<1e-2) lbl='0'; else lbl = xx.toFixed(0); p.noStroke(); p.fill(140,210,240,130); p.textSize(11); p.text(lbl, x-7, canvasH-margin/2+17); } // Energy line let Ey = canvasH-margin/2 - p.energy_state*(canvasH-margin/2-10)/V0; p.stroke(255,255,40,130); p.strokeWeight(1.7); p.line(0, Ey, canvasW-2*margin, Ey); p.noStroke(); p.fill(255,255,60,220); p.textSize(13); p.text("Eₙ = " + p.energy_state.toFixed(2), 12, Ey-5); // Axis labels p.fill(210,220,250,200); p.textSize(15); p.text("x", canvasW-margin*1.3, canvasH-margin/2+14); p.text("Potential / Ψ / |Ψ|²", 10, 18); p.pop(); }; }; new p5(sketch); </script> </body> </html> ```
Drag to resize
index.html ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Potential Well Simulation</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> <style> body { margin: 0; padding: 20px; font-family: Arial, sans-serif; background-color: #f0f0f0; } .control-panel { background-color: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); margin-bottom: 20px; } .control-group { margin-bottom: 10px; } label { display: inline-block; width: 120px; } </style> </head> <body> <div class="control-panel"> <div class="control-group"> <label for="wellWidth">Well Width:</label> <input type="range" id="wellWidth" min="100" max="300" value="200"> <span id="wellWidthValue">200</span> </div> <div class="control-group"> <label for="wellDepth">Well Depth:</label> <input type="range" id="wellDepth" min="50" max="200" value="100"> <span id="wellDepthValue">100</span> </div> <div class="control-group"> <label for="energyLevel">Energy Level (n):</label> <input type="range" id="energyLevel" min="1" max="8" value="1"> <span id="energyLevelValue">1</span> </div> </div> <div id="canvas-container"></div> <script> let wellWidth = 200; let wellDepth = 100; let energyLevel = 1; let particles = []; const particleCount = 1000; let canvasWidth = 800; let canvasHeight = 400; function setup() { let canvas = createCanvas(canvasWidth, canvasHeight); canvas.parent('canvas-container'); // Initialize particles for (let i = 0; i < particleCount; i++) { particles.push({ x: random(width), y: random(height), vx: random(-1, 1), vy: random(-1, 1) }); } // Setup controls document.getElementById('wellWidth').addEventListener('input', function() { wellWidth = parseInt(this.value); document.getElementById('wellWidthValue').textContent = wellWidth; }); document.getElementById('wellDepth').addEventListener('input', function() { wellDepth = parseInt(this.value); document.getElementById('wellDepthValue').textContent = wellDepth; }); document.getElementById('energyLevel').addEventListener('input', function() { energyLevel = parseInt(this.value); document.getElementById('energyLevelValue').textContent = energyLevel; }); } function draw() { background(240); // Draw potential well drawPotentialWell(); // Calculate probability distribution let probDist = calculateProbabilityDistribution(); // Draw probability distribution drawProbabilityDistribution(probDist); // Update and draw particles updateParticles(probDist); // Draw wave function drawWaveFunction(); } function drawPotentialWell() { let wellCenterX = width / 2; let wellLeft = wellCenterX - wellWidth / 2; let wellRight = wellCenterX + wellWidth / 2; // Draw well boundary stroke(0); strokeWeight(2); line(wellLeft, height - 100, wellLeft, height - 100 - wellDepth); line(wellRight, height - 100, wellRight, height - 100 - wellDepth); line(wellLeft, height - 100 - wellDepth, wellRight, height - 100 - wellDepth); // Label noStroke(); fill(0); text('Potential Well', wellCenterX - 50, height - 120 - wellDepth); } function calculateProbabilityDistribution() { let dist = []; let wellCenterX = width / 2; let wellLeft = wellCenterX - wellWidth / 2; let wellRight = wellCenterX + wellWidth / 2; for (let x = 0; x < width; x++) { if (x >= wellLeft && x <= wellRight) { // Inside well: sinusoidal probability distribution (solution to Schrödinger equation) let relativeX = (x - wellLeft) / wellWidth; let value = pow(sin(energyLevel * PI * relativeX), 2); dist.push(value); } else { // Outside well: exponential decay (tunneling effect) let distance; if (x < wellLeft) { distance = (wellLeft - x) / wellWidth; } else { distance = (x - wellRight) / wellWidth; } let value = exp(-distance * energyLevel * 50 / wellWidth); dist.push(value); } } return dist; } function drawProbabilityDistribution(probDist) { let wellCenterX = width / 2; let wellLeft = wellCenterX - wellWidth / 2; let wellRight = wellCenterX + wellWidth / 2; let maxProb = max(probDist); noFill(); stroke(0, 0, 255); strokeWeight(2); beginShape(); for (let x = 0; x < width; x++) { let y = map(probDist[x], 0, maxProb, height - 50, height - 250); vertex(x, y); } endShape(); } function drawWaveFunction() { let wellCenterX = width / 2; let wellLeft = wellCenterX - wellWidth / 2; let wellRight = wellCenterX + wellWidth / 2; let amplitude = 50; noFill(); stroke(255, 0, 0); strokeWeight(2); beginShape(); for (let x = 0; x < width; x++) { let y; if (x >= wellLeft && x <= wellRight) { // Inside well: standing wave let k = energyLevel * PI / wellWidth; let relX = x - wellLeft; y = height - 150 - amplitude * sin(k * relX) * (energyLevel % 2 === 0 ? 1 : -1); } else { // Outside well: exponential decay let decay; if (x < wellLeft) { decay = (wellLeft - x) / 30; } else { decay = (x - wellRight) / 30; } y = height - 150 - amplitude * exp(-decay); } vertex(x, y); } endShape(); } function updateParticles(probDist) { let wellCenterX = width / 2; let wellLeft = wellCenterX - wellWidth / 2; let wellRight = wellCenterX + wellWidth / 2; for (let i = 0; i < particles.length; i++) { let p = particles[i]; // Move particle p.x += p.vx; p.y += p.vy; // Handle boundary conditions if (p.x < 0 || p.x > width) { p.vx *= -1; p.x = constrain(p.x, 0, width); } if (p.y < 0 || p.y > height) { p.vy *= -1; p.y = constrain(p.y, 0, height); } // Quantum behavior - particles more likely to be found where probability is higher let x = floor(constrain(p.x, 0, width - 1)); let prob = probDist[x]; // Only show particles that are within a random threshold of the probability fill(0, 150, 0, 150); noStroke(); if (random(1) < prob * 0.5) { ellipse(p.x, p.y, 3, 3); } } } </script> </body> </html> ``` This HTML file creates a p5.js simulation that visualizes quantum particles in a potential well. The simulation includes: 1. Adjustable parameters for well width, depth, and energy level via sliders 2. Visualization of the quantum probability distribution (blue curve) 3. Visualization of the wave function (red curve) 4. Particle representation showing where particles are most likely to be found according to quantum probability The simulation demonstrates key quantum mechanical principles: - Quantized energy levels (discrete n values) - Wave-particle duality - Probability density distributions - Tunneling effect (exponential decay outside the well) - Standing wave patterns in the potential well Users can interact with the simulation by adjusting the parameters to see how different well configurations affect the quantum behavior.
Drag to resize
# Quantum Particle in a Potential Well Visualization I'll create an interactive simulation that visualizes quantum particles in a finite potential well using p5.js. The visualization will allow users to adjust the width and depth of the well along with particle energy to observe wave functions and probability distributions. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Particle in Potential Well</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.dom.min.js"></script> <style> body { margin: 0; padding: 20px; font-family: 'Arial', sans-serif; background: linear-gradient(135deg, #1a237e, #0d47a1); color: #e3f2fd; overflow-x: hidden; } .container { max-width: 800px; margin: 0 auto; background: rgba(13, 19, 38, 0.8); border-radius: 15px; padding: 20px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); } h1 { text-align: center; color: #18ffff; text-shadow: 0 0 10px rgba(24, 255, 255, 0.6); } .description { text-align: center; margin-bottom: 20px; line-height: 1.6; } canvas { display: block; margin: 0 auto; border-radius: 10px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4); } .controls { display: flex; justify-content: space-between; gap: 15px; margin-top: 20px; flex-wrap: wrap; } .control-group { flex: 1; min-width: 200px; background: rgba(29, 36, 74, 0.7); padding: 15px; border-radius: 10px; } .control-label { display: block; margin-bottom: 8px; font-weight: bold; } .control-value { font-weight: bold; color: #00e5ff; margin-left: 8px; } .explanation { margin-top: 25px; padding: 15px; background: rgba(13, 19, 38, 0.7); border-radius: 10px; border-left: 3px solid #00e5ff; } h3 { color: #80deea; margin-top: 10px; } .key-info { display: flex; justify-content: space-around; margin-top: 15px; } .key-item { text-align: center; } .color-box { display: inline-block; width: 20px; height: 20px; border-radius: 4px; margin-right: 8px; } </style> </head> <body> <div class="container"> <h1>Quantum Potential Well Simulator</h1> <p class="description">Visualize quantum particle behavior with adjustable well parameters. Observe wave functions and probability distributions!</p> <div id="canvas-container"></div> <div class="controls"> <div class="control-group"> <label class="control-label"> Well Width (<span id="width-value" class="control-value">100</span> px) </label> <input type="range" id="width-slider" min="50" max="200" value="100" style="width:100%"> <label class="control-label" style="margin-top:20px"> Well Depth (<span id="depth-value" class="control-value">100</span> eV) </label> <input type="range" id="depth-slider" min="20" max="200" value="100" style="width:100%"> </div> <div class="control-group"> <label class="control-label"> Particle Energy (<span id="energy-value" class="control-value">60</span> eV) </label> <input type="range" id="energy-slider" min="5" max="195" value="60" style="width:100%"> <label class="control-label" style="margin-top:20px"> Particle Speed (<span id="speed-value" class="control-value">1.0</span> x) </label> <input type="range" id="speed-slider" min="0.1" max="4" step="0.1" value="1.0" style="width:100%"> </div> </div> <div class="explanation"> <h3>Visualization Key:</h3> <div class="key-info"> <div class="key-item"> <div class="color-box" style="background:#004d40;"></div> Potential Well Region </div> <div class="key-item"> <div class="color-box" style="background:#e1bee7;"></div> Wave Function </div> <div class="key-item"> <div class="color-box" style="background:#4a148c;"></div> Probability Distribution </div> </div> <h3 style="margin-top:20px">Quantum Mechanics Principles:</h3> <p>This visualization demonstrates:</p> <ul> <li>Wave-particle duality - particles exist as probability waves</li> <li>Quantum tunneling - particles can penetrate barriers</li> <li>Energy quantization - only specific energy levels are allowed</li> <li>Uncertainty principle - position and momentum cannot be simultaneously known</li> </ul> </div> </div> <script> // Many states to simulate particle behavior const particleCount = 30; let particles = []; // Width and depth of the well let wellWidth, wellDepth, particleEnergy, particleSpeed; function setup() { const container = document.getElementById('canvas-container'); const canvas = createCanvas(700, 400); canvas.parent('canvas-container'); // Initialize controls wellWidth = 100; wellDepth = 100; particleEnergy = 60; particleSpeed = 1.0; // Setup particles for (let i = 0; i < particleCount; i++) { particles.push(createParticle()); } // Initialize sliders const widthSlider = document.getElementById('width-slider'); const depthSlider = document.getElementById('depth-slider'); const energySlider = document.getElementById('energy-slider'); const speedSlider = document.getElementById('speed-slider'); const widthValue = document.getElementById('width-value'); const depthValue = document.getElementById('depth-value'); const energyValue = document.getElementById('energy-value'); const speedValue = document.getElementById('speed-value'); widthSlider.oninput = function() { wellWidth = parseInt(this.value); widthValue.textContent = wellWidth; }; depthSlider.oninput = function() { wellDepth = parseInt(this.value); depthValue.textContent = wellDepth; }; energySlider.oninput = function() { particleEnergy = parseInt(this.value); energyValue.textContent = particleEnergy; }; speedSlider.oninput = function() { particleSpeed = parseFloat(this.value); speedValue.textContent = particleSpeed.toFixed(1); }; } function createParticle() { return { x: random(width), y: random(height / 3, height / 2), vx: (random() > 0.5 ? 1 : -1) * random(0.5, 2), vy: random(-0.5, 0.5), size: random(5, 8), phase: random(TWO_PI) }; } function draw() { background(13, 19, 38); drawPotentialWell(); drawWaveFunction(); drawProbabilityDistribution(); drawParticles(); drawLabels(); } function drawPotentialWell() { const wellLeft = width / 2 - wellWidth / 2; const wellRight = width / 2 + wellWidth / 2; // Draw potential well noStroke(); fill(0, 77, 64, 150); rect(wellLeft, 0, wellWidth, height); // Draw boundaries stroke(0, 150, 136); strokeWeight(2); line(wellLeft, 0, wellLeft, height); line(wellRight, 0, wellRight, height); // Draw well depth indicator stroke(64, 92, 230); strokeWeight(1); line(wellRight + 10, height - 30, wellRight + 10, height - 30 - wellDepth); fill(64, 92, 230); text('Well Depth', wellRight + 20, height - 20 - wellDepth / 2); // Draw energy level indicator stroke(229, 128, 57); strokeWeight(2); const energyHeight = height - map(particleEnergy, 5, 195, 50, height - 50); line(wellLeft - 30, energyHeight, wellRight + 30, energyHeight); fill(229, 128, 57); text('Energy Level', wellLeft, energyHeight - 10); } function drawWaveFunction() { const wellLeft = width / 2 - wellWidth / 2; const wellRight = width / 2 + wellWidth / 2; const midY = height / 2; // Draw wave function using trigonometric functions noFill(); stroke(225, 190, 231); strokeWeight(2); beginShape(); const nPoints = 200; for (let i = 0; i <= nPoints; i++) { const x = map(i, 0, nPoints, wellLeft - 100, wellRight + 100); let y = midY; if (x < wellLeft) { // Exponential decay outside the well (quantum tunneling) y = midY + 30 * exp(-0.02 * (wellLeft - x)) * sin(0.03 * x + frameCount * 0.02); } else if (x > wellRight) { // Exponential decay outside the well y = midY + 30 * exp(-0.02 * (x - wellRight)) * sin(0.03 * x + frameCount * 0.02); } else { // Wave function inside the well const freq = map(particleEnergy, 0, 200, 0.02, 0.08); const amp = map(particleEnergy, 0, 200, 30, 80); y = midY + amp * sin(freq * (x - wellLeft) * wellWidth + frameCount * 0.04); } vertex(x, y); } endShape(); } function drawProbabilityDistribution() { const wellLeft = width / 2 - wellWidth / 2; const wellRight = width / 2 + wellWidth / 2; const midY = height * 2 / 3; // Draw probability distribution (magnitude of wave function squared) noFill(); stroke(74, 20, 140); strokeWeight(3); beginShape(); const nPoints = 100; for (let i = 0; i <= nPoints; i++) { const x = map(i, 0, nPoints, wellLeft - 50, wellRight + 50); let y; if (x < wellLeft) { // Lower probability in tunneling region y = midY - 60 * exp(-0.025 * (wellLeft - x)); } else if (x > wellRight) { // Lower probability in tunneling region y = midY - 60 * exp(-0.025 * (x - wellRight)); } else { // Probability density inside the well const freq = map(particleEnergy, 0, 200, 0.03, 0.1); const amp = map(particleEnergy, 0, 200, 50, 100); y = midY - amp * pow(sin(freq * (x - wellLeft) * wellWidth + frameCount * 0.05), 2); } vertex(x, y); } endShape(); } function drawParticles() { // Update and draw particles for (let p of particles) { // Apply physics - position update p.x += p.vx * particleSpeed; p.y += p.vy * 0.1 * particleSpeed; // Particle interaction with potential well barriers const wellLeft = width / 2 - wellWidth / 2; const wellRight = width / 2 + wellWidth / 2; if (p.x < wellLeft || p.x > wellRight) { // Quantum tunneling effect: some particles penetrate if (random() < map(particleEnergy, 0, 200, 0.05, 0.3)) { p.vx *= -map(particleEnergy, 0, 200, 0.1, 0.3); } else { p.vx *= -0.9; p.vy += random(-0.2, 0.2); } } // Boundary checking if (p.x < 0) p.x = width; if (p.x > width) p.x = 0; if (p.y < 100) p.y = height - 100; if (p.y > height - 50) p.y = 100; // Draw particle with glow effect noStroke(); // Main particle const glowSize = p.size * 2; for (let i = 0; i < 3; i++) { fill(255, 215, 0, 30 - i*10); ellipse(p.x, p.y, glowSize - i*4); } fill(255, 215, 0); ellipse(p.x, p.y, p.size); // Stochastic trajectory stroke(255, 255, 224, 50); strokeWeight(1); for (let i = 0; i < 3; i++) { let trailX = p.x - p.vx * i * 3; let trailY = p.y - p.vy * i * 3; point(trailX, trailY); } } } function drawLabels() { // Draw name of visualization fill(179, 229, 252); textSize(18); textAlign(CENTER); text('Quantum Particle Behavior Visualization', width / 2, 40); // Draw well labels textSize(14); textAlign(LEFT); fill(100, 255, 218); text('Center of Potential Well', width / 2 - 20, height - 20); textSize(12); textAlign(RIGHT); fill(179, 229, 252); text('Adjust parameters with sliders to explore quantum phenomena', width - 20, height - 5); } </script> </body> </html> ``` This visualization demonstrates several quantum mechanics principles: 1. **Wave-particle duality**: Particles behave both as discrete objects and probability waves 2. **Quantum tunneling**: Some particles penetrate potential barriers despite insufficient energy 3. **Boundary interactions**: Particles interact with well boundaries, displaying quantum confinement 4. **Probability distributions**: The purple wave shows likelihood of finding a particle at a location 5. **Energy dependence**: Higher energy particles display more oscillatory behavior inside the well The interface includes interactive controls for: - Well width (horizontal size of potential region) - Well depth (strength of confinement) - Particle energy (affects wavelength and amplitude) - Particle speed (animation rate) The animation shows particle-like behavior with stochastic motion while simultaneously displaying wave-like characteristics in the probability distribution. The wave function visualization shows complex quantum tunneling effects outside the potential well boundaries.
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Mechanics - Particle in a Potential Well</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script> <style> body { margin: 0; padding: 20px; font-family: Arial, sans-serif; background: #1a1a1a; color: white; } .controls { position: absolute; top: 10px; right: 10px; background: rgba(0, 0, 0, 0.8); padding: 15px; border-radius: 10px; z-index: 100; } .control-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-size: 12px; } input[type="range"] { width: 150px; } .legend { position: absolute; top: 10px; left: 10px; background: rgba(0, 0, 0, 0.8); padding: 15px; border-radius: 10px; font-size: 12px; } .legend-item { display: flex; align-items: center; margin-bottom: 5px; } .legend-color { width: 20px; height: 10px; margin-right: 10px; } </style> </head> <body> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background: #ff6b6b;"></div> Potential Well </div> <div class="legend-item"> <div class="legend-color" style="background: #4ecdc4;"></div> Wave Function ψ(x) </div> <div class="legend-item"> <div class="legend-color" style="background: #45b7d1;"></div> Probability |ψ(x)|² </div> <div class="legend-item"> <div class="legend-color" style="background: #96ceb4;"></div> Energy Level </div> </div> <div class="controls"> <div class="control-group"> <label for="wellWidth">Well Width: <span id="widthValue">200</span></label> <input type="range" id="wellWidth" min="100" max="300" value="200"> </div> <div class="control-group"> <label for="wellDepth">Well Depth: <span id="depthValue">100</span></label> <input type="range" id="wellDepth" min="50" max="200" value="100"> </div> <div class="control-group"> <label for="energyLevel">Energy Level (n): <span id="energyValue">1</span></label> <input type="range" id="energyLevel" min="1" max="5" value="1"> </div> <div class="control-group"> <label> <input type="checkbox" id="showProbability" checked> Show Probability </label> </div> <div class="control-group"> <label> <input type="checkbox" id="animateWave" checked> Animate Wave </label> </div> </div> <script> let wellWidth = 200; let wellDepth = 100; let energyLevel = 1; let showProbability = true; let animateWave = true; let time = 0; let centerX, centerY; function setup() { createCanvas(800, 600); centerX = width / 2; centerY = height / 2; // Connect controls connectControls(); } function draw() { background(20); if (animateWave) { time += 0.05; } // Draw coordinate system drawCoordinateSystem(); // Draw potential well drawPotentialWell(); // Draw energy level drawEnergyLevel(); // Draw wave function drawWaveFunction(); // Draw probability distribution if (showProbability) { drawProbabilityDistribution(); } // Draw labels drawLabels(); } function drawCoordinateSystem() { stroke(100); strokeWeight(1); // X-axis line(50, centerY, width - 50, centerY); // Y-axis (for potential) line(centerX - wellWidth/2 - 50, 100, centerX - wellWidth/2 - 50, height - 100); // Grid lines for (let i = 0; i < 10; i++) { let x = map(i, 0, 9, 50, width - 50); stroke(50); line(x, 100, x, height - 100); } } function drawPotentialWell() { stroke(255, 107, 107); strokeWeight(3); fill(255, 107, 107, 50); let wellLeft = centerX - wellWidth / 2; let wellRight = centerX + wellWidth / 2; let wellBottom = centerY + wellDepth; // Draw the potential well shape beginShape(); vertex(50, wellBottom); vertex(wellLeft, wellBottom); vertex(wellLeft, centerY); vertex(wellRight, centerY); vertex(wellRight, wellBottom); vertex(width - 50, wellBottom); endShape(); } function drawEnergyLevel() { let energy = calculateEnergyLevel(energyLevel); let energyY = centerY + wellDepth - energy; stroke(150, 203, 180); strokeWeight(2); line(centerX - wellWidth/2, energyY, centerX + wellWidth/2, energyY); // Energy label fill(150, 203, 180); noStroke(); textAlign(LEFT); text(`E${energyLevel} = ${energy.toFixed(1)}`, centerX + wellWidth/2 + 10, energyY); } function calculateEnergyLevel(n) { // Energy levels for infinite square well: E_n = (n²π²ℏ²)/(2mL²) // Simplified for visualization return wellDepth * (n * n) / 25; } function drawWaveFunction() { stroke(78, 205, 196); strokeWeight(2); noFill(); let wellLeft = centerX - wellWidth / 2; let wellRight = centerX + wellWidth / 2; let energy = calculateEnergyLevel(energyLevel); let energyY = centerY + wellDepth - energy; beginShape(); for (let x = wellLeft; x <= wellRight; x += 2) { let normalizedX = map(x, wellLeft, wellRight, 0, PI * energyLevel); let amplitude = 30 * sin(normalizedX) * cos(time); let y = energyY + amplitude; vertex(x, y); } endShape(); // Wave function extends beyond well (exponential decay) drawEvanescentWave(wellLeft, energyY, -1); drawEvanescentWave(wellRight, energyY, 1); } function drawEvanescentWave(startX, energyY, direction) { stroke(78, 205, 196, 150); strokeWeight(2); for (let i = 0; i < 50; i++) { let x = startX + direction * i * 2; if (x < 50 || x > width - 50) break; let amplitude = 30 * exp(-i * 0.05) * cos(time) * sin(PI * energyLevel); let y = energyY + amplitude; if (i === 0) { line(startX, energyY, x, y); } else { let prevX = startX + direction * (i - 1) * 2; let prevAmplitude = 30 * exp(-(i-1) * 0.05) * cos(time) * sin(PI * energyLevel); let prevY = energyY + prevAmplitude; line(prevX, prevY, x, y); } } } function drawProbabilityDistribution() { stroke(69, 183, 209); strokeWeight(2); fill(69, 183, 209, 100); let wellLeft = centerX - wellWidth / 2; let wellRight = centerX + wellWidth / 2; let energy = calculateEnergyLevel(energyLevel); let energyY = centerY + wellDepth - energy; beginShape(); vertex(wellLeft, energyY); for (let x = wellLeft; x <= wellRight; x += 2) { let normalizedX = map(x, wellLeft, wellRight, 0, PI * energyLevel); let probability = sin(normalizedX) * sin(normalizedX); let amplitude = 40 * probability; let y = energyY - amplitude; vertex(x, y); } vertex(wellRight, energyY); endShape(CLOSE); } function drawLabels() { fill(255); noStroke(); textAlign(CENTER); // Title textSize(16); text("Quantum Particle in a Potential Well", width/2, 30); // Axis labels textSize(12); text("Position (x)", width/2, height - 20); push(); translate(20, height/2); rotate(-PI/2); text("Energy / Potential", 0, 0); pop(); } function connectControls() { document.getElementById('wellWidth').addEventListener('input', (e) => { wellWidth = parseInt(e.target.value); document.getElementById('widthValue').textContent = wellWidth; }); document.getElementById('wellDepth').addEventListener('input', (e) => { wellDepth = parseInt(e.target.value); document.getElementById('depthValue').textContent = wellDepth; }); document.getElementById('energyLevel').addEventListener('input', (e) => { energyLevel = parseInt(e.target.value); document.getElementById('energyValue').textContent = energyLevel; }); document.getElementById('showProbability').addEventListener('change', (e) => { showProbability = e.target.checked; }); document.getElementById('animateWave').addEventListener('change', (e) => { animateWave = e.target.checked; }); } </script> </body> </html> ``` This interactive quantum mechanics simulation demonstrates several key concepts: **Key Features:** 1. **Potential Well Visualization** - Red barrier showing the confining potential 2. **Wave Functions** - Teal oscillating curves showing the quantum state 3. **Probability Distributions** - Blue filled areas showing |ψ(x)|² 4. **Energy Levels** - Green horizontal lines showing quantized energies 5. **Evanescent Waves** - Exponentially decaying waves outside the well **Interactive Controls:** - **Well Width**: Affects the spacing between energy levels - **Well Depth**: Changes the potential barrier height - **Energy Level (n)**: Select different quantum states (1-5) - **Show Probability**: Toggle probability distribution display - **Animate Wave**: Toggle time evolution of the wave function **Quantum Principles Illustrated:** 1. **Wave-Particle Duality** - Particles described by wave functions 2. **Quantization** - Only certain energy levels are allowed 3. **Tunneling** - Wave function extends beyond classical boundaries 4. **Probability Interpretation** - |ψ|² gives probability density 5. **Standing Wave Patterns** - Higher energy levels have more nodes The simulation shows how changing the well parameters affects the quantum states, demonstrating the fundamental relationship between confinement and quantization in quantum mechanics.
Drag to resize
```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Quantum Particle in a Finite Potential Well – p5.js demo</title> <!-- p5.js --> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script> <!-- numeric.js (matrix / eigen-solver) --> <script src="https://cdnjs.cloudflare.com/ajax/libs/numeric/1.2.6/numeric.min.js"></script> <style> body{ margin:0; background:#111; color:#ddd; font-family: monospace; } .ui{ position:absolute; top:8px; left:8px; background:rgba(0,0,0,.6); padding:8px 14px; border-radius:6px; } .ui label{ display:block; margin:4px 0 0 0; font-size:13px; } </style> </head> <body> <div class="ui" id="controls"> <label>Well depth V₀ (energy units)</label> <input type="range" id="depth" min="0" max="100" value="50" step="1"> <label>Well width a (space units)</label> <input type="range" id="width" min="100" max="600" value="300" step="10"> <label>State index n</label> <input type="range" id="state" min="1" max="5" value="1" step="1"> <div id="readout" style="margin-top:8px;"></div> </div> <script> /* Quantum particle in a 1-D finite square well • V(x) = -V0 for |x| < a/2 0 otherwise • ħ = m = 1 units • Hamiltonian built with a finite-difference Laplacian. • numeric.js supplies a (real) eigen-solver. • The sliders control: V0 – well depth (energy units) a – well width (space units – pixels here) n – which eigen-state to draw (1 = ground) • Canvas shows – grey curve : potential – blue curve : wave-function ψn(x) – red filled : |ψn(x)|² (probability density) The code rebuilds the Hamiltonian whenever any slider is moved, finds all eigen-pairs, and draws the chosen state (if it exists). */ // -------------------- GLOBALS -------------------- let N = 180; // # grid points let L = 800; // domain size in "space units" (will change) let dx; // grid spacing (computed each rebuild) let x = []; // coordinates array let V = []; // potential array let eigvals = []; // energies let eigvecs = []; // eigenvectors [N][N] let needRebuild = true; // flag // UI handles let depthSlider, widthSlider, stateSlider, readout; // -------------------- p5 ------------------------- function setup(){ createCanvas(800, 400); pixelDensity(2); // grab sliders created in HTML depthSlider = select('#depth'); widthSlider = select('#width'); stateSlider = select('#state'); readout = select('#readout'); // attach callbacks depthSlider.input(()=> needRebuild = true); widthSlider.input(()=> needRebuild = true); stateSlider.input(()=> needRebuild = true); buildSystem(); // first build } function draw(){ if(needRebuild) buildSystem(); background(17); translate(0, height/2); // move origin to vertical center // draw potential stroke(120); noFill(); beginShape(); for(let i=0;i<N;i++){ let y = -V[i]*2; // simple visual scale vertex(map(x[i],-L/2,L/2,0,width), y); } endShape(); let nIdx = stateSlider.value()-1; if(nIdx >= eigvals.length){ readout.html("No bound state at that index (increase depth)."); return; } let E = eigvals[nIdx]; let psi= eigvecs[nIdx]; // already normalized in buildSystem() readout.html( `Eₙ = ${E.toFixed(3)} (only negative energies ⇒ bound states)<br> bound states found = ${eigvals.length}`); // calculate scale so wave fits nicely let maxPsi = max(psi.map(v=>abs(v))); let yScale = 100 / maxPsi; // probability density |ψ|² (draw first so wave overlays) noStroke(); fill(255,0,0,60); beginShape(); vertex(0,0); for(let i=0;i<N;i++){ let xx = map(x[i],-L/2,L/2,0,width); let yy = -pow(psi[i],2)*yScale; vertex(xx,yy); } vertex(width,0); endShape(CLOSE); // wave-function stroke(0,150,255); noFill(); strokeWeight(1.5); beginShape(); for(let i=0;i<N;i++){ let xx = map(x[i],-L/2,L/2,0,width); let yy = -psi[i]*yScale; vertex(xx,yy); } endShape(); } // ------------------ QUANTUM PART ----------------- function buildSystem(){ needRebuild = false; // fetch current parameters let V0 = parseFloat(depthSlider.value()); // positive number let a = parseFloat(widthSlider.value()); // width in pixels (space units) // choose domain L a bit larger than the well so wave has room to decay L = max(800, a*1.6); dx = L/(N-1); // coordinate list & potential x=[]; V=[]; for(let i=0;i<N;i++){ let xi = -L/2 + i*dx; x.push(xi); V.push( Math.abs(xi) < a/2 ? -V0 : 0 ); // finite square well } // build Hamiltonian (tridiagonal) H = -½ d²/dx² + V(x) // with ħ = m = 1 → kinetic term -½ (ψ[i+1] -2ψ[i] + ψ[i-1])/dx² let diag = new Array(N).fill(0); let upper= new Array(N-1).fill(0); let lower= new Array(N-1).fill(0); let k = 1/(dx*dx); // convenience for(let i=0;i<N;i++){ diag[i] = k + V[i]; // -½*(-2)/dx² = 1/dx² if(i<N-1){ upper[i] = lower[i] = -0.5*k; // -½*(1)/dx² } } // convert to full dense matrix for numeric.eig let H = Array.from({length:N},()=>Array(N).fill(0)); for(let i=0;i<N;i++){ H[i][i] = diag[i]; if(i<N-1){ H[i][i+1] = upper[i]; H[i+1][i] = lower[i]; } } // eigen-decomposition let res = numeric.eig(H); let eig = res.lambda.x; // real parts (array length N) let vec = res.E.x; // columns are eigenvectors (N x N) // collect bound states (E < 0) eigvals = []; eigvecs = []; // numeric.eig doesn't sort, so build indexing let idx = eig.map((e,i)=>({e,i})) .filter(o=>o.e<0) // bound only .sort((a,b)=>a.e-b.e); // ascending energy (more negative first) idx.forEach(o=>{ eigvals.push(o.e); // grab eigenvector column, normalize ∫|ψ|² dx = 1 (discrete sum) let psi = []; let norm=0; for(let r=0;r<N;r++){ let v = vec[r][o.i]; psi.push(v); norm += v*v; } norm = Math.sqrt(norm*dx); // discrete ∑ |ψ|² dx psi = psi.map(v=>v/norm); eigvecs.push(psi); }); // update stateSlider max so user can pick existing state stateSlider.attribute('max', max(1, eigvals.length)); if(stateSlider.value() > eigvals.length) stateSlider.value(eigvals.length); // force redraw immediately redraw(); } </script> </body> </html> ```
Drag to resize
```html <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script> <script> let depthSlider, widthSlider, energySlider; function setup() { const canvas = createCanvas(800, 400); canvas.parent('canvasContainer'); depthSlider = createSlider(50, 400, 200, 10); depthSlider.position(20, 20); widthSlider = createSlider(50, width, 300, 5); widthSlider.position(20, 60); energySlider = createSlider(10, 390, 100, 5); energySlider.position(20, 100); createP('Potential Depth V0').position(20, 0); createP('Well Width (px)').position(20, 40); createP('Particle Energy E').position(20, 80); } function draw() { background(255); const V0 = depthSlider.value(); let wellWidth = widthSlider.value(); let E = energySlider.value(); if (E > V0 - 5) E = V0 -5; const x_center = width/2; const x_start = min(x_center - wellWidth/2, 700); const x_end = max(x_center + wellWidth/2, 100); const k = sqrt(E) * 0.05; const kappa = sqrt(V0 - E) * 0.05; const waveAmplitude = 20; // Draw potential well fill(200); noStroke(); rectMode(CORNERS); rect(0, 200, width, height); fill(255); rect(x_start, 200, x_end, height); // Draw energy level line stroke(255, 0, 0); const EY = map(E, 0, V0, 100, 195); line(0, EY, width, EY); // Draw wavefunction stroke(0, 0, 255); noFill(); beginShape(); for (let x = 0; x <= width; x++) { let x_well = x - x_start; let psi; if (x < x_start) { const distToStart = x_start - x; const decay = exp(-kappa * distToStart); psi = decay; } else if (x <= x_end) { psi = cos(k * x_well); } else { const distToStart = x_end - x_start; const decay = exp(-kappa * (x - x_end)); psi = cos(k * distToStart) * decay; } const y = EY - psi * waveAmplitude; vertex(x, y); } endShape(); // Draw probability distribution stroke(0, 255, 0, 150); beginShape(); for (let x = 0; x <= width; x++) { let x_well = x - x_start; let psi2; if (x < x_start) { const distToStart = x_start - x; const decay = exp(-kappa * distToStart); psi2 = decay * decay; } else if (x <= x_end) { psi2 = cos(k * x_well) * cos(k * x_well); } else { const distToStart = x_end - x_start; const decay = exp(-kappa * (x - x_end)); psi2 = cos(k * distToStart) * cos(k * distToStart) * decay * decay; } const y = EY - psi2 * 2 * waveAmplitude; vertex(x, y); } endShape(); } </script> <div id="canvasContainer"></div> ```
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Mechanics Simulation</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script> </head> <body> <script> let depth = 10; let width = 200; let energy = 1; function setup() { createCanvas(600, 400); background(220); frameRate(30); } function draw() { background(220); // Draw potential well noFill(); stroke(0); rect(width / 2 - width / 2, height / 2 - depth / 2, width, depth); // Calculate wave function and probability distribution let waveFunction = []; let probabilityDistribution = []; for (let x = 0; x < width; x++) { let psi = sin(energy * PI * x / width); let prob = psi * psi; waveFunction.push(psi); probabilityDistribution.push(prob); } // Normalize probability distribution let maxProb = max(probabilityDistribution); for (let i = 0; i < probabilityDistribution.length; i++) { probabilityDistribution[i] /= maxProb; } // Draw wave function and probability distribution noFill(); stroke(255, 0, 0); beginShape(); for (let x = 0; x < width; x++) { let y = height / 2 - waveFunction[x] * 50; vertex(width / 2 - width / 2 + x, y); } endShape(); stroke(0, 0, 255); beginShape(); for (let x = 0; x < width; x++) { let y = height / 2 - probabilityDistribution[x] * depth / 2; vertex(width / 2 - width / 2 + x, y); } endShape(); // Display controls fill(0); noStroke(); textSize(16); text(`Depth: ${depth}`, 20, 20); text(`Width: ${width}`, 20, 40); text(`Energy: ${energy}`, 20, 60); } function mouseWheel(event) { if (event.delta > 0) { energy += 0.1; } else { energy -= 0.1; energy = max(0.1, energy); } } function keyPressed() { if (key === 'd') { depth += 1; } if (key === 'a') { depth -= 1; depth = max(1, depth); } if (key === 'w') { width += 10; } if (key === 's') { width -= 10; width = max(10, width); } } </script> </body> </html> ``` This code creates a p5.js animation that simulates the behavior of particles in a potential well. The user can adjust the depth and width of the well, as well as the energy of the particles, using the 'd', 'a', 'w', and 's' keys. The energy can also be adjusted using the mouse wheel. The resulting probability distributions and wave functions are visualized in real-time.
Drag to resize