1+ < meta charset ="UTF-8 ">
2+ <!-- Include Plotly.js from CDN -->
3+ < script src ="https://cdn.plot.ly/plotly-latest.min.js "> </ script >
4+ <!-- Include Math.js library for mathematical computations -->
5+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.5.0/math.min.js "> </ script >
6+ < style >
7+ # container {
8+ width : 110% ;
9+ margin : auto;
10+ padding : 20px ;
11+ transform : translateX (-5% ); /* This helps center the wider container */
12+ }
13+ # title {
14+ text-align : center;
15+ }
16+ # slider-container {
17+ width : 80% ;
18+ margin : auto;
19+ padding : 20px ;
20+ text-align : center;
21+ }
22+ # plot {
23+ width : 100% ;
24+ height : 600px ;
25+ }
26+ # n-display {
27+ font-weight : bold;
28+ }
29+ </ style >
30+
31+ < div id ="container ">
32+ < div id ="slider-container ">
33+ < label for ="n-slider "> Energy Level (n): < span id ="n-display "> 0</ span > </ label >
34+ < input type ="range " id ="n-slider " min ="0 " max ="100 " value ="0 " step ="1 " style ="width: 80%; ">
35+ </ div >
36+ < div id ="plot "> </ div >
37+ </ div >
38+
39+ < script >
40+ // Constants
41+ const N_POINTS = 1000 ;
42+ const RANGE_FACTOR = 1.2 ;
43+
44+ // Hermite Polynomial Function
45+ function hermite ( n , x ) {
46+ if ( n === 0 ) {
47+ return x . map ( ( ) => 1.0 ) ;
48+ } else if ( n === 1 ) {
49+ return x . map ( xi => 2 * xi ) ;
50+ } else {
51+ let h_prev = x . map ( ( ) => 1.0 ) ; // H_0
52+ let h_curr = x . map ( xi => 2 * xi ) ; // H_1
53+ let h_next = [ ] ;
54+
55+ for ( let i = 2 ; i <= n ; i ++ ) {
56+ h_next = x . map ( ( xi , idx ) => 2 * xi * h_curr [ idx ] - 2 * ( i - 1 ) * h_prev [ idx ] ) ;
57+ h_prev = h_curr ;
58+ h_curr = h_next ;
59+ }
60+ return h_curr ;
61+ }
62+ }
63+
64+ // Wavefunction ψₙ(x)
65+ function wavefunction ( n , x ) {
66+ // Normalization constant
67+ const normalization = 1.0 / ( Math . sqrt ( Math . pow ( 2 , n ) * math . factorial ( n ) * Math . sqrt ( Math . PI ) ) ) ;
68+ const hermite_n = hermite ( n , x ) ;
69+ return x . map ( ( xi , idx ) => normalization * hermite_n [ idx ] * Math . exp ( - xi * xi / 2 ) ) ;
70+ }
71+
72+ // Classical Position Distribution ρₙ(x)
73+ function classical_distribution ( n , x ) {
74+ const energy = n + 0.5 ;
75+ const result = x . map ( ( ) => 0 ) ;
76+ const mask = x . map ( xi => xi * xi < 2 * energy ) ;
77+ const denominator = x . map ( xi => Math . PI * Math . sqrt ( 2 * energy - xi * xi ) ) ;
78+
79+ return result . map ( ( val , idx ) => mask [ idx ] ? 1 / denominator [ idx ] : 0 ) ;
80+ }
81+
82+ // Get x-axis range
83+ function get_x_range ( n ) {
84+ const turning_point = Math . sqrt ( 2 * n + 1 ) ;
85+ const x_max = RANGE_FACTOR * turning_point ;
86+ return [ - x_max , x_max ] ;
87+ }
88+
89+ // Get y-axis max value
90+ function get_y_max ( probability ) {
91+ return Math . max ( ...probability ) ;
92+ }
93+
94+ // Update the plot
95+ function updatePlot ( n ) {
96+ const [ xmin , xmax ] = get_x_range ( n ) ;
97+ const x = Array . from ( { length : N_POINTS } , ( _ , i ) => xmin + i * ( xmax - xmin ) / ( N_POINTS - 1 ) ) ;
98+
99+ // Quantum probability
100+ const psi = wavefunction ( n , x ) ;
101+ const probability = psi . map ( psi_i => psi_i * psi_i ) ;
102+
103+ // Classical probability
104+ const classical_prob = classical_distribution ( n , x ) ;
105+
106+ // Y-axis range
107+ const y_max = get_y_max ( probability ) ;
108+ const y_range_max = y_max * RANGE_FACTOR ;
109+
110+ // Classical turning point
111+ const turning_point = Math . sqrt ( 2 * n + 1 ) ;
112+
113+ const data = [
114+ {
115+ x : x ,
116+ y : probability ,
117+ type : 'scatter' ,
118+ name : 'Quantum |ψₙ(x)|²' ,
119+ line : { color : 'blue' , width : 2 }
120+ } ,
121+ {
122+ x : x ,
123+ y : classical_prob ,
124+ type : 'scatter' ,
125+ name : 'Classical ρₙ(x)' ,
126+ line : { color : 'red' , width : 2 , dash : 'dot' }
127+ }
128+ ] ;
129+
130+ const layout = {
131+ title : `Quantum vs Classical Probability Distribution for n = ${ n } ` ,
132+ xaxis : {
133+ title : 'Position (x)' ,
134+ range : [ xmin , xmax ] ,
135+ showgrid : true ,
136+ gridwidth : 1 ,
137+ gridcolor : 'LightGray' ,
138+ zeroline : false ,
139+ showticklabels : false // Hide x-axis numerical values
140+ } ,
141+ yaxis : {
142+ title : 'Probability Density' ,
143+ range : [ 0 , y_range_max ] ,
144+ showgrid : true ,
145+ gridwidth : 1 ,
146+ gridcolor : 'LightGray'
147+ } ,
148+ showlegend : true ,
149+ hovermode : 'x' ,
150+ plot_bgcolor : 'white' ,
151+ margin : {
152+ l : 50 , // left margin
153+ r : 20 , // right margin
154+ t : 40 , // top margin
155+ b : 40 // bottom margin
156+ } ,
157+ shapes : [
158+ {
159+ type : 'line' ,
160+ x0 : turning_point ,
161+ y0 : 0 ,
162+ x1 : turning_point ,
163+ y1 : y_range_max ,
164+ line : {
165+ color : 'gray' ,
166+ width : 1 ,
167+ dash : 'dash'
168+ }
169+ } ,
170+ {
171+ type : 'line' ,
172+ x0 : - turning_point ,
173+ y0 : 0 ,
174+ x1 : - turning_point ,
175+ y1 : y_range_max ,
176+ line : {
177+ color : 'gray' ,
178+ width : 1 ,
179+ dash : 'dash'
180+ }
181+ }
182+ ] ,
183+ annotations : [
184+ {
185+ x : turning_point ,
186+ y : y_range_max * 0.95 ,
187+ xref : 'x' ,
188+ yref : 'y' ,
189+ text : 'Turning point' ,
190+ showarrow : false ,
191+ xanchor : 'left' ,
192+ font : {
193+ color : 'gray'
194+ }
195+ } ,
196+ {
197+ x : - turning_point ,
198+ y : y_range_max * 0.95 ,
199+ xref : 'x' ,
200+ yref : 'y' ,
201+ text : 'Turning point' ,
202+ showarrow : false ,
203+ xanchor : 'right' ,
204+ font : {
205+ color : 'gray'
206+ }
207+ }
208+ ]
209+ } ;
210+
211+ Plotly . newPlot ( 'plot' , data , layout ) ;
212+ }
213+
214+ // Initialize the plot
215+ updatePlot ( 0 ) ;
216+
217+ // Event listener for slider
218+ document . getElementById ( 'n-slider' ) . addEventListener ( 'input' , function ( ) {
219+ const n = parseInt ( this . value ) ;
220+ document . getElementById ( 'n-display' ) . innerText = n ;
221+ updatePlot ( n ) ;
222+ } ) ;
223+ </ script >
0 commit comments