feat(beacons): plot-path link seeds TX chain to match beacon EIRP
The "Plot path to beacon" action now includes `tx_power_dbm` and `src_gain_dbi` in the /path query string so the path calculator's TX side emits the same EIRP as the beacon out of the box. The beacon schema stores `power_mw` as EIRP already (per Beacons.RangeEstimate), so we take 10·log10(power_mw), split against a default 30 dBi dish, and clamp the TX power to a 0 dBm floor so very-low-EIRP beacons produce a sane gain/power split instead of -10 dBm outputs. Examples: 10 W EIRP (40 dBm) → 30 dBi dish + 10 dBm TX 100 W EIRP (50 dBm) → 30 dBi dish + 20 dBm TX 100 mW EIRP (20 dBm) → 20 dBi + 0 dBm (clamped)
This commit is contained in:
parent
fbec454917
commit
5dea91d43f
2 changed files with 50 additions and 1 deletions
|
|
@ -285,11 +285,41 @@ defmodule MicrowavepropWeb.BeaconLive.Show do
|
|||
"dst_height_ft" => to_string(beacon.height_ft)
|
||||
}
|
||||
|
||||
params = maybe_put(base, "band", BandResolver.resolve_as_string(beacon.frequency_mhz))
|
||||
{tx_power_dbm, src_gain_dbi} = baseline_tx_for_eirp(beacon.power_mw)
|
||||
|
||||
params =
|
||||
base
|
||||
|> maybe_put("band", BandResolver.resolve_as_string(beacon.frequency_mhz))
|
||||
|> maybe_put("tx_power_dbm", tx_power_dbm)
|
||||
|> maybe_put("src_gain_dbi", src_gain_dbi)
|
||||
|
||||
"/path?" <> URI.encode_query(params)
|
||||
end
|
||||
|
||||
# Splits the beacon's EIRP (the beacon schema's `power_mw` field is
|
||||
# already an EIRP value, per Beacons.RangeEstimate) into a
|
||||
# tx_power_dbm + src_gain_dbi pair so the path calculator's TX chain
|
||||
# emits the same EIRP as the beacon. We default the antenna gain to
|
||||
# 30 dBi (typical 2-3 ft microwave dish) and derive the TX power from
|
||||
# there, clamping to a 0 dBm / 1 mW minimum so very-low-EIRP beacons
|
||||
# produce sane baseline values instead of -10 dBm absurdities.
|
||||
defp baseline_tx_for_eirp(nil), do: {nil, nil}
|
||||
defp baseline_tx_for_eirp(power_mw) when power_mw <= 0, do: {nil, nil}
|
||||
|
||||
defp baseline_tx_for_eirp(power_mw) do
|
||||
eirp_dbm = 10.0 * :math.log10(power_mw)
|
||||
default_gain = 30.0
|
||||
min_tx_dbm = 0.0
|
||||
|
||||
tx_dbm = max(min_tx_dbm, eirp_dbm - default_gain)
|
||||
gain_dbi = eirp_dbm - tx_dbm
|
||||
|
||||
{format_dbm(tx_dbm), format_dbi(gain_dbi)}
|
||||
end
|
||||
|
||||
defp format_dbm(v), do: v |> Float.round(1) |> to_string()
|
||||
defp format_dbi(v), do: v |> Float.round(1) |> to_string()
|
||||
|
||||
defp precise_grid(%Beacon{lat: lat, lon: lon}) when is_number(lat) and is_number(lon) do
|
||||
Maidenhead.from_latlon(lat, lon, 8)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -92,6 +92,25 @@ defmodule MicrowavepropWeb.BeaconLiveTest do
|
|||
{:ok, _view, html} = live(conn, ~p"/beacons/#{beacon}")
|
||||
assert html =~ "Pending approval"
|
||||
end
|
||||
|
||||
test "plot-path-to-beacon link pre-populates tx_power + gain to match beacon EIRP",
|
||||
%{conn: conn} do
|
||||
# power_mw: 10_000 → EIRP 40 dBm → default-gain 30 dBi → tx 10 dBm
|
||||
beacon = approved_beacon_fixture(user_fixture(), power_mw: 10_000.0)
|
||||
{:ok, _view, html} = live(conn, ~p"/beacons/#{beacon}")
|
||||
|
||||
assert html =~ "tx_power_dbm=10.0"
|
||||
assert html =~ "src_gain_dbi=30.0"
|
||||
end
|
||||
|
||||
test "low-EIRP beacon clamps tx_power to 0 dBm floor and lowers gain", %{conn: conn} do
|
||||
# power_mw: 100 → EIRP 20 dBm → tx 0 dBm (clamped), gain 20 dBi
|
||||
beacon = approved_beacon_fixture(user_fixture(), power_mw: 100.0, callsign: "W5LOW")
|
||||
{:ok, _view, html} = live(conn, ~p"/beacons/#{beacon}")
|
||||
|
||||
assert html =~ "tx_power_dbm=0.0"
|
||||
assert html =~ "src_gain_dbi=20.0"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Form" do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue