Major refactoring of RFCP backend: - Modular propagation models (8 models) - SharedMemoryManager for terrain data - ProcessPoolExecutor parallel processing - WebSocket progress streaming - Building filtering pipeline (351k → 15k) - 82 unit tests Performance: Standard preset 38s → 5s (7.6x speedup) Known issue: Detailed preset timeout (fix in 3.1.0)
66 lines
1.8 KiB
Python
66 lines
1.8 KiB
Python
"""
|
|
Coverage result aggregation and statistics.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import List
|
|
|
|
|
|
@dataclass
|
|
class PointResult:
|
|
lat: float
|
|
lon: float
|
|
rsrp: float
|
|
distance: float
|
|
path_loss: float
|
|
terrain_loss: float
|
|
building_loss: float
|
|
diffraction_loss: float
|
|
has_los: bool
|
|
model_used: str
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"lat": self.lat, "lon": self.lon,
|
|
"rsrp": self.rsrp, "distance": self.distance,
|
|
"path_loss": self.path_loss, "terrain_loss": self.terrain_loss,
|
|
"building_loss": self.building_loss, "diffraction_loss": self.diffraction_loss,
|
|
"has_los": self.has_los, "model_used": self.model_used,
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class CoverageResult:
|
|
points: List[PointResult]
|
|
stats: dict
|
|
computation_time: float
|
|
models_used: List[str]
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"points": [p.to_dict() for p in self.points],
|
|
"count": len(self.points),
|
|
"stats": self.stats,
|
|
"computation_time": round(self.computation_time, 2),
|
|
"models_used": self.models_used,
|
|
}
|
|
|
|
|
|
def compute_stats(points: List[PointResult]) -> dict:
|
|
if not points:
|
|
return {"min_rsrp": 0, "max_rsrp": 0, "avg_rsrp": 0,
|
|
"los_percentage": 0, "total_points": 0}
|
|
|
|
rsrp_values = [p.rsrp for p in points]
|
|
los_count = sum(1 for p in points if p.has_los)
|
|
|
|
return {
|
|
"min_rsrp": min(rsrp_values),
|
|
"max_rsrp": max(rsrp_values),
|
|
"avg_rsrp": sum(rsrp_values) / len(rsrp_values),
|
|
"los_percentage": los_count / len(points) * 100,
|
|
"total_points": len(points),
|
|
"points_with_buildings": sum(1 for p in points if p.building_loss > 0),
|
|
"points_with_terrain_loss": sum(1 for p in points if p.terrain_loss > 0),
|
|
}
|