html量子效果,HTML5 量子谐振子动画模拟

HTML

导入代码模板:

Quantum Harmonic Oscillator

.custombutton {

/* this class turns an ordinary link into a nice attractive push-button */

display: inline-block;

width: 92px;

height: 24px;

line-height: 24px;

font-size: 15px;

font-family: Arial, sans-serif;

text-align: center;

color: black;

background: -webkit-linear-gradient(white, #eeeeee, #eeeeee, #e0e0e0);

background: linear-gradient(white, #eeeeee, #eeeeee, #e0e0e0);

text-decoration: none;

border: 1px solid gray;

border-radius: 5px;

-webkit-user-select: none;

-moz-user-select: -moz-none;

-webkit-user-select: none;

-ms-user-select: none;

user-select: none;

cursor: pointer;

-webkit-tap-highlight-color: rgba(0, 0, 0, 0);

}

.custombutton:active {

background: -webkit-linear-gradient(#909090, #808080, #808080, #707070);

background: linear-gradient(#909090, #808080, #808080, #707070);

}

input[type=range] {

-webkit-user-select: none;

user-select: none;

}

sup {

position: relative;

vertical-align: bottom;

bottom: 0.4em;

font-size: 0.75em;

}

Quantum Harmonic Oscillator

Error!

Pause  Speed:

&nbsp

Real/imag 

Mag/phase

This simulation animates harmonic oscillator wavefunctions that are built from arbitrary superpositions of the lowest eight definite-energy wavefunctions. The “clock faces” show phasor diagrams for the complex amplitudes of these eight

basis functions, going from the ground state at the left to the seventh excited state at the right, with the outside of each “clock” corresponding to a magnitude of 1. The current wavefunction is then built by summing the eight

basis functions, multiplied by their corresponding complex amplitudes. As time passes, each basis amplitude rotates in the complex plane at a frequency proportional to the corresponding energy.

You can plot either the real and imaginary parts of the wavefunction (shown in orange and blue, respectively), or the magnitude and phase, with the phase represented by hues going from red (pure real and positive) to light green (pure imaginary

and positive) to cyan (pure real and negative) to purple (pure imaginary and negative) and finally back to red.

Click on any clock face to change the corresponding amplitude. To see an individual basis function, click “zero” and then click on the corresponding clock face. You can also create a coherent state (or an approximation thereof), which oscillates back and forth somewhat like a classical particle would. The parameter α determines the amplitude of this oscillation, with α2 equal to the average number of energy units

above the ground state. For large values of α, however, the true coherent state is not well approximated using only the lowest eight basis states.

By Daniel V. Schroeder,

Physics Dept.,

Weber State University

More physics software

var theCanvas = document.getElementById("theCanvas");

var theContext = theCanvas.getContext("2d");

var pauseButton = document.getElementById("pauseButton");

var speedSlider = document.getElementById("speedSlider");

var realImag = document.getElementById("realImag");

var alphaSlider = document.getElementById("alphaSlider");

var alphaReadout = document.getElementById("alphaReadout");

var iMax = theCanvas.width; // max index in function arrays (so array size is iMax+1)

var pxPerX = 60; // number of pixels per conventional x unit

var clockSpaceFraction = 0.25; // fraction of vertical space taken up by clocks

var clockRadiusFraction = 0.45; // as fraction of width or height of clock space

var psi = {

re: (new Array(iMax + 1)),

im: (new Array(iMax + 1))

}

var nMax = 7; // maximum energy quantum number

var eigenPsi = new Array(nMax + 1);

var amplitude = new Array(nMax + 1); // amplitudes of the eigenfunctions in psi

var phase = new Array(nMax + 1); // phases of the eigenfunctions in psi

var nColors = 360;

var phaseColor = new Array(nColors + 1);

var running = true;

var mouseIsDown = false;

var mouseClock;

theCanvas.addEventListener('mousedown', mouseDown, false);

document.body.addEventListener('mousemove', mouseMove, false);

document.body.addEventListener('mouseup', mouseUp, false); // button release could occur outside canvas

theCanvas.addEventListener('touchstart', mouseDown, false);

document.body.addEventListener('touchmove', mouseMove, false);

document.body.addEventListener('touchend', mouseUp, false);

init();

nextFrame();

function init() {

// Initialize eigenfunctions (simple harmonic oscillator):

for (var n = 0; n <= nMax; n++) {

eigenPsi[n] = new Array(iMax + 1);

}

for (var i = 0; i <= iMax; i++) {

var x = (i - iMax / 2) / pxPerX;

eigenPsi[0][i] = Math.exp(-x * x / 2);

eigenPsi[1][i] = Math.sqrt(2) * x * eigenPsi[0][i];

eigenPsi[2][i] = (1 / Math.sqrt(2)) * (2 * x * x - 1) * eigenPsi[0][i];

eigenPsi[3][i] = (1 / Math.sqrt(3)) * (2 * x * x * x - 3 * x) * eigenPsi[0][i];

eigenPsi[4][i] = (1 / Math.sqrt(24)) * (4 * x * x * x * x - 12 * x * x + 3) * eigenPsi[0][i];

eigenPsi[5][i] = (1 / Math.sqrt(60)) * (4 * x * x * x * x * x - 20 * x * x * x + 15 * x) * eigenPsi[0][i];

eigenPsi[6][i] = (1 / Math.sqrt(720)) * (8 * x * x * x * x * x * x - 60 * x * x * x * x + 90 * x * x - 15) * eigenPsi[0][i];

eigenPsi[7][i] = (1 / Math.sqrt(36 * 70)) * (8 * x * x * x * x * x * x * x - 84 * x * x * x * x * x + 210 * x * x * x - 105 * x) * eigenPsi[0][i];

}

// Initialize amplitudes and phases:

for (var n = 0; n <= nMax; n++) {

amplitude[n] = 0;

phase[n] = 0;

}

amplitude[0] = 1 / Math.sqrt(2);

amplitude[1] = 1 / Math.sqrt(2);

// Initialize array of colors to represent phases:

for (var c = 0; c <= nColors; c++) {

phaseColor[c] = colorString(c / nColors);

}

}

function nextFrame() {

for (var n = 0; n <= nMax; n++) {

phase[n] -= (n + 0.5) * Number(speedSlider.value);

if (phase[n] < 0) phase[n] += 2 * Math.PI;

}

buildPsi();

paintCanvas();

if (running) window.setTimeout(nextFrame, 1000 / 30);

}

function buildPsi() {

for (var i = 0; i <= iMax; i++) {

psi.re[i] = 0;

psi.im[i] = 0;

}

for (var n = 0; n <= nMax; n++) {

var realPart = amplitude[n] * Math.cos(phase[n]);

var imagPart = amplitude[n] * Math.sin(phase[n]);

for (var i = 0; i <= iMax; i++) {

psi.re[i] += realPart * eigenPsi[n][i];

psi.im[i] += imagPart * eigenPsi[n][i];

}

}

}

function mouseDown(e) {

var clockSpaceHeight = theCanvas.height * clockSpaceFraction;

var clockPixelRadius = clockSpaceHeight * clockRadiusFraction;

if (e.pageY - theCanvas.offsetTop > theCanvas.height - clockSpaceHeight) {

mouseClock = Math.floor((e.pageX - theCanvas.offsetLeft) / clockSpaceHeight);

var clockCenterX = clockSpaceHeight * (mouseClock + 0.5); // relative to left of canvas

var clockCenterY = theCanvas.height - clockSpaceHeight * 0.5; // relative to top of canvas

var relX = e.pageX - theCanvas.offsetLeft - clockCenterX;

var relY = clockCenterY - (e.pageY - theCanvas.offsetTop); // measured up from clock center

var pixelDistance2 = relX * relX + relY * relY;

if (pixelDistance2 <= clockPixelRadius * clockPixelRadius) {

e.preventDefault();

mouseIsDown = true;

amplitude[mouseClock] = Math.sqrt(pixelDistance2) / clockPixelRadius;

phase[mouseClock] = Math.atan2(relY, relX);

if (phase[mouseClock] < 0) phase[mouseClock] += 2 * Math.PI;

buildPsi();

paintCanvas();

}

}

}

function mouseMove(e) {}

function mouseUp(e) {

mouseIsDown = false;

}

function paintCanvas() {

theContext.fillStyle = "black";

theContext.fillRect(0, 0, theCanvas.width, theCanvas.height);

var baselineY, pxPerY;

if (realImag.checked) {

baselineY = theCanvas.height * (1 - clockSpaceFraction) / 2;

pxPerY = baselineY * 0.9;

// Draw the horizontal axis:

theContext.strokeStyle = "gray";

theContext.lineWidth = 1;

theContext.beginPath();

theContext.moveTo(0, baselineY);

theContext.lineTo(theCanvas.width, baselineY);

theContext.stroke();

theContext.lineWidth = 2;

// Plot the real part of psi:

theContext.beginPath();

theContext.moveTo(0, baselineY - psi.re[0] * pxPerY);

for (var i = 1; i <= iMax; i++) {

theContext.lineTo(i, baselineY - psi.re[i] * pxPerY);

}

theContext.strokeStyle = "#ffc000";

theContext.stroke();

// Plot the imaginary part of psi:

theContext.beginPath();

theContext.moveTo(0, baselineY - psi.im[0] * pxPerY);

for (var i = 1; i <= iMax; i++) {

theContext.lineTo(i, baselineY - psi.im[i] * pxPerY);

}

theContext.strokeStyle = "#00d0ff";

theContext.stroke();

} else { // "Mag/phase" is checked

// Plot the probability distribution with phase as color:

baselineY = theCanvas.height * (1 - clockSpaceFraction);

pxPerY = baselineY * 0.55;

theContext.lineWidth = 2;

for (var i = 0; i <= iMax; i++) {

theContext.beginPath();

theContext.moveTo(i, baselineY);

theContext.lineTo(i, baselineY - pxPerY * (psi.re[i] * psi.re[i] + psi.im[i] * psi.im[i]));

var localPhase = Math.atan2(psi.im[i], psi.re[i]);

if (localPhase < 0) localPhase += 2 * Math.PI;

theContext.strokeStyle = phaseColor[Math.round(localPhase * nColors / (2 * Math.PI))];

theContext.stroke();

}

}

// Draw the eigen-phasor diagrams:

var phasorSpace = theCanvas.height * clockSpaceFraction;

var clockRadius = phasorSpace * clockRadiusFraction;

for (var n = 0; n <= nMax; n++) {

theContext.strokeStyle = "gray";

theContext.lineWidth = 1;

theContext.beginPath();

var centerX = (n + 0.5) * phasorSpace;

var centerY = theCanvas.height - 0.5 * phasorSpace;

theContext.arc(centerX, centerY, clockRadius, 0, 2 * Math.PI);

theContext.stroke();

theContext.beginPath();

theContext.moveTo(centerX, centerY);

var clockHandX = centerX + clockRadius * amplitude[n] * Math.cos(phase[n]);

var clockHandY = centerY - clockRadius * amplitude[n] * Math.sin(phase[n]);

theContext.lineTo(clockHandX, clockHandY);

theContext.strokeStyle = phaseColor[Math.round(phase[n] * nColors / (2 * Math.PI))];

theContext.lineWidth = 3;

theContext.stroke();

}

}

function startStop() {

running = !running;

if (running) {

pauseButton.innerHTML = "Pause";

nextFrame();

} else {

pauseButton.innerHTML = "Resume";

}

}

function zero() {

for (var n = 0; n <= nMax; n++) {

amplitude[n] = 0;

}

buildPsi();

paintCanvas();

}

function normalizePsi() {

var norm2 = 0;

for (var n = 0; n <= nMax; n++) {

norm2 += amplitude[n] * amplitude[n];

}

if (norm2 > 0) {

for (var n = 0; n <= nMax; n++) {

amplitude[n] /= Math.sqrt(norm2);

}

buildPsi();

paintCanvas();

}

}

function coherent() {

var alphaMag = Number(alphaSlider.value);

var nFact = 1;

for (var n = 0; n <= nMax; n++) {

if (n > 0) nFact *= n;

amplitude[n] = Math.pow(alphaMag, n) / Math.sqrt(nFact);

phase[n] = 0;

}

normalizePsi();

}

function adjustAlpha() {

alphaReadout.innerHTML = Number(alphaSlider.value).toFixed(1);

}

// Function to convert a number to a two-digit hex string (from stackoverflow):

function twoDigitHex(c) {

var hex = c.toString(16);

return hex.length == 1 ? "0" + hex : hex;

}

// Function to create a hex color string for a given hue (between 0 and 1):

function colorString(hue) {

var r, g, b;

if (hue < 1 / 6) {

r = 255;

g = Math.round(hue * 6 * 255);

b = 0; // red to yellow

} else if (hue < 1 / 3) {

r = Math.round((1 / 3 - hue) * 6 * 255);

g = 255;

b = 0; // yellow to green

} else if (hue < 1 / 2) {

r = 0;

g = 255;

b = Math.round((hue - 1 / 3) * 6 * 255); // green to cyan

} else if (hue < 2 / 3) {

r = 0;

g = Math.round((2 / 3 - hue) * 6 * 255);

b = 255; // cyan to blue

} else if (hue < 5 / 6) {

r = Math.round((hue - 2 / 3) * 6 * 255);

g = 0;

b = 255; // blue to magenta

} else {

r = 255;

g = 0;

b = Math.round((1 - hue) * 6 * 255); // magenta to red

}

return "#" + twoDigitHex(r) + twoDigitHex(g) + twoDigitHex(b);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值