Hydrogen Atom & Energy Levels

Author

Shan

Published

March 24, 2026

The Hydrogen Atom

The hydrogen atom is the simplest bound quantum system — a single electron of charge \(-e\) bound to a proton of charge \(+e\) by the Coulomb potential: \[ V(r) = -\frac{e^2}{4\pi\epsilon_0 r} \] The time-independent Schrödinger equation in spherical coordinates is: \[ \left[ -\frac{\hbar^2}{2m_e}\nabla^2 + V(r) \right] \psi(r,\theta,\phi) = E\psi(r,\theta,\phi) \] Separating variables, the wavefunction factorizes as: \[ \psi_{n\ell m}(r,\theta,\phi) = R_{n\ell}(r)\, Y_\ell^m(\theta,\phi) \] where \(R_{n\ell}\) are the radial wavefunctions and \(Y_\ell^m\) are the spherical harmonics.


Energy Eigenvalues

Solving the radial equation yields the quantized energy levels: \[ E_n = -\frac{m_e e^4}{2\hbar^2} \cdot \frac{1}{(4\pi\epsilon_0)^2} \cdot \frac{1}{n^2} = -\frac{13.6 \text{ eV}}{n^2}, \quad n = 1, 2, 3, \ldots \] The ground state energy is \(E_1 = -13.6\ \text{eV}\). The negative sign reflects a bound state — energy must be supplied to ionize the atom. The ionization energy is therefore \(13.6\ \text{eV}\).

The Bohr radius sets the natural length scale: \[ a_0 = \frac{4\pi\epsilon_0\hbar^2}{m_e e^2} \approx 0.529\ \text{Å} \]


Python: Computing Energy Levels

Code
import numpy as np
import plotly.graph_objects as go

# Constants
E1 = -13.6  # eV, ground state energy

# Quantum numbers
n_vals = np.arange(1, 11)
E_n = E1 / n_vals**2

for n, E in zip(n_vals, E_n):
    print(f"n = {n:2d}  →  E = {E:8.4f} eV")
n =  1  →  E = -13.6000 eV
n =  2  →  E =  -3.4000 eV
n =  3  →  E =  -1.5111 eV
n =  4  →  E =  -0.8500 eV
n =  5  →  E =  -0.5440 eV
n =  6  →  E =  -0.3778 eV
n =  7  →  E =  -0.2776 eV
n =  8  →  E =  -0.2125 eV
n =  9  →  E =  -0.1679 eV
n = 10  →  E =  -0.1360 eV

Interactive Energy Level Diagram

Code
fig = go.Figure()
colors = ["#6C5CE7","#0984E3","#00B894","#FDCB6E","#E17055","#D63031","#A29BFE","#FD79A8","#55EFC4","#B2BEC3"]

# Draw energy levels as horizontal lines
for i, (n, E) in enumerate(zip(n_vals, E_n)):
    fig.add_shape(
        type="line",
        x0=0.1, x1=0.9,
        y0=E, y1=E,
        line=dict(color=colors[i], width=2.5)
    )
    fig.add_annotation(
        x=0.93, y=E,
        text=f"n={n}  {E:.2f} eV",
        showarrow=False,
        font=dict(size=11, color=colors[i]),
        xanchor="left"
    )

# Draw a few transitions (Lyman series, n→1)
lyman_upper = [2, 3, 4]
for n_upper in lyman_upper:
    E_upper = E1 / n_upper**2
    E_lower = E1
    delta_E = E_upper - E_lower
    wavelength_nm = 1240 / abs(delta_E)
    fig.add_annotation(
        x=0.5, y=(E_upper + E_lower) / 2,
        ax=0.5, ay=(E_upper + E_lower) / 2,
        axref="x", ayref="y",
        xref="x", yref="y",
        showarrow=True,
        arrowhead=2,
        arrowsize=1.2,
        arrowwidth=1.5,
        arrowcolor="#636E72",
        text=f"λ={wavelength_nm:.0f} nm",
        font=dict(size=9, color="#636E72"),
        xanchor="right"
    )

fig.update_layout(
    title="Hydrogen Atom Energy Levels",
    xaxis=dict(visible=False, range=[0, 1.4]),
    yaxis=dict(
        title="Energy (eV)",
        range=[-15, 1],
        tickvals=list(E_n[:6]),
        ticktext=[f"{E:.2f}" for E in E_n[:6]],
        gridcolor="rgba(150,150,150,0.15)"
    ),
    plot_bgcolor="white",
    paper_bgcolor="white",
    height=600,
    margin=dict(l=60, r=180, t=60, b=40),
    font=dict(family="serif")
)

fig.show()

Radial Wavefunctions

The first few radial wavefunctions \(R_{n\ell}(r)\) are: \[ R_{10}(r) = 2\left(\frac{1}{a_0}\right)^{3/2} e^{-r/a_0} \] \[ R_{20}(r) = \frac{1}{\sqrt{2}}\left(\frac{1}{2a_0}\right)^{3/2}\left(2 - \frac{r}{a_0}\right)e^{-r/2a_0} \] \[ R_{21}(r) = \frac{1}{\sqrt{24}}\left(\frac{1}{2a_0}\right)^{3/2}\frac{r}{a_0}\,e^{-r/2a_0} \]

Code
from scipy.special import genlaguerre, factorial

def R_nl(n, l, r_bohr):
    """Radial wavefunction R_nl(r), r in units of a0."""
    rho = 2 * r_bohr / n
    norm = np.sqrt(
        (2 / n)**3 * factorial(n - l - 1) /
        (2 * n * factorial(n + l)**3)
    )
    L = genlaguerre(n - l - 1, 2 * l + 1)(rho)
    return norm * np.exp(-rho / 2) * rho**l * L

r = np.linspace(0, 30, 1000)  # in units of a0

fig2 = go.Figure()

orbitals = [(1,0,"1s"), (2,0,"2s"), (2,1,"2p"), (3,0,"3s"), (3,1,"3p")]
palette  = ["#6C5CE7","#0984E3","#00B894","#E17055","#FDCB6E"]

for (n, l, label), color in zip(orbitals, palette):
    psi = R_nl(n, l, r)
    prob = r**2 * psi**2          # radial probability density

    fig2.add_trace(go.Scatter(
        x=r, y=prob,
        name=label,
        line=dict(color=color, width=2),
        hovertemplate=f"{label}<br>r = %{{x:.2f}} a₀<br>r²|R|² = %{{y:.4f}}<extra></extra>"
    ))

fig2.update_layout(
    title="Radial Probability Densities r²|R_{nl}|²",
    xaxis_title="r / a₀",
    yaxis_title="r² |R(r)|²",
    plot_bgcolor="white",
    paper_bgcolor="white",
    height=450,
    legend=dict(title="Orbital"),
    font=dict(family="serif")
)

fig2.show()

Transition Energies & Spectral Series

Photon energy for a transition \(n_i \to n_f\) follows from the Rydberg formula: \[ \Delta E = 13.6\left(\frac{1}{n_f^2} - \frac{1}{n_i^2}\right)\ \text{eV},\qquad \frac{1}{\lambda} = R_\infty\left(\frac{1}{n_f^2} - \frac{1}{n_i^2}\right) \] where \(R_\infty = 1.097 \times 10^7\ \text{m}^{-1}\) is the Rydberg constant.

Code
series = {
    "Lyman (UV, nf=1)":   (1, range(2, 8)),
    "Balmer (Vis, nf=2)": (2, range(3, 9)),
    "Paschen (IR, nf=3)": (3, range(4, 10)),
}

print(f"{'Series':<25} {'ni':>4} {'ΔE (eV)':>10} {'λ (nm)':>10}")
print("-" * 55)
for name, (nf, ni_range) in series.items():
    for ni in ni_range:
        dE  = 13.6 * (1/nf**2 - 1/ni**2)
        lam = 1240 / abs(dE)
        print(f"{name:<25} {ni:>4}   {dE:>9.3f}   {lam:>9.1f}")
    print()
Series                      ni    ΔE (eV)     λ (nm)
-------------------------------------------------------
Lyman (UV, nf=1)             2      10.200       121.6
Lyman (UV, nf=1)             3      12.089       102.6
Lyman (UV, nf=1)             4      12.750        97.3
Lyman (UV, nf=1)             5      13.056        95.0
Lyman (UV, nf=1)             6      13.222        93.8
Lyman (UV, nf=1)             7      13.322        93.1

Balmer (Vis, nf=2)           3       1.889       656.5
Balmer (Vis, nf=2)           4       2.550       486.3
Balmer (Vis, nf=2)           5       2.856       434.2
Balmer (Vis, nf=2)           6       3.022       410.3
Balmer (Vis, nf=2)           7       3.122       397.1
Balmer (Vis, nf=2)           8       3.188       389.0

Paschen (IR, nf=3)           4       0.661      1875.6
Paschen (IR, nf=3)           5       0.967      1282.2
Paschen (IR, nf=3)           6       1.133      1094.1
Paschen (IR, nf=3)           7       1.234      1005.2
Paschen (IR, nf=3)           8       1.299       954.9
Paschen (IR, nf=3)           9       1.343       923.2