WBGT_physics.ts

Physics-based solar radiation computation and unit conversion utilities for WBGT inputs

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.