Add band configuration module for propagation scoring
Single source of truth for all scoring parameters: weights, thresholds, seasonal tables, and per-band coefficients for 8 microwave bands (10G through 241G). Includes ITU-R P.838-3 rain attenuation coefficients, humidity effects, refractivity scoring thresholds, and sunrise/tier definitions.
This commit is contained in:
parent
3228835636
commit
60461ffe32
2 changed files with 622 additions and 0 deletions
328
lib/microwaveprop/propagation/band_config.ex
Normal file
328
lib/microwaveprop/propagation/band_config.ex
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
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.
|
||||
"""
|
||||
|
||||
@weights %{
|
||||
humidity: 0.20,
|
||||
time_of_day: 0.20,
|
||||
td_depression: 0.12,
|
||||
refractivity: 0.10,
|
||||
sky: 0.10,
|
||||
season: 0.10,
|
||||
wind: 0.06,
|
||||
rain: 0.08,
|
||||
pressure: 0.04
|
||||
}
|
||||
|
||||
@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: "#00ffa3"},
|
||||
%{min_score: 65, label: "GOOD", color: "#7dffd4"},
|
||||
%{min_score: 50, label: "MARGINAL", color: "#ffe566"},
|
||||
%{min_score: 33, label: "POOR", color: "#ff9044"},
|
||||
%{min_score: 0, label: "NEGLIGIBLE", color: "#ff4f4f"}
|
||||
]
|
||||
|
||||
@humidity_beneficial_thresholds [{4, 55}, {7, 70}, {10, 82}, {14, 90}, {18, 95}, {22, 88}]
|
||||
@humidity_beneficial_default 75
|
||||
|
||||
@refractivity_thresholds [
|
||||
{-500, 98, 85},
|
||||
{-300, 92, 78},
|
||||
{-200, 80, 80},
|
||||
{-100, 65, 65},
|
||||
{-60, 55, 55}
|
||||
]
|
||||
@refractivity_default {42, 42}
|
||||
@shallow_bl_threshold_m 300
|
||||
@shallow_bl_score 82
|
||||
|
||||
@band_configs %{
|
||||
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 => 32,
|
||||
3 => 22,
|
||||
4 => 55,
|
||||
5 => 68,
|
||||
6 => 90,
|
||||
7 => 95,
|
||||
8 => 75,
|
||||
9 => 78,
|
||||
10 => 82,
|
||||
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
|
||||
},
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@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 the scoring weights map. All 9 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
|
||||
|
||||
@doc "Returns the shallow boundary layer threshold in meters."
|
||||
@spec shallow_bl_threshold_m() :: number()
|
||||
def shallow_bl_threshold_m, do: @shallow_bl_threshold_m
|
||||
|
||||
@doc "Returns the score applied when boundary layer is shallow."
|
||||
@spec shallow_bl_score() :: number()
|
||||
def shallow_bl_score, do: @shallow_bl_score
|
||||
end
|
||||
294
test/microwaveprop/propagation/band_config_test.exs
Normal file
294
test/microwaveprop/propagation/band_config_test.exs
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
defmodule Microwaveprop.Propagation.BandConfigTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias Microwaveprop.Propagation.BandConfig
|
||||
|
||||
@all_freqs [10_000, 24_000, 47_000, 68_000, 75_000, 122_000, 134_000, 241_000]
|
||||
|
||||
describe "get/1" do
|
||||
test "returns config for 10 GHz" do
|
||||
config = BandConfig.get(10_000)
|
||||
assert config.freq_mhz == 10_000
|
||||
assert config.label == "10 GHz"
|
||||
assert config.humidity_effect == :beneficial
|
||||
assert config.humidity_penalty == 0.0
|
||||
assert config.rain_k == 0.010
|
||||
assert config.rain_alpha == 1.28
|
||||
assert config.typical_range_km == 200
|
||||
assert config.extended_range_km == 500
|
||||
assert config.exceptional_range_km == 1000
|
||||
end
|
||||
|
||||
test "returns config for 24 GHz" do
|
||||
config = BandConfig.get(24_000)
|
||||
assert config.freq_mhz == 24_000
|
||||
assert config.label == "24 GHz"
|
||||
assert config.humidity_effect == :harmful
|
||||
assert config.humidity_penalty == 1.6
|
||||
assert config.rain_k == 0.070
|
||||
assert config.rain_alpha == 1.07
|
||||
assert config.typical_range_km == 100
|
||||
assert config.extended_range_km == 250
|
||||
assert config.exceptional_range_km == 500
|
||||
end
|
||||
|
||||
test "returns config for 47 GHz" do
|
||||
config = BandConfig.get(47_000)
|
||||
assert config.freq_mhz == 47_000
|
||||
assert config.humidity_effect == :harmful
|
||||
assert config.humidity_penalty == 1.0
|
||||
assert config.rain_k == 0.187
|
||||
assert config.rain_alpha == 0.93
|
||||
end
|
||||
|
||||
test "returns config for 68 GHz with atmospheric absorption" do
|
||||
config = BandConfig.get(68_000)
|
||||
assert config.o2_db_km == 0.90
|
||||
assert config.h2o_coeff == 0.007
|
||||
assert config.humidity_penalty == 1.4
|
||||
assert config.rain_k == 0.310
|
||||
assert config.rain_alpha == 0.86
|
||||
assert config.typical_range_km == 40
|
||||
assert config.extended_range_km == 80
|
||||
assert config.exceptional_range_km == 150
|
||||
end
|
||||
|
||||
test "returns config for 75 GHz" do
|
||||
config = BandConfig.get(75_000)
|
||||
assert config.o2_db_km == 0.012
|
||||
assert config.h2o_coeff == 0.006
|
||||
assert config.humidity_penalty == 1.2
|
||||
assert config.rain_k == 0.345
|
||||
assert config.rain_alpha == 0.84
|
||||
end
|
||||
|
||||
test "returns config for 122 GHz" do
|
||||
config = BandConfig.get(122_000)
|
||||
assert config.o2_db_km == 0.80
|
||||
assert config.h2o_coeff == 0.010
|
||||
assert config.humidity_penalty == 1.0
|
||||
assert config.rain_k == 0.498
|
||||
assert config.rain_alpha == 0.77
|
||||
end
|
||||
|
||||
test "returns config for 134 GHz" do
|
||||
config = BandConfig.get(134_000)
|
||||
assert config.o2_db_km == 0.08
|
||||
assert config.h2o_coeff == 0.015
|
||||
assert config.humidity_penalty == 1.3
|
||||
assert config.rain_k == 0.520
|
||||
assert config.rain_alpha == 0.75
|
||||
end
|
||||
|
||||
test "returns config for 241 GHz" do
|
||||
config = BandConfig.get(241_000)
|
||||
assert config.o2_db_km == 0.08
|
||||
assert config.h2o_coeff == 0.30
|
||||
assert config.humidity_penalty == 3.0
|
||||
assert config.rain_k == 0.550
|
||||
assert config.rain_alpha == 0.70
|
||||
assert config.typical_range_km == 10
|
||||
assert config.extended_range_km == 50
|
||||
assert config.exceptional_range_km == 115
|
||||
end
|
||||
|
||||
test "returns nil for unknown band" do
|
||||
assert BandConfig.get(999) == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "all_bands/0" do
|
||||
test "returns 8 bands" do
|
||||
bands = BandConfig.all_bands()
|
||||
assert length(bands) == 8
|
||||
end
|
||||
|
||||
test "bands are sorted by frequency" do
|
||||
freqs = Enum.map(BandConfig.all_bands(), & &1.freq_mhz)
|
||||
assert freqs == @all_freqs
|
||||
end
|
||||
end
|
||||
|
||||
describe "all_freqs/0" do
|
||||
test "returns sorted frequency list" do
|
||||
assert BandConfig.all_freqs() == @all_freqs
|
||||
end
|
||||
end
|
||||
|
||||
describe "weights/0" do
|
||||
test "returns all 9 factor keys" do
|
||||
weights = BandConfig.weights()
|
||||
|
||||
expected_keys =
|
||||
MapSet.new([
|
||||
:humidity,
|
||||
:time_of_day,
|
||||
:td_depression,
|
||||
:refractivity,
|
||||
:sky,
|
||||
:season,
|
||||
:wind,
|
||||
:rain,
|
||||
:pressure
|
||||
])
|
||||
|
||||
assert MapSet.new(Map.keys(weights)) == expected_keys
|
||||
end
|
||||
|
||||
test "weights sum to 1.0" do
|
||||
total = BandConfig.weights() |> Map.values() |> Enum.sum()
|
||||
assert_in_delta total, 1.0, 0.001
|
||||
end
|
||||
|
||||
test "individual weights have correct values" do
|
||||
weights = BandConfig.weights()
|
||||
assert weights.humidity == 0.20
|
||||
assert weights.time_of_day == 0.20
|
||||
assert weights.td_depression == 0.12
|
||||
assert weights.refractivity == 0.10
|
||||
assert weights.sky == 0.10
|
||||
assert weights.season == 0.10
|
||||
assert weights.wind == 0.06
|
||||
assert weights.rain == 0.08
|
||||
assert weights.pressure == 0.04
|
||||
end
|
||||
end
|
||||
|
||||
describe "sunrise_table/0" do
|
||||
test "returns 12 monthly values" do
|
||||
table = BandConfig.sunrise_table()
|
||||
assert length(table) == 12
|
||||
end
|
||||
|
||||
test "returns expected sunrise hours" do
|
||||
assert BandConfig.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
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "tiers/0" do
|
||||
test "returns 5 tiers" do
|
||||
tiers = BandConfig.tiers()
|
||||
assert length(tiers) == 5
|
||||
end
|
||||
|
||||
test "tiers are ordered by threshold descending" do
|
||||
thresholds = Enum.map(BandConfig.tiers(), & &1.min_score)
|
||||
assert thresholds == [80, 65, 50, 33, 0]
|
||||
end
|
||||
|
||||
test "tier labels and colors are correct" do
|
||||
tiers = BandConfig.tiers()
|
||||
[excellent, good, marginal, poor, negligible] = tiers
|
||||
|
||||
assert excellent == %{min_score: 80, label: "EXCELLENT", color: "#00ffa3"}
|
||||
assert good == %{min_score: 65, label: "GOOD", color: "#7dffd4"}
|
||||
assert marginal == %{min_score: 50, label: "MARGINAL", color: "#ffe566"}
|
||||
assert poor == %{min_score: 33, label: "POOR", color: "#ff9044"}
|
||||
assert negligible == %{min_score: 0, label: "NEGLIGIBLE", color: "#ff4f4f"}
|
||||
end
|
||||
end
|
||||
|
||||
describe "seasonal bases" do
|
||||
test "every band has 12 months in seasonal_base" do
|
||||
for freq <- @all_freqs do
|
||||
config = BandConfig.get(freq)
|
||||
assert map_size(config.seasonal_base) == 12, "#{freq} missing months in seasonal_base"
|
||||
assert Enum.all?(1..12, &Map.has_key?(config.seasonal_base, &1))
|
||||
end
|
||||
end
|
||||
|
||||
test "10 GHz seasonal base peaks in summer" do
|
||||
config = BandConfig.get(10_000)
|
||||
assert config.seasonal_base[7] == 95
|
||||
assert config.seasonal_base[3] == 22
|
||||
end
|
||||
|
||||
test "24 GHz seasonal base peaks in winter" do
|
||||
config = BandConfig.get(24_000)
|
||||
assert config.seasonal_base[11] == 96
|
||||
assert config.seasonal_base[7] == 18
|
||||
end
|
||||
|
||||
test "24 GHz has seasonal adjustments" do
|
||||
config = BandConfig.get(24_000)
|
||||
assert config.seasonal_adj[7] == -10
|
||||
assert config.seasonal_adj[5] == -4
|
||||
end
|
||||
|
||||
test "10 GHz has empty seasonal adjustments" do
|
||||
config = BandConfig.get(10_000)
|
||||
assert config.seasonal_adj == %{}
|
||||
end
|
||||
end
|
||||
|
||||
describe "humidity_beneficial_thresholds/0" do
|
||||
test "returns threshold tuples sorted by hour" do
|
||||
thresholds = BandConfig.humidity_beneficial_thresholds()
|
||||
assert thresholds == [{4, 55}, {7, 70}, {10, 82}, {14, 90}, {18, 95}, {22, 88}]
|
||||
end
|
||||
end
|
||||
|
||||
describe "humidity_beneficial_default/0" do
|
||||
test "returns 75" do
|
||||
assert BandConfig.humidity_beneficial_default() == 75
|
||||
end
|
||||
end
|
||||
|
||||
describe "refractivity_thresholds/0" do
|
||||
test "returns gradient/score tuples" do
|
||||
thresholds = BandConfig.refractivity_thresholds()
|
||||
|
||||
assert thresholds == [
|
||||
{-500, 98, 85},
|
||||
{-300, 92, 78},
|
||||
{-200, 80, 80},
|
||||
{-100, 65, 65},
|
||||
{-60, 55, 55}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "refractivity_default/0" do
|
||||
test "returns default scores" do
|
||||
assert BandConfig.refractivity_default() == {42, 42}
|
||||
end
|
||||
end
|
||||
|
||||
describe "shallow_bl_threshold_m/0" do
|
||||
test "returns 300" do
|
||||
assert BandConfig.shallow_bl_threshold_m() == 300
|
||||
end
|
||||
end
|
||||
|
||||
describe "shallow_bl_score/0" do
|
||||
test "returns 82" do
|
||||
assert BandConfig.shallow_bl_score() == 82
|
||||
end
|
||||
end
|
||||
|
||||
describe "only 10 GHz is beneficial" do
|
||||
test "10 GHz has beneficial humidity effect" do
|
||||
assert BandConfig.get(10_000).humidity_effect == :beneficial
|
||||
end
|
||||
|
||||
test "all other bands have harmful humidity effect" do
|
||||
for freq <- @all_freqs -- [10_000] do
|
||||
config = BandConfig.get(freq)
|
||||
assert config.humidity_effect == :harmful, "#{freq} should be :harmful"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue