70 lines
2.0 KiB
Python
70 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from math import log10
|
|
|
|
from app.core.geo import GeoPoint, haversine
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class LinkBudget:
|
|
distance_km: float
|
|
fspl_db: float
|
|
diffraction_db: float
|
|
vegetation_db: float
|
|
atmospheric_db: float
|
|
total_loss_db: float
|
|
rx_power_dbm: float
|
|
fade_margin_db: float
|
|
fresnel_clear: bool
|
|
link_viable: bool
|
|
|
|
|
|
def fspl(freq_mhz: float, dist_km: float) -> float:
|
|
if freq_mhz <= 0:
|
|
raise ValueError("freq_mhz must be positive")
|
|
if dist_km <= 0:
|
|
raise ValueError("dist_km must be positive")
|
|
return 32.44 + 20 * log10(freq_mhz) + 20 * log10(dist_km)
|
|
|
|
|
|
def itm_loss(*args: object, **kwargs: object) -> float:
|
|
raise NotImplementedError("Longley-Rice ITM integration is implemented in a later stage")
|
|
|
|
|
|
def p1812_field(*args: object, **kwargs: object) -> float:
|
|
raise NotImplementedError("ITU-R P.1812 integration is implemented in a later stage")
|
|
|
|
|
|
def manual_link_budget(
|
|
tx: GeoPoint,
|
|
rx: GeoPoint,
|
|
tx_power_dbm: float,
|
|
tx_gain_dbi: float,
|
|
rx_gain_dbi: float,
|
|
sensitivity_dbm: float,
|
|
frequency_mhz: float,
|
|
diffraction_db: float = 0.0,
|
|
vegetation_db: float = 0.0,
|
|
atmospheric_db: float = 0.0,
|
|
misc_loss_db: float = 0.0,
|
|
fresnel_clear: bool = True,
|
|
) -> LinkBudget:
|
|
distance_km = haversine(tx, rx) / 1000.0
|
|
free_space_loss = fspl(frequency_mhz, distance_km)
|
|
total_loss = free_space_loss + diffraction_db + vegetation_db + atmospheric_db + misc_loss_db
|
|
rx_power = tx_power_dbm + tx_gain_dbi + rx_gain_dbi - total_loss
|
|
margin = rx_power - sensitivity_dbm
|
|
return LinkBudget(
|
|
distance_km=distance_km,
|
|
fspl_db=free_space_loss,
|
|
diffraction_db=diffraction_db,
|
|
vegetation_db=vegetation_db,
|
|
atmospheric_db=atmospheric_db,
|
|
total_loss_db=total_loss,
|
|
rx_power_dbm=rx_power,
|
|
fade_margin_db=margin,
|
|
fresnel_clear=fresnel_clear,
|
|
link_viable=margin > 0 and fresnel_clear,
|
|
)
|