WBGT_physics.ts
Purpose
This module provides the physical calculations required to derive solar radiation from sky cover and geographic/temporal context, as well as unit conversion helpers used by the NDFD data normalization layer.
Its responsibilities include:
- Converting Fahrenheit to Celsius and knots to m/s for NDFD unit normalization
- Adjusting wind speed from 10m measurement height to 2m above ground
- Computing day-of-year, equation of time, solar declination, and solar hour angle
- Calculating direct normal irradiance on a horizontal surface with atmosphere and elevation correction
- Applying empirical cloud attenuation to produce Global Horizontal Irradiance (GHI)
Invariants
Solar Elevation Clamp
calculateDirectSolarRadiation clamps sinAlpha to [−1, 1] before Math.asin to prevent NaN from floating-point rounding.
Negative elevation angles (sun below horizon) always return 0.
Nighttime Zero Guard
Both solar functions return 0 when the solar elevation angle is ≤ 0 or the result is non-finite.
computeSolarRadiation additionally returns 0 if direct ≤ 0.
Cloud Attenuation Formula
cloudFactor = 1 − 0.75 × (cc / 100)^3.4
GHI = direct × cloudFactor
Where cc is cloud cover percentage clamped to [0, 100]. An undefined cloudAmount is treated as 0 (clear sky).
At 0% cloud cover: cloudFactor ≈ 1.0. At 100%: cloudFactor ≈ 0.25.
Elevation Pressure Correction
Atmospheric transmissivity is corrected for altitude using a scale height of 8,434 m:
P = P0 × exp(−elevation / 8434)
tau = 0.75 × (P / P0)^0.5
This reduces effective transmissivity at high elevations.
Timezone Offset from Date
The local standard meridian is derived from −date.getTimezoneOffset() / 60, using the device’s current UTC offset.
This correctly accounts for DST without requiring a separate timezone library.
Exports
fahrenheitToCelsius(...)
function fahrenheitToCelsius(f: number): number
knotToMps(...)
function knotToMps(k: number): number
Converts knots to meters per second (k / 1.944).
convertWindSpeed10mTo2m(...)
function convertWindSpeed10mTo2m(U10: number, z0?: number): number
Converts wind speed from 10m measurement height to 2m using logarithmic wind profile. Default roughness length z0 = 0.03 m (short grass).
calculateDoy(...)
function calculateDoy(date: Date): number
Returns the day-of-year (1–366) for the given Date.
calculateDirectSolarRadiation(...)
function calculateDirectSolarRadiation(
date: Date,
latDeg: number,
lonDeg: number,
elevMeters: number,
): number
Returns direct beam irradiance on a horizontal surface in W/m². Returns 0 at night or on computation error.
computeSolarRadiation(...)
function computeSolarRadiation(
cloudAmount: number | undefined,
date: Date,
lat: number,
lon: number,
elev: number,
): number
Returns Global Horizontal Irradiance (W/m²) after applying empirical cloud attenuation to the direct solar radiation. Returns 0 at night or when cloud cover fully attenuates.