prop/test/microwaveprop/propagation/path_compute_test.exs
2026-05-07 16:04:32 -05:00

124 lines
4.6 KiB
Elixir

defmodule Microwaveprop.Propagation.PathComputeTest do
use ExUnit.Case, async: true
use ExUnitProperties
alias Microwaveprop.Propagation.BandConfig
alias Microwaveprop.Propagation.PathCompute
describe "compute_loss_budget/5" do
test "fspl increases with distance" do
band = BandConfig.get(10_000)
near = PathCompute.compute_loss_budget(10.0, 10.0, band, nil, nil)
far = PathCompute.compute_loss_budget(100.0, 10.0, band, nil, nil)
assert near.fspl < far.fspl
assert near.total < far.total
end
test "fspl increases with frequency" do
band_10g = BandConfig.get(10_000)
band_24g = BandConfig.get(24_000)
low = PathCompute.compute_loss_budget(50.0, 10.0, band_10g, nil, nil)
high = PathCompute.compute_loss_budget(50.0, 24.0, band_24g, nil, nil)
assert low.fspl < high.fspl
end
test "gas absorption losses with default humidity when conditions absent" do
band = BandConfig.get(10_000)
result = PathCompute.compute_loss_budget(50.0, 10.0, band, nil, nil)
assert result.o2 >= 0
assert result.h2o >= 0
end
test "higher bands have more h2o absorption" do
band_10g = BandConfig.get(10_000)
band_75g = BandConfig.get(75_000)
low = PathCompute.compute_loss_budget(50.0, 10.0, band_10g, nil, nil)
high = PathCompute.compute_loss_budget(50.0, 75.0, band_75g, nil, nil)
assert low.h2o <= high.h2o
end
test "rain loss is zero when there's no rain" do
band = BandConfig.get(10_000)
conditions = %{rain_rate_mmhr: 0.0, abs_humidity: 7.5}
result = PathCompute.compute_loss_budget(50.0, 10.0, band, nil, conditions)
assert result.rain == 0.0
end
test "rain loss is positive when it's raining" do
band = BandConfig.get(10_000)
conditions = %{rain_rate_mmhr: 5.0, abs_humidity: 7.5}
result = PathCompute.compute_loss_budget(50.0, 10.0, band, nil, conditions)
assert result.rain > 0
end
test "diffraction loss is included when terrain result is present" do
band = BandConfig.get(10_000)
terrain = %{analysis: %{diffraction_db: 15.0}}
result = PathCompute.compute_loss_budget(50.0, 10.0, band, terrain, nil)
assert result.diffraction == 15.0
end
test "diffraction loss is zero when no terrain result" do
band = BandConfig.get(10_000)
result = PathCompute.compute_loss_budget(50.0, 10.0, band, nil, nil)
assert result.diffraction == 0.0
end
end
describe "compute_loss_budget/5 property" do
property "total is always >= fspl" do
check all(
dist_km <- float(min: 0.1, max: 500),
band_config = BandConfig.get(10_000)
) do
result = PathCompute.compute_loss_budget(dist_km, 10.0, band_config, nil, nil)
assert result.total >= result.fspl
assert result.total > 0
end
end
property "all loss components are non-negative across known bands" do
bands = [50, 144, 222, 432, 902, 1_296, 2_304, 3_400, 5_760, 10_000, 24_000, 47_000, 75_000]
check all(
dist_km <- float(min: 0.1, max: 500),
band_mhz <- member_of(bands)
) do
band_config = BandConfig.get(band_mhz)
freq_ghz = band_mhz / 1000
result = PathCompute.compute_loss_budget(dist_km, freq_ghz, band_config, nil, nil)
assert result.fspl >= 0
assert result.o2 >= 0
assert result.h2o >= 0
assert result.rain >= 0
assert result.diffraction >= 0
end
end
end
describe "compute_power_budget/2" do
test "computes rx power and margins" do
loss = %{total: 140.0, fspl: 130.0, o2: 3.0, h2o: 5.0, rain: 0.0, diffraction: 2.0}
params = %{tx_power_dbm: 30.0, src_gain_dbi: 20.0, dst_gain_dbi: 20.0}
result = PathCompute.compute_power_budget(params, loss)
# EIRP = tx_power + src_gain = 50 dBm
assert_in_delta result.eirp_dbm, 50.0, 0.1
# rx_power = eirp - loss + dst_gain
assert_in_delta result.rx_power_dbm, -70.0, 0.1
# margin_cw = rx_power - (-140)
assert_in_delta result.margin_cw, 70.0, 0.1
end
test "higher tx power improves margins" do
loss = %{total: 140.0, fspl: 130.0, o2: 3.0, h2o: 5.0, rain: 0.0, diffraction: 2.0}
low = PathCompute.compute_power_budget(%{tx_power_dbm: 20.0, src_gain_dbi: 10.0, dst_gain_dbi: 10.0}, loss)
high = PathCompute.compute_power_budget(%{tx_power_dbm: 30.0, src_gain_dbi: 20.0, dst_gain_dbi: 20.0}, loss)
assert low.rx_power_dbm < high.rx_power_dbm
assert low.margin_cw < high.margin_cw
end
end
end