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