@mytec: iter1.6.1 ready for testing
This commit is contained in:
98
backend/app/services/atmospheric_service.py
Normal file
98
backend/app/services/atmospheric_service.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import math
|
||||
|
||||
|
||||
class AtmosphericService:
|
||||
"""ITU-R P.676 atmospheric absorption model"""
|
||||
|
||||
# Simplified model for frequencies < 50 GHz
|
||||
# Standard atmosphere: T=15C, P=1013 hPa, humidity=50%
|
||||
|
||||
def calculate_atmospheric_loss(
|
||||
self,
|
||||
frequency_mhz: float,
|
||||
distance_km: float,
|
||||
temperature_c: float = 15.0,
|
||||
humidity_percent: float = 50.0,
|
||||
altitude_m: float = 0.0,
|
||||
) -> float:
|
||||
"""
|
||||
Calculate atmospheric absorption loss
|
||||
|
||||
Args:
|
||||
frequency_mhz: Frequency in MHz
|
||||
distance_km: Path length in km
|
||||
temperature_c: Temperature in Celsius
|
||||
humidity_percent: Relative humidity (0-100)
|
||||
altitude_m: Altitude above sea level
|
||||
|
||||
Returns:
|
||||
Loss in dB
|
||||
"""
|
||||
freq_ghz = frequency_mhz / 1000
|
||||
|
||||
# Below 1 GHz - negligible
|
||||
if freq_ghz < 1.0:
|
||||
return 0.0
|
||||
|
||||
# Calculate specific attenuation (dB/km)
|
||||
gamma = self._specific_attenuation(freq_ghz, temperature_c, humidity_percent)
|
||||
|
||||
# Altitude correction (less atmosphere at higher altitudes)
|
||||
altitude_factor = math.exp(-altitude_m / 8500) # Scale height ~8.5km
|
||||
|
||||
loss = gamma * distance_km * altitude_factor
|
||||
|
||||
return min(loss, 20.0) # Cap for reasonable distances
|
||||
|
||||
def _specific_attenuation(
|
||||
self,
|
||||
freq_ghz: float,
|
||||
temperature_c: float,
|
||||
humidity_percent: float,
|
||||
) -> float:
|
||||
"""
|
||||
Calculate specific attenuation in dB/km
|
||||
|
||||
Simplified ITU-R P.676 model
|
||||
"""
|
||||
# Water vapor density (g/m3) - simplified
|
||||
# Saturation vapor pressure (hPa)
|
||||
es = 6.1121 * math.exp(
|
||||
(18.678 - temperature_c / 234.5)
|
||||
* (temperature_c / (257.14 + temperature_c))
|
||||
)
|
||||
rho = (humidity_percent / 100) * es * 216.7 / (273.15 + temperature_c)
|
||||
|
||||
# Oxygen absorption (dominant at 60 GHz, minor below 10 GHz)
|
||||
if freq_ghz < 10:
|
||||
gamma_o = 0.001 * freq_ghz ** 2 # Very small
|
||||
elif freq_ghz < 57:
|
||||
gamma_o = 0.001 * (freq_ghz / 10) ** 2.5
|
||||
else:
|
||||
# Near 60 GHz resonance
|
||||
gamma_o = 15.0 # Peak absorption
|
||||
|
||||
# Water vapor absorption (peaks at 22 GHz and 183 GHz)
|
||||
if freq_ghz < 10:
|
||||
gamma_w = 0.0001 * rho * freq_ghz ** 2
|
||||
elif freq_ghz < 50:
|
||||
gamma_w = 0.001 * rho * (freq_ghz / 22) ** 2
|
||||
else:
|
||||
gamma_w = 0.01 * rho
|
||||
|
||||
return gamma_o + gamma_w
|
||||
|
||||
@staticmethod
|
||||
def get_weather_description(loss_db: float) -> str:
|
||||
"""Describe atmospheric conditions based on loss"""
|
||||
if loss_db < 0.1:
|
||||
return "clear"
|
||||
elif loss_db < 0.5:
|
||||
return "normal"
|
||||
elif loss_db < 2.0:
|
||||
return "humid"
|
||||
else:
|
||||
return "foggy"
|
||||
|
||||
|
||||
atmospheric_service = AtmosphericService()
|
||||
Reference in New Issue
Block a user