import math class WeatherService: """ITU-R P.838 rain attenuation model""" # ITU-R P.838-3 coefficients for horizontal polarization # Format: (frequency_GHz, k, alpha) RAIN_COEFFICIENTS = { 0.7: (0.0000387, 0.912), 1.0: (0.0000887, 0.949), 1.8: (0.000292, 1.021), 2.1: (0.000425, 1.052), 2.6: (0.000683, 1.091), 3.5: (0.00138, 1.149), 5.0: (0.00361, 1.206), 10.0: (0.0245, 1.200), 20.0: (0.0906, 1.099), 30.0: (0.175, 1.021), } def calculate_rain_attenuation( self, frequency_mhz: float, distance_km: float, rain_rate: float, # mm/h ) -> float: """ Calculate rain attenuation in dB Args: frequency_mhz: Frequency in MHz distance_km: Path length in km rain_rate: Rain rate in mm/h (0=none, 5=light, 25=moderate, 50=heavy) Returns: Attenuation in dB """ if rain_rate <= 0: return 0.0 freq_ghz = frequency_mhz / 1000 # Get interpolated coefficients k, alpha = self._get_coefficients(freq_ghz) # Specific attenuation (dB/km) gamma_r = k * (rain_rate ** alpha) # Effective path length reduction for longer paths # Rain cells are typically 2-5 km if distance_km > 2: reduction_factor = 1 / (1 + distance_km / 35) effective_distance = distance_km * reduction_factor else: effective_distance = distance_km attenuation = gamma_r * effective_distance return min(attenuation, 30.0) # Cap at 30 dB def _get_coefficients(self, freq_ghz: float) -> tuple[float, float]: """Interpolate rain coefficients for frequency""" freqs = sorted(self.RAIN_COEFFICIENTS.keys()) # Find surrounding frequencies if freq_ghz <= freqs[0]: return self.RAIN_COEFFICIENTS[freqs[0]] if freq_ghz >= freqs[-1]: return self.RAIN_COEFFICIENTS[freqs[-1]] for i in range(len(freqs) - 1): if freqs[i] <= freq_ghz <= freqs[i + 1]: f1, f2 = freqs[i], freqs[i + 1] k1, a1 = self.RAIN_COEFFICIENTS[f1] k2, a2 = self.RAIN_COEFFICIENTS[f2] # Linear interpolation t = (freq_ghz - f1) / (f2 - f1) k = k1 + t * (k2 - k1) alpha = a1 + t * (a2 - a1) return k, alpha return self.RAIN_COEFFICIENTS[freqs[0]] @staticmethod def rain_rate_from_description(description: str) -> float: """Convert rain description to rate""" rates = { "none": 0.0, "drizzle": 2.5, "light": 5.0, "moderate": 12.5, "heavy": 25.0, "very_heavy": 50.0, "extreme": 100.0, } return rates.get(description.lower(), 0.0) weather_service = WeatherService()