Files
RadioTestApi/app/services/coverage.py
T
2026-06-17 13:26:35 +03:00

71 lines
2.3 KiB
Python

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,
}