Both bands share the physics of low microwave: humidity and refractivity gradient build ducts the same way, and rain + gas absorption are effectively zero at VHF/UHF. humidity_effect is :beneficial, rain_k / rain_alpha are (0, 1), and o2_db_km / h2o_coeff are 0. Range estimates reflect tropo reality: 2m ducts can reach 2500+ km under exceptional conditions (e.g. documented Hawaii ↔ California openings), 70cm a bit less. The seasonal base matches the low-microwave summer-peak curve. These configs do NOT capture sporadic-E, meteor scatter, or aurora — those need ionospheric data (GIRO ionosondes, NOAA SWPC) we don't yet ingest. The scoring on these bands is therefore "tropo-only" and will underestimate openings driven by ionospheric modes.
713 lines
17 KiB
Elixir
713 lines
17 KiB
Elixir
defmodule Microwaveprop.Propagation.BandConfig do
|
||
@moduledoc """
|
||
Data-driven band configuration for the propagation scoring algorithm.
|
||
|
||
This is the single source of truth for all scoring parameters: weights,
|
||
thresholds, seasonal tables, and band-specific coefficients. When the
|
||
algorithm is tuned or new bands are added, only this module changes.
|
||
"""
|
||
|
||
# Recalibrated 2026-04-11 via gradient descent on 5000 QSOs (loss 0.42 → 0.12).
|
||
# Key shifts: rain +70%, season +39%, wind +60%; time_of_day -50%, pressure -31%.
|
||
@weights %{
|
||
humidity: 0.1243,
|
||
time_of_day: 0.0496,
|
||
td_depression: 0.0978,
|
||
refractivity: 0.1049,
|
||
sky: 0.08,
|
||
season: 0.1112,
|
||
wind: 0.08,
|
||
rain: 0.1362,
|
||
pressure: 0.1032,
|
||
pwat: 0.1128
|
||
}
|
||
|
||
@sunrise_table [7.4, 7.3, 7.0, 6.7, 6.35, 6.25, 6.35, 6.65, 6.9, 7.1, 7.35, 7.45]
|
||
|
||
@tiers [
|
||
%{min_score: 80, label: "EXCELLENT", color: "#059669"},
|
||
%{min_score: 65, label: "GOOD", color: "#0d9488"},
|
||
%{min_score: 50, label: "MARGINAL", color: "#ca8a04"},
|
||
%{min_score: 33, label: "POOR", color: "#ea580c"},
|
||
%{min_score: 0, label: "NEGLIGIBLE", color: "#dc2626"}
|
||
]
|
||
|
||
@humidity_beneficial_thresholds [{4, 55}, {7, 70}, {10, 82}, {14, 90}, {18, 95}, {22, 88}]
|
||
@humidity_beneficial_default 75
|
||
|
||
# Thresholds calibrated for HRRR-derived gradients (coarser than sounding data).
|
||
# HRRR percentiles: p1=-230, p5=-162, p10=-130, p25=-94, p50=-70, p75=-53, p95=-40
|
||
@refractivity_thresholds [
|
||
{-200, 98, 85},
|
||
{-150, 92, 80},
|
||
{-100, 82, 72},
|
||
{-75, 68, 62},
|
||
{-55, 55, 55},
|
||
{-40, 48, 48}
|
||
]
|
||
@refractivity_default {42, 42}
|
||
|
||
@band_configs %{
|
||
# VHF / UHF bands share the tropo-ducting physics of low microwave
|
||
# (humidity and refractivity gradient build ducts the same way),
|
||
# so rain attenuation and gas absorption are effectively zero and
|
||
# humidity is :beneficial. The difference from 902+ is mostly in
|
||
# the achievable range — a 2m duct can reach 2500+ km under
|
||
# exceptional conditions (e.g. documented Hawaii ↔ California
|
||
# openings). These do NOT capture sporadic-E or meteor scatter,
|
||
# which need ionospheric data we don't yet ingest.
|
||
144 => %{
|
||
freq_mhz: 144,
|
||
label: "144 MHz",
|
||
o2_db_km: 0.0,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.0,
|
||
rain_alpha: 1.0,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 350,
|
||
extended_range_km: 900,
|
||
exceptional_range_km: 2500
|
||
},
|
||
440 => %{
|
||
freq_mhz: 440,
|
||
label: "440 MHz",
|
||
o2_db_km: 0.0,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.0,
|
||
rain_alpha: 1.0,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 300,
|
||
extended_range_km: 700,
|
||
exceptional_range_km: 1800
|
||
},
|
||
902 => %{
|
||
freq_mhz: 902,
|
||
label: "902 MHz",
|
||
o2_db_km: 0.006,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.000,
|
||
rain_alpha: 1.0,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 400,
|
||
extended_range_km: 800,
|
||
exceptional_range_km: 1500
|
||
},
|
||
1_296 => %{
|
||
freq_mhz: 1_296,
|
||
label: "1296 MHz",
|
||
o2_db_km: 0.006,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.000,
|
||
rain_alpha: 1.0,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 350,
|
||
extended_range_km: 700,
|
||
exceptional_range_km: 1200
|
||
},
|
||
2_304 => %{
|
||
freq_mhz: 2_304,
|
||
label: "2304 MHz",
|
||
o2_db_km: 0.006,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.001,
|
||
rain_alpha: 1.15,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 300,
|
||
extended_range_km: 600,
|
||
exceptional_range_km: 1000
|
||
},
|
||
3_456 => %{
|
||
freq_mhz: 3_456,
|
||
label: "3456 MHz",
|
||
o2_db_km: 0.006,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.002,
|
||
rain_alpha: 1.20,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 250,
|
||
extended_range_km: 550,
|
||
exceptional_range_km: 900
|
||
},
|
||
5_760 => %{
|
||
freq_mhz: 5_760,
|
||
label: "5760 MHz",
|
||
o2_db_km: 0.007,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.005,
|
||
rain_alpha: 1.25,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 220,
|
||
extended_range_km: 500,
|
||
exceptional_range_km: 1000
|
||
},
|
||
10_000 => %{
|
||
freq_mhz: 10_000,
|
||
label: "10 GHz",
|
||
o2_db_km: 0.007,
|
||
h2o_coeff: 0.0,
|
||
humidity_effect: :beneficial,
|
||
humidity_penalty: 0.0,
|
||
rain_k: 0.010,
|
||
rain_alpha: 1.28,
|
||
seasonal_base: %{
|
||
1 => 38,
|
||
2 => 40,
|
||
3 => 22,
|
||
4 => 55,
|
||
5 => 68,
|
||
6 => 90,
|
||
7 => 95,
|
||
8 => 75,
|
||
9 => 78,
|
||
10 => 88,
|
||
11 => 78,
|
||
12 => 25
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 200,
|
||
extended_range_km: 500,
|
||
exceptional_range_km: 1000
|
||
},
|
||
24_000 => %{
|
||
freq_mhz: 24_000,
|
||
label: "24 GHz",
|
||
o2_db_km: 0.02,
|
||
h2o_coeff: 0.002,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.6,
|
||
rain_k: 0.070,
|
||
rain_alpha: 1.07,
|
||
seasonal_base: %{
|
||
1 => 88,
|
||
2 => 84,
|
||
3 => 68,
|
||
4 => 62,
|
||
5 => 51,
|
||
6 => 34,
|
||
7 => 18,
|
||
8 => 18,
|
||
9 => 48,
|
||
10 => 68,
|
||
11 => 96,
|
||
12 => 88
|
||
},
|
||
seasonal_adj: %{5 => -4, 6 => -8, 7 => -10, 8 => -10, 9 => -4},
|
||
typical_range_km: 100,
|
||
extended_range_km: 250,
|
||
exceptional_range_km: 500
|
||
},
|
||
47_000 => %{
|
||
freq_mhz: 47_000,
|
||
label: "47 GHz",
|
||
o2_db_km: 0.04,
|
||
h2o_coeff: 0.003,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.0,
|
||
rain_k: 0.187,
|
||
rain_alpha: 0.93,
|
||
seasonal_base: %{
|
||
1 => 90,
|
||
2 => 88,
|
||
3 => 78,
|
||
4 => 68,
|
||
5 => 55,
|
||
6 => 38,
|
||
7 => 22,
|
||
8 => 22,
|
||
9 => 48,
|
||
10 => 74,
|
||
11 => 96,
|
||
12 => 90
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 70,
|
||
extended_range_km: 150,
|
||
exceptional_range_km: 300
|
||
},
|
||
68_000 => %{
|
||
freq_mhz: 68_000,
|
||
label: "68 GHz",
|
||
o2_db_km: 0.90,
|
||
h2o_coeff: 0.007,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.4,
|
||
rain_k: 0.310,
|
||
rain_alpha: 0.86,
|
||
seasonal_base: %{
|
||
1 => 90,
|
||
2 => 88,
|
||
3 => 78,
|
||
4 => 65,
|
||
5 => 50,
|
||
6 => 32,
|
||
7 => 18,
|
||
8 => 18,
|
||
9 => 44,
|
||
10 => 70,
|
||
11 => 92,
|
||
12 => 90
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 40,
|
||
extended_range_km: 80,
|
||
exceptional_range_km: 150
|
||
},
|
||
75_000 => %{
|
||
freq_mhz: 75_000,
|
||
label: "75 GHz",
|
||
o2_db_km: 0.012,
|
||
h2o_coeff: 0.006,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.2,
|
||
rain_k: 0.345,
|
||
rain_alpha: 0.84,
|
||
seasonal_base: %{
|
||
1 => 90,
|
||
2 => 90,
|
||
3 => 80,
|
||
4 => 68,
|
||
5 => 55,
|
||
6 => 38,
|
||
7 => 22,
|
||
8 => 22,
|
||
9 => 48,
|
||
10 => 74,
|
||
11 => 96,
|
||
12 => 90
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 50,
|
||
extended_range_km: 120,
|
||
exceptional_range_km: 250
|
||
},
|
||
122_000 => %{
|
||
freq_mhz: 122_000,
|
||
label: "122 GHz",
|
||
o2_db_km: 0.80,
|
||
h2o_coeff: 0.010,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.0,
|
||
rain_k: 0.498,
|
||
rain_alpha: 0.77,
|
||
seasonal_base: %{
|
||
1 => 92,
|
||
2 => 90,
|
||
3 => 78,
|
||
4 => 62,
|
||
5 => 45,
|
||
6 => 28,
|
||
7 => 15,
|
||
8 => 15,
|
||
9 => 38,
|
||
10 => 68,
|
||
11 => 92,
|
||
12 => 92
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 30,
|
||
extended_range_km: 80,
|
||
exceptional_range_km: 140
|
||
},
|
||
134_000 => %{
|
||
freq_mhz: 134_000,
|
||
label: "134 GHz",
|
||
o2_db_km: 0.08,
|
||
h2o_coeff: 0.015,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.3,
|
||
rain_k: 0.520,
|
||
rain_alpha: 0.75,
|
||
seasonal_base: %{
|
||
1 => 92,
|
||
2 => 90,
|
||
3 => 78,
|
||
4 => 65,
|
||
5 => 48,
|
||
6 => 30,
|
||
7 => 18,
|
||
8 => 18,
|
||
9 => 42,
|
||
10 => 70,
|
||
11 => 92,
|
||
12 => 92
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 40,
|
||
extended_range_km: 100,
|
||
exceptional_range_km: 160
|
||
},
|
||
# 142–145 GHz — between the 118 GHz O2 line and the 183 GHz H2O line.
|
||
# Coefficients linearly interpolate between 134 GHz and 241 GHz; rain
|
||
# tracks ITU-R P.838 in the K-band-extrapolated regime. Ranges scaled
|
||
# from the handful of contacts in the corpus (n=4 at 142 GHz, n=2 at
|
||
# 145 GHz) — these are scaffolding values and will need calibration as
|
||
# the band sees more activity.
|
||
142_000 => %{
|
||
freq_mhz: 142_000,
|
||
label: "142 GHz",
|
||
o2_db_km: 0.05,
|
||
h2o_coeff: 0.025,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.4,
|
||
rain_k: 0.530,
|
||
rain_alpha: 0.74,
|
||
seasonal_base: %{
|
||
1 => 92,
|
||
2 => 90,
|
||
3 => 78,
|
||
4 => 65,
|
||
5 => 47,
|
||
6 => 28,
|
||
7 => 16,
|
||
8 => 16,
|
||
9 => 40,
|
||
10 => 68,
|
||
11 => 92,
|
||
12 => 92
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 35,
|
||
extended_range_km: 80,
|
||
exceptional_range_km: 160
|
||
},
|
||
145_000 => %{
|
||
freq_mhz: 145_000,
|
||
label: "145 GHz",
|
||
o2_db_km: 0.06,
|
||
h2o_coeff: 0.040,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 1.5,
|
||
rain_k: 0.535,
|
||
rain_alpha: 0.74,
|
||
seasonal_base: %{
|
||
1 => 92,
|
||
2 => 90,
|
||
3 => 78,
|
||
4 => 64,
|
||
5 => 46,
|
||
6 => 27,
|
||
7 => 15,
|
||
8 => 15,
|
||
9 => 38,
|
||
10 => 66,
|
||
11 => 92,
|
||
12 => 92
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 35,
|
||
extended_range_km: 80,
|
||
exceptional_range_km: 150
|
||
},
|
||
241_000 => %{
|
||
freq_mhz: 241_000,
|
||
label: "241 GHz",
|
||
o2_db_km: 0.08,
|
||
h2o_coeff: 0.30,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 3.0,
|
||
rain_k: 0.550,
|
||
rain_alpha: 0.70,
|
||
seasonal_base: %{
|
||
1 => 95,
|
||
2 => 92,
|
||
3 => 75,
|
||
4 => 55,
|
||
5 => 35,
|
||
6 => 15,
|
||
7 => 8,
|
||
8 => 8,
|
||
9 => 30,
|
||
10 => 65,
|
||
11 => 95,
|
||
12 => 95
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 10,
|
||
extended_range_km: 50,
|
||
exceptional_range_km: 115
|
||
},
|
||
# Sub-mm bands (288–411 GHz) — extrapolated scaffolding so the scoring
|
||
# pipeline doesn't silently drop these contacts. The prod corpus has 1
|
||
# contact per band, all under 1.5 km (effectively LOS), so the absorption
|
||
# values dominate any duct-related score. Coefficients track ITU-R P.676/
|
||
# 838 trends past the 325 GHz H2O line; ranges are nominal.
|
||
288_000 => %{
|
||
freq_mhz: 288_000,
|
||
label: "288 GHz",
|
||
o2_db_km: 0.10,
|
||
h2o_coeff: 0.45,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 3.5,
|
||
rain_k: 0.560,
|
||
rain_alpha: 0.68,
|
||
seasonal_base: %{
|
||
1 => 95,
|
||
2 => 92,
|
||
3 => 75,
|
||
4 => 55,
|
||
5 => 35,
|
||
6 => 14,
|
||
7 => 7,
|
||
8 => 7,
|
||
9 => 28,
|
||
10 => 64,
|
||
11 => 95,
|
||
12 => 95
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 5,
|
||
extended_range_km: 15,
|
||
exceptional_range_km: 50
|
||
},
|
||
322_000 => %{
|
||
freq_mhz: 322_000,
|
||
label: "322 GHz",
|
||
o2_db_km: 0.12,
|
||
h2o_coeff: 0.55,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 4.0,
|
||
rain_k: 0.570,
|
||
rain_alpha: 0.66,
|
||
seasonal_base: %{
|
||
1 => 96,
|
||
2 => 92,
|
||
3 => 74,
|
||
4 => 52,
|
||
5 => 32,
|
||
6 => 12,
|
||
7 => 6,
|
||
8 => 6,
|
||
9 => 26,
|
||
10 => 62,
|
||
11 => 96,
|
||
12 => 96
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 5,
|
||
extended_range_km: 15,
|
||
exceptional_range_km: 40
|
||
},
|
||
403_000 => %{
|
||
freq_mhz: 403_000,
|
||
label: "403 GHz",
|
||
o2_db_km: 0.15,
|
||
h2o_coeff: 0.40,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 3.0,
|
||
rain_k: 0.580,
|
||
rain_alpha: 0.64,
|
||
seasonal_base: %{
|
||
1 => 96,
|
||
2 => 92,
|
||
3 => 74,
|
||
4 => 52,
|
||
5 => 32,
|
||
6 => 12,
|
||
7 => 6,
|
||
8 => 6,
|
||
9 => 26,
|
||
10 => 62,
|
||
11 => 96,
|
||
12 => 96
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 3,
|
||
extended_range_km: 10,
|
||
exceptional_range_km: 30
|
||
},
|
||
411_000 => %{
|
||
freq_mhz: 411_000,
|
||
label: "411 GHz",
|
||
o2_db_km: 0.15,
|
||
h2o_coeff: 0.42,
|
||
humidity_effect: :harmful,
|
||
humidity_penalty: 3.2,
|
||
rain_k: 0.580,
|
||
rain_alpha: 0.64,
|
||
seasonal_base: %{
|
||
1 => 96,
|
||
2 => 92,
|
||
3 => 74,
|
||
4 => 52,
|
||
5 => 32,
|
||
6 => 12,
|
||
7 => 6,
|
||
8 => 6,
|
||
9 => 26,
|
||
10 => 62,
|
||
11 => 96,
|
||
12 => 96
|
||
},
|
||
seasonal_adj: %{},
|
||
typical_range_km: 3,
|
||
extended_range_km: 10,
|
||
exceptional_range_km: 30
|
||
}
|
||
}
|
||
|
||
@doc "Returns the band config for the given frequency in MHz, or nil if not found."
|
||
@spec get(integer()) :: map() | nil
|
||
def get(freq_mhz), do: Map.get(@band_configs, freq_mhz)
|
||
|
||
@doc "Returns all band configs sorted by frequency (ascending)."
|
||
@spec all_bands() :: [map()]
|
||
def all_bands do
|
||
@band_configs
|
||
|> Enum.sort_by(fn {freq, _config} -> freq end)
|
||
|> Enum.map(fn {_freq, config} -> config end)
|
||
end
|
||
|
||
@doc "Returns all supported frequencies sorted ascending."
|
||
@spec all_freqs() :: [integer()]
|
||
def all_freqs do
|
||
@band_configs
|
||
|> Map.keys()
|
||
|> Enum.sort()
|
||
end
|
||
|
||
@doc "Returns band options as {label, value_string} tuples for form dropdowns."
|
||
@spec band_options() :: [{String.t(), String.t()}]
|
||
def band_options do
|
||
Enum.map(all_bands(), fn band -> {band.label, to_string(band.freq_mhz)} end)
|
||
end
|
||
|
||
@doc "Returns the scoring weights map. All 10 values sum to 1.0."
|
||
@spec weights() :: map()
|
||
def weights, do: @weights
|
||
|
||
@doc "Returns the 12-element sunrise hour table (Jan-Dec, local time)."
|
||
@spec sunrise_table() :: [float()]
|
||
def sunrise_table, do: @sunrise_table
|
||
|
||
@doc "Returns score tier definitions ordered by threshold descending."
|
||
@spec tiers() :: [map()]
|
||
def tiers, do: @tiers
|
||
|
||
@doc "Returns humidity beneficial thresholds as {hour, score} tuples."
|
||
@spec humidity_beneficial_thresholds() :: [{integer(), integer()}]
|
||
def humidity_beneficial_thresholds, do: @humidity_beneficial_thresholds
|
||
|
||
@doc "Returns the default humidity beneficial score."
|
||
@spec humidity_beneficial_default() :: integer()
|
||
def humidity_beneficial_default, do: @humidity_beneficial_default
|
||
|
||
@doc "Returns refractivity thresholds as {gradient, score_beneficial, score_harmful} tuples."
|
||
@spec refractivity_thresholds() :: [{number(), number(), number()}]
|
||
def refractivity_thresholds, do: @refractivity_thresholds
|
||
|
||
@doc "Returns the default refractivity scores as {beneficial, harmful}."
|
||
@spec refractivity_default() :: {number(), number()}
|
||
def refractivity_default, do: @refractivity_default
|
||
end
|