0Core Concept
Dynamic light pollution rating differs from the traditional "static Bortle" in three ways:
- Follows Bortle (1–9), but recalibrates the SQM correspondences—replacing the long-circulated, convention-based reference numbers with real field measurements (Bortle's original text never gave SQM values).
- The dark end is set by geography, not the zenith reading—zenith SQM saturates above ~21.8, so classes 1–3 are separated by "surrounding dark-area extent + terrain shielding".
- The rating shifts dynamically with the sky—moon phase/position, the Milky Way, cloud, and humidity all temporarily pull down the actual rating for a given night.
Output is on two axes: the light-pollution axis (dynamic effective SQM → dynamic Bortle) and the observability axis (cloud + humidity + transparency, deciding "whether you can observe tonight, and how clearly").
1Data Sources (all public, no authentication)
| Data | Source | Notes |
|---|---|---|
| Light-pollution SQM tiles | djlorenz.github.io /astronomy/lp2024 | David Lorenz 2024; 5°×5° per tile, 600×600 grid (~0.9km); WGS-84 |
| Terrain DEM | s3.amazonaws.com /elevation-tiles-prod/terrarium | Mapzen terrarium; z12 (~37m/px); WGS-84 |
| Calibration measurements | unihedron.com /projects/darksky/database | 16,074 globally crowdsourced measurements (2005–2026), used for fitting and calibration |
The atlas is published publicly as binary gridded tiles; a deterministic decode of the tiles turns coordinates into SQM values—reproducing the algorithm below yields results that are bit-for-bit identical to the atlas.
2SQM Tile Decoding Algorithm (reproduced from public tiles)
input: lat, lon (WGS-84)
lonD = ((lon+180) mod 360 + 360) mod 360
tileX = floor(lonD/5)+1 ; tileY = floor((lat+65)/5)+1 # tileY∈[1,28]
file = binary_tile_{tileX}_{tileY}.dat.gz → gzip decompress (360001 bytes)
ix = round(120*((lonD - 5*(tileX-1)) + 1/240)) # ∈[1,600]
iy = round(120*(((lat+65) - 5*(tileY-1)) + 1/240))
first = data[0]*128 + data[1]
latSum = Σ_{i=1}^{iy-1} signed(data[600*i + 1]) # signed: b<128?b:b-256
lonSum = Σ_{i=1}^{ix-1} signed(data[600*(iy-1) + 1 + i])
C = clamp(first + latSum + lonSum, 0, 10000)
brightnessRatio = (5/195)*(exp(0.0195*C) - 1)
SQM = 22.0 - 5*log10(1+brightnessRatio) / log10(100) # mag/arcsec²
Vectorization: precompute per-tile cumcol[iy] and cr[r][k], then C = first + cumcol[iy-1] + cr[iy-1][ix-1] is an O(1) lookup. Verified against the official stored values with max|diff|=0.0000.
3Zenith SQM ↔ Bortle: Recalibration Table
The most widely circulated Bortle–SQM correspondence is actually misleading (it labels class 1 as 22.0)—it comes neither from Bortle's original text nor from any authoritative definition, just years of convention; measure for real and you only get ~21.7. The table below recalibrates using 6,438 "clear · moonless · zenith" measurements, giving the estimated measured zenith SQM:
| Class | Environment | Map SQM (classifying) | Est. measured p25/median/p75 | Median dist. to dome | Dark-area share |
|---|---|---|---|---|---|
| 1 | Pristine dark | ≥21.99 +vast openness | 21.61 / 21.72 / 21.86 | 105 km | 100% |
| 2 | Typical dark | 21.89–21.99 +medium openness | 21.45 / 21.60 / 21.79 | 77 | 96% |
| 3 | Rural dark | 21.69–21.89 | 21.40 / 21.58 / 21.73 | 44 | 64% |
| 4 | Rural/suburban | 20.49–21.69 | 21.03 / 21.29 / 21.47 | 18 | 18% |
| 5 | Suburban | 19.50–20.49 | 19.78 / 20.25 / 20.58 | 0 | 5% |
| 6 | Bright suburban | 18.94–19.50 | 18.95 / 19.25 / 19.61 | — | — |
| 7 | Suburban–urban transition | 18.38–18.94 | 18.30 / 18.58 / 18.81 | — | — |
| 8–9 | Urban | <18.38 | 17.84 / 18.14 / 18.26 | — | — |
3.1 Crossover (when the zenith stops working)
- Zenith standard deviation by class: B4 0.346 → B3 0.058 → B2 0.031 → B1 0.005 (collapses to zero).
- Around SQM 21.7 (from Bortle 3) the zenith begins to saturate; by SQM 21.9 (Bortle 2) it is completely pinned.
- Physical floor ~21.9–22.0 (airglow / zodiacal light / Milky Way); measurements >22.0 are physically impossible (196 removed, 71% from a single bad station).
4Static Baseline Rating (intrinsic to a site; moonless clear night)
Effective Bortle baseline = f( zenith darkness , terrain-aware surrounding glow ) · class ≥4 (map SQM<21.7): zenith-dominated, look up table §3 directly · class 1–3 (map SQM≥21.7): zenith + surrounding glow (incl. terrain shielding) jointly classify/downgrade
4.1 Surrounding Glow Index (distance-weighted, using only the light-pollution tiles)
glow_raw = Σ_surroundingCells A(s) / d^2.5 # d=distance km, sample ±120km/step 4km, exclude d<3km A(s) = max(0, 10^(8-0.4·s) - 10^(-0.8)) # this cell's linear amount of "artificial light above the natural floor" glowIndex = log10(glow_raw + 1e-9)
The distance exponent 2.5 = the Walker/Garstang light-propagation law; radius, exponent, and floor are all tunable parameters. It captures the whole surrounding glow, not just the single nearest dome.
4.2 Terrain-Shielding Gate (key)
for each azimuth φ (every 5°): along φ sample elevation out to ~50km, compute the horizon angle = atan((elevation - site elevation - curvature correction)/distance) curvature correction = d²/(2·(7/6)·R_earth) shield[φ] = distance where horizon angle first >2° glow_terrain = Σ A(s)/d^2.5 × visibility(φ,d) visibility = 0 if d > shield[φ] (blocked by mountains below the horizon) ; otherwise 1
| Validation point | Zenith | Raw glow | Terrain glow | Blocked |
|---|---|---|---|---|
| Tivoli (Namibia desert) | 22.00 | −3.70 | −3.70 | 0% |
| Wiruna (Australia) | 21.96 | −2.42 | −2.42 | 0% |
| Kendrick Park (near Flagstaff) | 21.91 | −2.07 | −2.39 | 52% |
| Crestone (backed by a 4300m ridge) | 21.85 | −2.25 | −2.61 | 56% |
Crestone's eastern half is shielded by the 5–16° Sangre de Cristo ridge from the Front Range cities 100km away → cutting 56%, actually surpassing Wiruna. Kendrick Park is shielded 52% by the San Francisco Peaks (3850m) → rescued from a "dark-pocket downgrade to class 3" back to class 2.
4.3 Downgrade Thresholds (dark end, classes 1–3; map SQM ≥21.89)
| Terrain glow index | Verdict | Observational meaning (Bortle definition) |
|---|---|---|
| < −3.0 | Class 1 | No light dome anywhere on the horizon |
| −3.0 ~ −2.2 | Class 2 | 1–2 faint distant light domes |
| > −2.2 | Downgrade to class 3 | Prominent light domes (dark pocket) |
The thresholds are currently supported by "physical model + 4 benchmark points + Bortle definition + Walker distances", at v0.1; awaiting fine-tuning from dark-site measurements (§7).
5Dynamic Layer (Same-Night Sky Corrections)
effective SQM(t) = baseline SQM(loc) − Δmoonlight(t) − ΔMilkyWay(t) − Δtwilight(t) dynamic class(t) = use the §3 recalibration table to reverse-lookup effective SQM(t)
5.1 Moonlight Curve (fitted from the 16k measurements)
Let u = moon phase% / 100 × sin(moon altitude); zenith brightening ΔSQM (mag):
| Moon alt \ phase | <30% | 30–70% | 70–100% |
|---|---|---|---|
| 0–15° | +0.08 | +0.07 | +0.22 |
| 15–30° | +0.07 | +0.11 | +0.42 |
| 30–45° | +0.20 | +0.21 | +0.69 |
| 45°+ | — | +1.02 | +1.78 |
- Smooth approximation: ΔSQM ≈ 1.18 · u^0.65 (production should interpolate the table above directly; per-point scatter is large, R²≈0.10).
- Moonlight is blocked by terrain too: at field point 1 a full moon brightens by 2.35 mag, but only 1.75 once the moon is blocked by mountains (0.6 less) → the moonlight term also passes through the §4.2 terrain gate (using the moon's azimuth at the time).
- Production can add a "moon–target angular distance" refinement, or switch to the Krisciunas-Schaefer form.
5.2 Milky Way / Twilight (v2)
- Milky Way: when the galactic plane/center is near the zenith, the zenith brightens by ~±0.2–0.4 mag; compute the zenith's galactic coordinates from time and location.
- Twilight: when the sun's altitude is > −18° the sky is brighter (can be >0.5 mag); check whether it is within astronomical night.
6Observability Axis (independent of the light-pollution class)
6.1 Cloud (bidirectional effect; coefficients derived from measurements)
SQM change from overcast relative to clear, by environment:
| Environment (map SQM) | Few clouds | Cloudy | Overcast |
|---|---|---|---|
| Urban/bright (<19) | −0.2 | −0.4 | −2.2 |
| Suburban (19–20.5) | −0.2 | −0.5 | −3.8 |
| Rural (20.5–21.3) | −0.1 | — | −1.8 |
| Very dark (>21.3) | 0 | 0 | +0.3 |
6.2 Humidity + Nearby Streetlights (sub-grid local pollution)
- Field point 2: map 20.84, measured only 20.20 (−0.64 mag), due to a few nearby streetlights + high-humidity scattering by a creek.
- These are below the resolution of the map (~0.9km) and the glow sampling (4km), so they cannot be captured.
- Requires external data: humidity (weather API) + high-resolution local lighting (OSM streetlights / VIIRS). This is v2.
7Calibration Status & External Anchoring
| Quantity to calibrate | Fittable from 16k zenith measurements? | Status |
|---|---|---|
| Zenith↔SQM recalibration | ✅ Yes | Done (§3) |
| Cloud effect coefficients | ✅ Yes | Done (§6.1) |
| Moonlight curve | ✅ Yes | Done (§5.1) |
| Surrounding/terrain → zenith residual | ✅ Yes | Doable (not yet run) |
| Surrounding glow → how many classes to downgrade | ❌ No | Needs external ground truth |
Why the downgrade coefficient cannot be fitted: the measurements are zenith, while Bortle is whole-sky; surrounding light domes mainly affect the horizon, which the zenith SQM barely sees → with "the zenith fixed" the data contains no quantity that varies with the horizon. A structural limitation.
External anchoring (in place of dark-site measurements):
- The very definition of Bortle 1 vs 2 is "whether there are light domes on the horizon": class 1 = no distant light pollution; class 2 = 1–2 faint domes on the horizon; SQM differs by only 0.15–0.4 mag. → Directly validates §4 and gives a qualitative threshold.
- SQM fails at the dark end: the vendor acknowledges accuracy drops below 21.5 and that class 1–2 readings are only approximate.
- NPS/Duriscoe use whole-sky "average sky luminance (ASL)", precisely because "domes are brighter on the horizon than at the zenith" → the same approach used by professionals.
- Walker's law distances: population 1000 → avoidable at 32km, 10000 → 80km; large-city domes are visible 150+ miles away. → Calibrates the glow/distance thresholds.
8Field Validation (ground truth)
8.1 China Field Points (user-provided)
| Point | Coordinates | Map SQM | Measured | User rating | Model |
|---|---|---|---|---|---|
| Point 1 | 23.820, 114.099 | 21.24 | 21.25 | Class 4 | ✅ zenith-dominated, matches |
| Point 2 | 23.834, 112.886 | 20.84 | 20.20 | Below class 4 | ✅ local pollution −0.64 → class 5 |
Point 1: the map is accurate, zenith-dominated, class 4 matches; the moon blocked by mountains brightens 0.6 mag less (validating terrain blocking of moonlight). Point 2: the map overestimates by 0.64 mag, revealing "sub-grid local pollution" (§6.2); a city to the E corresponds to "the Milky Way being invisible to the E".
8.2 Benchmark Dark Sites
Tivoli / Hakos (Namibia), Wiruna (Australia), Crestone / Kendrick Park (USA) — see §4.2; the terrain gate correctly separates "valleys backed by mountains" from "open dark pockets".
9Implementation Roadmap
v1 (doable now, all public data)
SQM tiles → recalibrated rating (§3) → terrain-aware glow (§4) → moonlight dynamic layer (§5.1) → cloud observability gate (§6.1). Downgrade thresholds use v0.1 (§4.3).
v2
Milky Way/twilight terms (§5.2); humidity + local lighting (§6.2, needs external data); fine-tune the downgrade thresholds with user-measured dark-site points.
10Constants & Formulas Quick Reference
SQM formula SQM = 22 − 5·log10(1 + (5/195)(e^(0.0195·C)−1)) / log10(100) Glow Σ max(0,10^(8−0.4s)−10^(−0.8)) / d^2.5 R=120km, step=4km, exclude d<3km, exponent 2.5 Terrain gate horizon angle > 2° blocks (incl. curvature correction d²/(2·(7/6)·R_earth)) Downgrade thresholds terrain glow index <−3.0→class 1 / −3.0~−2.2→class 2 / >−2.2→class 3 Moonlight ΔSQM ≈ 1.18·u^0.65 , u=moonPhase/100×sin(moonAlt) (or use §5.1 table interpolation) Cloud gate overcast=not observable; cloud "brightening" only used in light-polluted environments Natural floor SQM upper limit ~22.0, >22.0 treated as bad data and removed