Light quanta · Radiation spectrum and regime comparison

Where Wien's law holds, and where it stops.

What does a measured radiation spectrum look like at a given temperature, in which regime is Wien's law or the classical law an accurate description, and what does a density plot actually measure?

Radiation spectrum and regime comparison

The radiation spectrum and regime comparison

Static worked example

Model note
  • Frequency-basis spectral energy density (frequencyEnergyDensity), Peak frequency (peakFrequency) and Peak wavelength (peakWavelength): Host calculation, by the site's own reference code. Computed in radiation.spectra.
  • Band-integrated radiation energy (bandEnergy): Host calculation, by the site's own reference code. Computed in radiation.bandIntegration.
  • Computed from the settings last applied (settings revision 1, result 1).
  • Not modeled: emissivity and cavity imperfections; detector and spectrometer response; polarization; non-equilibrium radiation; any photon or quantum-statistical model beyond the displayed formulas.

What does a measured radiation spectrum look like at a given temperature, in which regime is Wien's law or the classical law an accurate description, and what does a density plot actually measure?

Spectrum settings
Experiment settings axis scale, which laws are drawn, the band, the probe frequency, the regime tolerance
The spectrum at T = 5000 K: energy density per hertz, uν, against frequency, on logarithmic axes. Planck's curve peaks at 2.94 × 10¹⁴ Hz. Wien's law meets Planck's at high frequency (short wavelength); the classical law meets it at low frequency (long wavelength) and keeps rising where Planck's falls.10¹¹10¹²10¹³10¹⁴10¹⁵10¹⁶10⁻²⁰10⁻¹⁹10⁻¹⁸10⁻¹⁷10⁻¹⁶10⁻¹⁵Frequency ν (Hz)peakprobe
  • Planck 1900
  • Wien 1896
  • Classical §1
Energy density per hertz, uν, in J m⁻³ Hz⁻¹, on logarithmic axes. The shaded strip is the band; the dashed vertical line is the probe frequency.

Spectral densities at the probe frequency

Values at ν = 6.0000 × 1014 Hz, T = 5000 K. Wavelength density is the Jacobian-transformed value, never a bare substitution of λ = c/ν.
Lawuν (J·m⁻³·Hz⁻¹)uλ (J·m⁻⁴)
Planck 19004.223940 × 10−16 J/(m³ Hz)5.072237 × 105 J/(m³ m)
Wien 18964.210617 × 10−16 J/(m³ Hz)5.056239 × 105 J/(m³ m)
Classical §12.318107 × 10−14 J/(m³ Hz)2.783655 × 107 J/(m³ m)

Band energy: identical across representations

From the frequency integral: 0.1286853 J/m³. From the wavelength integral over the same physical band: 0.1286853 J/m³. These agree because the Jacobian is applied; a relabeled axis without it would not agree (see “Show the code”).

Peak locations: representation-dependent, and why

Frequency-density peak νpeak2.939463 × 1014 Hz
Wavelength-density peak λpeak5.795544 × 10−7 m
c / λpeak (NOT the frequency-density peak)5.172810 × 1014 Hz
Per-natural-log-interval peak (x = 3.9206904)4.084697 × 1014 Hz

The frequency-density peak and c divided by the wavelength-density peak are different numbers on purpose: uλ and uν are different functions related by a Jacobian, so their maxima do not correspond under λ = c/ν.

Wien and classical regime verdict

At this temperature and probe frequency, x = hν/(kBT) = 5.759092. Wien's law's relative error here is 0.0031540; the classical law's relative error is 53.880, so it gives 54.880 times Planck's value. In the Wien regime at this temperature and frequency.

This pointwise error is not a certificate for the light paper's integrated entropy argument (§4), which holds only within its own stated limits.

Not modeled: emissivity and cavity imperfections; detector and spectrometer response; polarization; non-equilibrium radiation; any photon or quantum-statistical model beyond the displayed formulas.

The same action without dragging, color, or a canvas

Every action here is typed text entry and a text result: type the temperature, the band edges and the probe frequency, choose the representation from the select lists above, and read the band-energy and peak tables and the regime verdict sentence. The spectrum drawing shows the same densities; its description names the peak, and the three laws differ by line pattern, not colour. No control depends on dragging a handle, distinguishing color alone, or reading a canvas.

A hot body glows at every frequency, most brightly in a middle range that moves higher as the body gets hotter. Wien's formula matches the glow closely at high frequencies and the older classical rule matches it at low ones, and each fails badly where the other works.

Section 1 derives what Maxwell's theory and the electron theory predict for radiation in equilibrium with resonators and a gas: each resonator carries a mean energy (R/N)T, and Planck's relation between resonator and radiation then gives ρν = (R/N)(8πν2/L3)T. Einstein says this law disagrees with experience and makes the total energy infinite. Section 2 takes Planck's formula, ρν = αν3/(eβν/T − 1), which fits all experience so far; for large T/ν it becomes the law of Section 1, and matching the two gives N = 6.17 × 1023. Section 4 works in the opposite limit with Wien's law, ρ = αν3e−βν/T, confirmed for large ν/T, keeping in mind that its results hold only within limits. The instrument draws all three. At 5000 K and a probe at 600 THz, where x = hν/kBT = 5.76, Wien's law is 0.32 percent below Planck's and the classical law gives 54.9 times Planck's value; within a 1 percent tolerance Wien's law holds for x above 4.61 and the classical law for x below 0.0199. The peak depends on how the density is measured: per unit frequency at 294 THz, per unit wavelength at 580 nm, per logarithmic interval at 408 THz. The energy in a band, 0.129 J/m3 between 400 and 600 THz, is the same whichever axis is used.

Modern qualifications

Einstein wrote L for the speed of light and ρν for the density per unit frequency, with Planck's constants α and β, β = 4.866 × 10−11 (the exponent of α on the plate is read as −56 on a single witness, where the N he states needs −57). He gave the divergence no name, the textbook name for it being Ehrenfest's of 1911, and he names no one for the classical law: Rayleigh had argued for a density growing as ν2T at long wavelengths in June 1900, and Jeans's correction of the coefficient came in 1905. Wien's law dates from 1896 and Planck's formula from October 1900. The value N = 6.17 × 1023 is Planck's own; Einstein's point in Section 2 is that it follows from the long-wavelength limit alone, without Planck's theory of resonators.

Show the code

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

planckFrequencyEnergyDensity · src/physics/reference/radiation/spectra.ts · this site’s source, as built · sha256:d3a25d58cb1c5886f7c5f2582d305e3bdd7e3381fa26f490935e8bf73ca136b4

This function computes the listed outputs when it runs.

In words

u_nu = (8 pi h nu^3 / c^3) divided by (e^x - 1), with x = h nu / (k_B T). The first factor is the same mode count the classical law uses; everything that distinguishes Planck from Rayleigh and Jeans is in the second. Measured at 600 THz and 5800 K it returns 9.383671111056491 times 10^-16 J per cubic metre per hertz, where the classical law gives 2.689 times 10^-14 and Wien's gives 9.318 times 10^-16.

Implementation

/** Planck frequency energy density u_nu (J m^-3 Hz^-1). */
export function planckFrequencyEnergyDensity(
  nu: CyclicFrequency | number,
  T: number,
  set: ConstantSet,
): RadiationResult<number> {
  const quantityId = "frequencyEnergyDensity";
  const unit = "J/(m^3 Hz)";
  if (!Number.isFinite(nu) || nu <= 0) return refuseNonpositive("frequency", nu, quantityId, unit);
  if (!Number.isFinite(T) || T <= 0) return refuseNonpositive("temperature", T, quantityId, unit);

  const { h, c, kB } = getBasePhysicsConstants(set);
  const x = (h * nu) / (kB * T);

  // u_nu = (8 * pi * h * nu^3 / c^3) * (1 / (e^x - 1))
  const lnPrefactor = Math.log(8 * Math.PI * h) + 3 * Math.log(nu) - 3 * Math.log(c);
  let lnFactor: number;
  if (x > 50) {
    lnFactor = -x - Math.log1p(-Math.exp(-x));
  } else if (x < 1e-4) {
    lnFactor = -Math.log(Math.expm1(x));
  } else {
    lnFactor = -Math.log(Math.expm1(x));
  }

  const lnU = lnPrefactor + lnFactor;
  const packed = packLogRepresentation(lnU, "frequency");

  return {
    status: "value",
    quantityId,
    unit,
    value: packed.value,
    linearRepresentable: packed.linearRepresentable,
    ...packed.logFields,
  };
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

wienFrequencyEnergyDensity · src/physics/reference/radiation/spectra.ts · this site’s source, as built · sha256:bdf403193622426ca6356e97cd28d4f762d7ede397f10650087d7214678c397f

This function computes the listed outputs when it runs.

In words

Wien's spectrum, (8 pi h nu^3 / c^3) times e to the minus x, with x = h nu / (k_B T). It is Planck's expression with the minus one dropped from the denominator, which is why the two agree wherever the exponential is large, and it is computed in logarithms for the same reason Planck's is.

Implementation

/** Wien frequency energy density u_nu (J m^-3 Hz^-1). */
export function wienFrequencyEnergyDensity(
  nu: CyclicFrequency | number,
  T: number,
  set: ConstantSet,
): RadiationResult<number> {
  const quantityId = "frequencyEnergyDensity";
  const unit = "J/(m^3 Hz)";
  if (!Number.isFinite(nu) || nu <= 0) return refuseNonpositive("frequency", nu, quantityId, unit);
  if (!Number.isFinite(T) || T <= 0) return refuseNonpositive("temperature", T, quantityId, unit);

  const { h, c, kB } = getBasePhysicsConstants(set);
  const x = (h * nu) / (kB * T);

  // u_nu = (8 * pi * h * nu^3 / c^3) * e^-x
  const lnU = Math.log(8 * Math.PI * h) + 3 * Math.log(nu) - 3 * Math.log(c) - x;
  const packed = packLogRepresentation(lnU, "frequency");

  return {
    status: "value",
    quantityId,
    unit,
    value: packed.value,
    linearRepresentable: packed.linearRepresentable,
    ...packed.logFields,
  };
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

rayleighJeansFrequencyEnergyDensity · src/physics/reference/radiation/spectra.ts · this site’s source, as built · sha256:72f42d8291a9769560bd3921b345d5adf0bb31fbfdb729e5766833f81a9a7751

This function computes the listed outputs when it runs.

In words

The classical spectrum, (8 pi nu^2 / c^3) times k_B T: the number of modes at this frequency multiplied by the equipartition energy of each. The Planck constant does not appear, which is the point of showing it beside the other two.

Implementation

/** Rayleigh-Jeans frequency energy density u_nu (J m^-3 Hz^-1). */
export function rayleighJeansFrequencyEnergyDensity(
  nu: CyclicFrequency | number,
  T: number,
  set: ConstantSet,
): RadiationResult<number> {
  const quantityId = "frequencyEnergyDensity";
  const unit = "J/(m^3 Hz)";
  if (!Number.isFinite(nu) || nu <= 0) return refuseNonpositive("frequency", nu, quantityId, unit);
  if (!Number.isFinite(T) || T <= 0) return refuseNonpositive("temperature", T, quantityId, unit);

  const { c, kB } = getBasePhysicsConstants(set);

  // u_nu = (8 * pi * nu^2 / c^3) * k_B * T
  const lnU = Math.log(8 * Math.PI * kB * T) + 2 * Math.log(nu) - 3 * Math.log(c);
  const packed = packLogRepresentation(lnU, "frequency");

  return {
    status: "value",
    quantityId,
    unit,
    value: packed.value,
    linearRepresentable: packed.linearRepresentable,
    ...packed.logFields,
  };
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

planckBandEnergyDensity · src/physics/reference/radiation/bandIntegration.ts · this site’s source, as built · sha256:67db96ef0d7c4d6b2fb9465408df41c4ccc69ccaed656905ed2ed1e121788cfd

This function computes the listed outputs when it runs.

In words

It integrates the Planck density from one frequency bound to the other with adaptive Gauss-Kronrod quadrature: fifteen points per interval, and each interval split in two whenever the fifteen-point and seven-point estimates disagree by more than a relative 10^-12. At 5800 K the band from 400 to 790 THz comes back as 0.376 J/m^3, which is 43.9 per cent of everything the spectrum holds. Three refusals come first: a bound at or below zero, a range whose upper bound is not above its lower, and a nonpositive temperature.

Implementation

/** Integral of Planck spectrum over frequency band [nuMin, nuMax]. */
export function planckBandEnergyDensity(
  nuMin: CyclicFrequency | number,
  nuMax: CyclicFrequency | number,
  T: number,
  set: ConstantSet,
): RadiationResult<number> {
  const quantityId = "bandEnergy";
  const unit = "J/m^3";
  if (!Number.isFinite(nuMin) || nuMin <= 0 || !Number.isFinite(nuMax) || nuMax <= 0) {
    return {
      status: "outside-domain",
      quantityId,
      unit,
      condition: "nonpositive-frequency-bound",
      domainKind: "physical",
      reason: "Frequency bounds must be positive and finite.",
    };
  }
  if (nuMax <= nuMin) {
    return {
      status: "outside-domain",
      quantityId,
      unit,
      condition: "inverted-frequency-range",
      domainKind: "input",
      reason: `Upper frequency bound ${nuMax} must be strictly greater than lower bound ${nuMin}.`,
    };
  }
  if (!Number.isFinite(T) || T <= 0) {
    return {
      status: "outside-domain",
      quantityId,
      unit,
      condition: "nonpositive-temperature",
      domainKind: "physical",
      reason: `Temperature must be positive and finite (got ${T}).`,
    };
  }

  const f = (nu: number) => {
    const res = planckFrequencyEnergyDensity(nu, T, set);
    return res.status === "value" && res.linearRepresentable ? res.value : 0;
  };

  const total = adaptiveQuadrature(f, nuMin, nuMax);
  return {
    status: "value",
    quantityId,
    unit,
    value: total,
    linearRepresentable: true,
  };
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

regimeRelativeErrors · src/physics/reference/radiation/spectra.ts · this site’s source, as built · sha256:a4b44ec160f4721a8ce8233a6c39adb4e6b2dc061a427db51151d9bddaee5917

This function computes the listed outputs when it runs.

In words

Everything turns on one dimensionless number, x = h nu / (k_B T). Wien's relative error is e to the minus x, so Wien is good where x is large, which is high frequency or low temperature. The classical error is (e^x - 1)/x - 1, which vanishes where x is small. The function returns both errors, the regime they put you in, and the value of x at which each error reaches its tolerance, one per cent by default. Measured at 600 THz and 5800 K: x = 4.96, Wien runs 0.70 per cent below Planck, and the classical law is 27.7 times too large.

Implementation

/**
 * Relative error analysis comparing Wien and Rayleigh-Jeans approximations to Planck's exact law.
 */
export function regimeRelativeErrors(
  nu: CyclicFrequency | number,
  T: number,
  set: ConstantSet,
  options: { epsilonW?: number; epsilonRJ?: number } = {},
): RegimeReport {
  const { h, kB } = getBasePhysicsConstants(set);
  const epsilonW = options.epsilonW ?? 0.01;
  const epsilonRJ = options.epsilonRJ ?? 0.01;

  const x = (h * nu) / (kB * T);
  const wienRelativeError = Math.exp(-x);

  // The classical (Rayleigh-Jeans) relative error, measured against Planck like Wien's above:
  // (u_classical - u_Planck) / u_Planck = (e^x - 1)/x - 1. It was computed as 1 - x/(e^x - 1),
  // which divides by u_classical instead: the two agree to first order at small x, but at
  // x = 5.76 that read 0.98 while the classical law is 54.8 times Planck's value, and it put the
  // 1% boundary at x = 0.020067 where the owning bead specifies 0.0198678. Past x = 700, e^x
  // exceeds binary64 and the error is reported as Infinity, which callers must show in words.
  let rayleighJeansRelativeError: number;
  if (x < 1e-7) {
    rayleighJeansRelativeError = x / 2;
  } else if (x > 700) {
    rayleighJeansRelativeError = Number.POSITIVE_INFINITY;
  } else {
    rayleighJeansRelativeError = Math.expm1(x) / x - 1;
  }

  const wienBoundaryX = Math.log(1 / epsilonW);

  // Solve (e^x - 1)/x - 1 = epsilonRJ, that is e^x - 1 = (1 + epsilonRJ) x, by Newton's method.
  // For small epsilonRJ, x ~ 2 * epsilonRJ - (2/3) * epsilonRJ^2.
  let rjBoundaryX = 2 * epsilonRJ;
  for (let iter = 0; iter < 20; iter++) {
    const fVal = Math.expm1(rjBoundaryX) - (1 + epsilonRJ) * rjBoundaryX;
    const dfVal = Math.exp(rjBoundaryX) - (1 + epsilonRJ);
    const step = fVal / dfVal;
    rjBoundaryX -= step;
    if (Math.abs(step) < 1e-12) break;
  }

  const wienAdmitted = wienRelativeError <= epsilonW;
  const rayleighJeansAdmitted = rayleighJeansRelativeError <= epsilonRJ;

  let regime: "wien" | "rayleigh-jeans" | "intermediate";
  if (wienAdmitted) {
    regime = "wien";
  } else if (rayleighJeansAdmitted) {
    regime = "rayleigh-jeans";
  } else {
    regime = "intermediate";
  }

  return {
    x,
    wienRelativeError,
    rayleighJeansRelativeError,
    regime,
    wienAdmitted,
    rayleighJeansAdmitted,
    wienBoundaryX,
    rayleighJeansBoundaryX: rjBoundaryX,
  };
}

Open the derivation

Two printed limitations, made visible

The light paper states two regime limitations rather than one universal law. §2 concludes that the classical basis is suitable for large energy densities and wavelengths and fails completely for small wavelengths and low densities. §4 notes that Wien's law is not exactly valid, but that experiment fully confirms it for large ν/T, so results based on it hold only within those limits. This instrument shows the criteria for both limitations explicitly, at the temperature and frequency you choose, rather than asserting one law everywhere.

Two coordinate traps

A frequency-domain density uν and a wavelength-domain density uλ are related by a Jacobian, uλ(λ) = uν(c/λ)·c/λ², not by simple substitution. Their peaks do not correspond under λ = c/ν, and relabeling an axis without the Jacobian breaks the one invariant that does hold: the energy in a matching physical band, which agrees exactly between representations.

Embed this laboratory on another page. It starts from its worked defaults, not your current settings.