layout: post title: 一维谐振子薛定谔方程的数值解 categories:
对微分方程
$$\left({d^2 \over dx^2}+f(x)\right) y(x)=0$$
可采用努梅罗夫方法 求其数值解. 求解时, 先对 $x$ 进行均匀离散化. 若已知前面两点 $$x_{n-1}$$, $$xn$$ 的解 $$y{n-1}$$, $y_n$, 则后一点的解可写为
$$y_{n+1}={[24-10f(x_n) h^2]yn - [12+f(x{n-1}) h^2] y{n-1} \over 12+f(x{n+1}) h^2 }$$
其中 $h=xn-x{n-1}$ 为离散间距.
一维薛定谔方程可写为如下形式:
$$\alg -{\hbar^2 \over 2\m}{d^2 \over dx^2}\Y+V\Y=E\Y \ {d^2 \over dx^2}\Y+{2\m (E-V) \over \hbar^2}\Y=0 \ \left( {d^2 \over dx^2}+{2\m (E-V) \over \hbar^2} \right)\Y=0 \ealg$$
与上面的微分方程对比可知
$$f(x)={2\m (E-V) \over \hbar^2}$$
因此可利用此方法求解任意势能函数下一维薛定谔方程的数值解. 下面是用于求解一维谐振子薛定谔方程的小程序, 可用于求解其能量本征值.
<div id="ctn" style="border:dotted 5px #ccc;width:600px"></div> 质量<input type="box" id="mass" value="1"> 能量<input type="box" id="tryEng" value="0.5"> 步长<input type="box" id="step" value="0.01"> Xmin<input type="box" id="minX" value="-5"> Xmax<input type="box" id="maxX" value="5"><br>
<input type="button" id="play" value="求解">
<input type="button" id="stop" value="暂停"> <script> var $=function(id){return document.getElementById(id)}; var i=0, mass, dX, hsq, tryEng, minX, maxX, x, y, facX, facY, facPot, minPot, maxPot, norm, pntNum, Y=[], points=[] mass=parseFloat($("mass").value) tryEng=parseFloat($('tryEng').value) dX=parseFloat($("step").value) minX=parseFloat($("minX").value) maxX=parseFloat($("maxX").value) hsq=dX*dX pntNum=parseInt((maxX-minX)/dX)+1 function pot(x) { return 0.5*x*x } function V(x) { return 2*(tryEng-pot(x))*mass } function getY() { mass=parseFloat($("mass").value) tryEng=parseFloat($('tryEng').value) dX=parseFloat($("step").value) minX=parseFloat($("minX").value) maxX=parseFloat($("maxX").value) hsq=dX*dX pntNum=parseInt(Math.abs(maxX-minX)/dX)+1 facX=2*cx/Math.abs(maxX-minX) facY=cy Y[0]=1E-9; Y[1]= (24-10*V(minX)*hsq)*Y[0] / (12+V(minX+dX)*hsq) x=minX+dX norm=Y[0]*Y[0]+Y[1]*Y[1] for(i=2; i<pntNum; i++) { x += dX Y[i] = ( (24-10*V(x-dX)*hsq)*Y[i-1] - (12+V(x-2*dX)*hsq)*Y[i-2] )/(12+V(x)*hsq) norm += Y[i]*Y[i] } norm=1/Math.sqrt(norm*dX) for(i=0; i<pntNum; i++) Y[i]*=norm // console.log(Y) } var stage = new Kinetic.Stage({ container: 'ctn', width: 600, height: 600 }); var layer = new Kinetic.Layer(); stage.add(layer); var cx=stage.getWidth()/2; var cy=stage.getHeight()/2; facX=2*cx/(maxX-minX) facY=cy var potCurve = new Kinetic.Shape({ stroke: '#880000', strokeWidth: 2, drawFunc: function(context) { minPot=1E10; maxPot=-1E10 for(i=0; i<pntNum; i++) { x = (minX+i*dX) y = pot(x) if(y<minPot) minPot=y else if(y>maxPot) maxPot=y } facPot=cy/(maxPot-minPot) context.beginPath(); for(i=0; i<pntNum; i++) { x = (minX+i*dX) y = -pot(x) x = x*facX+cx y=y*facPot+cy context.lineTo(x, y); } context.closePath(); context.strokeShape(this); } }); layer.add(potCurve) var axis = new Kinetic.Shape({ stroke: 'black', strokeWidth: 2, drawFunc: function(context) { context.beginPath(); context.moveTo(cx, 0); context.lineTo(cx, 2*cy); context.moveTo(0, cy); context.lineTo(2*cx, cy); for(i=0; i<pntNum; i += 10) { x = (minX+i*dX) y = -maxPot/40 x = x*facX+cx y=y*facPot+cy context.moveTo(x, cy); context.lineTo(x, y); } context.closePath(); context.strokeShape(this); } }); layer.add(axis) var tryLine = new Kinetic.Shape({ stroke: 'red', strokeWidth: 2, drawFunc: function(context) { context.beginPath(); y=-tryEng context.moveTo(0, y*facPot+cy) context.lineTo(2*cx, y*facPot+cy); context.closePath(); context.strokeShape(this); } }); layer.add(tryLine) var circ = new Kinetic.Circle({ x: cx, y: cy, radius: 5, fill: 'red', stroke: 'red' }); layer.add(circ); var pen = new Kinetic.Circle({ x: 0, y: cy, radius: 5, fill: 'blue', stroke: 'blue' }); layer.add(pen); var line=new Kinetic.Line({ points:[0,0,0,0], stroke:"blue", strokeWidth:4 }); layer.add(line); layer.draw() var anim = new Kinetic.Animation( function (frame) { var i=parseInt(frame.time) if(i<pntNum) { x = (minX+i*dX)*facX+cx y = -Y[i]*facY+cy points.push(x, y); line.setPoints(points); pen.setX(x); pen.setY(y); } else { anim.stop() points=[]; frame.time=0 } }, layer); $('play').addEventListener('click', function() { getY(); anim.start();}, false); $('stop').addEventListener('click', function() { anim.stop(); }, false); </script>