@mytec: feat: Phase 3.0 Architecture Refactor ✅
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)
This commit is contained in:
75
backend/app/propagation/longley_rice.py
Normal file
75
backend/app/propagation/longley_rice.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Longley-Rice Irregular Terrain Model (ITM).
|
||||
|
||||
Best for:
|
||||
- VHF/UHF over irregular terrain
|
||||
- Point-to-point links
|
||||
- Distances 1-2000 km
|
||||
|
||||
Note: This is a simplified area-mode version.
|
||||
Full implementation requires terrain profile data.
|
||||
|
||||
Reference: NTIA Report 82-100
|
||||
"""
|
||||
|
||||
import math
|
||||
from app.propagation.base import PropagationModel, PropagationInput, PropagationOutput
|
||||
|
||||
|
||||
class LongleyRiceModel(PropagationModel):
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "Longley-Rice"
|
||||
|
||||
@property
|
||||
def frequency_range(self) -> tuple:
|
||||
return (20, 20000) # 20 MHz to 20 GHz
|
||||
|
||||
@property
|
||||
def distance_range(self) -> tuple:
|
||||
return (1000, 2000000) # 1-2000 km
|
||||
|
||||
def calculate(self, input: PropagationInput) -> PropagationOutput:
|
||||
"""
|
||||
Simplified Longley-Rice (area mode).
|
||||
|
||||
For proper implementation, use splat! or NTIA ITM reference.
|
||||
"""
|
||||
f = input.frequency_mhz
|
||||
d = max(input.distance_m / 1000, 1.0)
|
||||
h1 = max(input.tx_height_m, 1.0)
|
||||
h2 = max(input.rx_height_m, 1.0)
|
||||
|
||||
# Terrain irregularity parameter (simplified)
|
||||
delta_h = input.terrain_roughness_m or 90 # Default: rolling hills
|
||||
|
||||
# Free space loss
|
||||
L_fs = 32.45 + 20 * math.log10(d) + 20 * math.log10(f)
|
||||
|
||||
# Terrain clutter loss (simplified)
|
||||
if delta_h < 10:
|
||||
L_terrain = 0 # Flat
|
||||
elif delta_h < 50:
|
||||
L_terrain = 5 # Gently rolling
|
||||
elif delta_h < 150:
|
||||
L_terrain = 10 # Rolling hills
|
||||
else:
|
||||
L_terrain = 15 # Mountains
|
||||
|
||||
# Height gain
|
||||
h_eff = h1 + h2
|
||||
height_gain = 10 * math.log10(h_eff / 20) if h_eff > 20 else 0
|
||||
|
||||
L = L_fs + L_terrain - height_gain
|
||||
|
||||
return PropagationOutput(
|
||||
path_loss_db=L,
|
||||
model_name=self.name,
|
||||
is_los=delta_h < 10 and d < 10,
|
||||
breakdown={
|
||||
"free_space_loss": L_fs,
|
||||
"terrain_loss": L_terrain,
|
||||
"height_gain": height_gain,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user