first commit
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from app.config import settings
|
||||
from app.models.schemas import CoverageRequest, GeoAntenna
|
||||
from app.services.geodesy import grid_in_circle, line_distance_m
|
||||
from app.services.link_calculator import LinkCalculator
|
||||
|
||||
|
||||
class CoverageService:
|
||||
def __init__(self, link_calculator: LinkCalculator) -> None:
|
||||
self.link_calculator = link_calculator
|
||||
|
||||
async def calculate_coverage(self, request: CoverageRequest) -> dict[str, Any]:
|
||||
grid_points = grid_in_circle(
|
||||
request.origin.lat,
|
||||
request.origin.lng,
|
||||
request.radius_m,
|
||||
request.resolution_m,
|
||||
)
|
||||
|
||||
if len(grid_points) > settings.max_grid_points:
|
||||
raise ValueError(
|
||||
f"Grid has {len(grid_points)} points, exceeds max_grid_points={settings.max_grid_points}"
|
||||
)
|
||||
|
||||
semaphore = asyncio.Semaphore(settings.coverage_concurrency)
|
||||
features: list[dict[str, Any]] = []
|
||||
|
||||
async def evaluate_point(lat: float, lng: float) -> dict[str, Any]:
|
||||
async with semaphore:
|
||||
to_point = GeoAntenna(lat=lat, lng=lng, antenna_height_m=request.origin.antenna_height_m)
|
||||
result = await self.link_calculator.calculate_link(
|
||||
from_pt=request.origin,
|
||||
to_pt=to_point,
|
||||
frequency_mhz=request.frequency_mhz,
|
||||
fresnel_clearance=request.fresnel_clearance,
|
||||
tx_power_dbm=request.tx_power_dbm,
|
||||
rx_sensitivity_dbm=request.rx_sensitivity_dbm,
|
||||
sample_step_m=request.sample_step_m,
|
||||
)
|
||||
|
||||
covered = result.los and result.fresnel_clear and result.link_budget.status != "poor"
|
||||
distance = line_distance_m(request.origin.lat, request.origin.lng, lat, lng)
|
||||
|
||||
return {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [round(lng, 6), round(lat, 6)],
|
||||
},
|
||||
"properties": {
|
||||
"covered": covered,
|
||||
"los": result.los,
|
||||
"fresnel_clear": result.fresnel_clear,
|
||||
"margin_db": result.link_budget.margin_db,
|
||||
"status": result.link_budget.status,
|
||||
"distance_m": round(distance, 1),
|
||||
},
|
||||
}
|
||||
|
||||
tasks = [evaluate_point(lat, lng) for lat, lng in grid_points]
|
||||
features = await asyncio.gather(*tasks)
|
||||
|
||||
return {
|
||||
"type": "FeatureCollection",
|
||||
"features": features,
|
||||
}
|
||||
Reference in New Issue
Block a user