added covarage
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
from itmlogic.misc.qerfi import qerfi
|
||||
from itmlogic.preparatory_subroutines.qlrpfl import qlrpfl
|
||||
from itmlogic.statistics.avar import avar
|
||||
|
||||
from app.config import get_settings
|
||||
from app.core.dem import elevations_along
|
||||
from app.core.geo import GeoPoint, haversine, sample_path
|
||||
|
||||
_DB = 8.685890
|
||||
|
||||
|
||||
def _climate_code(environment: str) -> int:
|
||||
mapping = {
|
||||
"urban": 5,
|
||||
"suburban": 6,
|
||||
"rural": 7,
|
||||
}
|
||||
return mapping.get(environment, 7)
|
||||
|
||||
|
||||
def _build_prop(
|
||||
*,
|
||||
freq_mhz: float,
|
||||
distance_km: float,
|
||||
tx_height_m: float,
|
||||
rx_height_m: float,
|
||||
surface_profile_m: list[float],
|
||||
climate: int,
|
||||
) -> dict:
|
||||
prop: dict = {
|
||||
"fmhz": freq_mhz,
|
||||
"d": distance_km,
|
||||
"hg": [tx_height_m, rx_height_m],
|
||||
"ipol": 0,
|
||||
"eps": 15,
|
||||
"sgm": 0.005,
|
||||
"klim": climate,
|
||||
"ens0": 314,
|
||||
"lvar": 5,
|
||||
"gma": 157e-9,
|
||||
"kwx": 0,
|
||||
"wn": freq_mhz / 47.7,
|
||||
"ens": 314,
|
||||
"mdvarx": 11,
|
||||
"klimx": 0,
|
||||
}
|
||||
|
||||
pfl = [len(surface_profile_m) - 1, 0, *surface_profile_m]
|
||||
if pfl[0] > 0:
|
||||
pfl[1] = distance_km * 1000 / pfl[0]
|
||||
prop["pfl"] = pfl
|
||||
prop["gme"] = prop["gma"] * (1 - 0.04665 * math.exp(prop["ens"] / 179.3))
|
||||
zq = complex(prop["eps"], 376.62 * prop["sgm"] / prop["wn"])
|
||||
prop["zgnd"] = np.sqrt(zq - 1)
|
||||
prop = qlrpfl(prop)
|
||||
return prop
|
||||
|
||||
|
||||
def itm_path_loss(
|
||||
tx: GeoPoint,
|
||||
rx: GeoPoint,
|
||||
*,
|
||||
tx_height_agl: float,
|
||||
rx_height_agl: float,
|
||||
freq_mhz: float,
|
||||
elevation_profile_m: list[float] | None = None,
|
||||
dem_path: str | None = None,
|
||||
climate: int = 5,
|
||||
) -> float:
|
||||
distance_km = haversine(tx, rx) / 1000.0
|
||||
if elevation_profile_m is None:
|
||||
points = sample_path(tx, rx, 64)
|
||||
try:
|
||||
elevation_profile_m = elevations_along(
|
||||
points,
|
||||
dem_path=dem_path or get_settings().dem_path,
|
||||
).tolist()
|
||||
except Exception:
|
||||
elevation_profile_m = [0.0, 0.0]
|
||||
|
||||
profile = [float(value) for value in elevation_profile_m]
|
||||
if profile:
|
||||
profile[0] = profile[0] + tx_height_agl
|
||||
profile[-1] = profile[-1] + rx_height_agl
|
||||
|
||||
prop = _build_prop(
|
||||
freq_mhz=freq_mhz,
|
||||
distance_km=distance_km,
|
||||
tx_height_m=profile[0] if profile else tx_height_agl,
|
||||
rx_height_m=profile[-1] if profile else rx_height_agl,
|
||||
surface_profile_m=profile,
|
||||
climate=climate,
|
||||
)
|
||||
fs = _DB * math.log(2 * prop["wn"] * prop["dist"])
|
||||
zr = qerfi([0.5])
|
||||
zc = qerfi([0.5])
|
||||
correction, _ = avar(zr[0], 0, zc[0], prop)
|
||||
return float(fs + correction)
|
||||
|
||||
|
||||
def p1812_path_loss(
|
||||
tx: GeoPoint,
|
||||
rx: GeoPoint,
|
||||
*,
|
||||
tx_height_agl: float,
|
||||
rx_height_agl: float,
|
||||
freq_mhz: float,
|
||||
environment: str,
|
||||
elevation_profile_m: list[float] | None = None,
|
||||
dem_path: str | None = None,
|
||||
) -> float:
|
||||
climate = _climate_code(environment)
|
||||
base_loss = itm_path_loss(
|
||||
tx,
|
||||
rx,
|
||||
tx_height_agl=tx_height_agl,
|
||||
rx_height_agl=rx_height_agl,
|
||||
freq_mhz=freq_mhz,
|
||||
elevation_profile_m=elevation_profile_m,
|
||||
dem_path=dem_path,
|
||||
climate=climate,
|
||||
)
|
||||
clutter_db = {
|
||||
"urban": 8.0,
|
||||
"suburban": 4.0,
|
||||
"rural": 0.0,
|
||||
}.get(environment, 0.0)
|
||||
return base_loss + clutter_db
|
||||
Reference in New Issue
Block a user