64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
from pyproj import Geod
|
|
|
|
from app.core.antenna import AntennaPattern, gain
|
|
from app.models.antenna import (
|
|
AntennaPatternSpec,
|
|
BeamRequest,
|
|
BeamResponse,
|
|
PatternResponse,
|
|
PatternSample,
|
|
)
|
|
|
|
_GEOD = Geod(ellps="WGS84")
|
|
|
|
|
|
def _to_core(spec: AntennaPatternSpec) -> AntennaPattern:
|
|
return AntennaPattern(
|
|
pattern=spec.pattern,
|
|
azimuth_deg=spec.azimuth_deg,
|
|
tilt_deg=spec.tilt_deg,
|
|
gain_dbi=spec.gain_dbi,
|
|
beamwidth_h=spec.beamwidth_h,
|
|
beamwidth_v=spec.beamwidth_v,
|
|
front_to_back_db=spec.front_to_back_db,
|
|
sidelobe_floor_db=spec.sidelobe_floor_db,
|
|
)
|
|
|
|
|
|
def normalize_pattern(spec: AntennaPatternSpec) -> PatternResponse:
|
|
pattern = _to_core(spec)
|
|
samples = [
|
|
PatternSample(azimuth_deg=az, elevation_deg=0, gain_dbi=gain(pattern, az, 0))
|
|
for az in range(0, 360, 5)
|
|
]
|
|
return PatternResponse(pattern=spec.pattern, samples=samples)
|
|
|
|
|
|
def beam_geometry(request: BeamRequest) -> BeamResponse:
|
|
antenna = request.antenna
|
|
half_width = (antenna.beamwidth_h or 360.0) / 2.0
|
|
if antenna.pattern == "omni":
|
|
azimuths = list(range(0, 361, 10))
|
|
else:
|
|
start = antenna.azimuth_deg - half_width
|
|
end = antenna.azimuth_deg + half_width
|
|
azimuths = [start + (end - start) * i / 32 for i in range(33)]
|
|
|
|
coords = [[request.origin.lon, request.origin.lat]]
|
|
for azimuth in azimuths:
|
|
lon, lat, _ = _GEOD.fwd(request.origin.lon, request.origin.lat, azimuth, request.radius_m)
|
|
coords.append([lon, lat])
|
|
coords.append([request.origin.lon, request.origin.lat])
|
|
|
|
return BeamResponse(
|
|
geojson={
|
|
"type": "Feature",
|
|
"properties": {
|
|
"pattern": antenna.pattern,
|
|
"azimuth_deg": antenna.azimuth_deg,
|
|
"radius_m": request.radius_m,
|
|
},
|
|
"geometry": {"type": "Polygon", "coordinates": [coords]},
|
|
}
|
|
)
|