@mytec: iter1.6.1 ready for testing
This commit is contained in:
82
backend/app/services/indoor_service.py
Normal file
82
backend/app/services/indoor_service.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import math
|
||||
|
||||
|
||||
class IndoorService:
|
||||
"""ITU-R P.2109 building entry loss model"""
|
||||
|
||||
# Building Entry Loss (BEL) by construction type at 2 GHz
|
||||
# Format: (median_loss_dB, std_dev_dB)
|
||||
BUILDING_TYPES = {
|
||||
"none": (0.0, 0.0), # Outdoor only
|
||||
"light": (8.0, 4.0), # Wood frame, large windows
|
||||
"medium": (15.0, 6.0), # Brick, standard windows
|
||||
"heavy": (22.0, 8.0), # Concrete, small windows
|
||||
"basement": (30.0, 10.0), # Underground
|
||||
"vehicle": (6.0, 3.0), # Inside car
|
||||
"train": (20.0, 5.0), # Inside train
|
||||
}
|
||||
|
||||
# Frequency correction factor (dB per octave above 2 GHz)
|
||||
FREQ_CORRECTION = 2.5
|
||||
|
||||
def calculate_indoor_loss(
|
||||
self,
|
||||
frequency_mhz: float,
|
||||
building_type: str = "medium",
|
||||
floor_number: int = 0,
|
||||
depth_m: float = 0.0,
|
||||
) -> float:
|
||||
"""
|
||||
Calculate building entry/indoor penetration loss
|
||||
|
||||
Args:
|
||||
frequency_mhz: Frequency in MHz
|
||||
building_type: Type of building construction
|
||||
floor_number: Floor number (0=ground, negative=basement)
|
||||
depth_m: Distance from exterior wall in meters
|
||||
|
||||
Returns:
|
||||
Loss in dB
|
||||
"""
|
||||
if building_type == "none":
|
||||
return 0.0
|
||||
|
||||
base_loss, _ = self.BUILDING_TYPES.get(building_type, (15.0, 6.0))
|
||||
|
||||
# Frequency correction
|
||||
freq_ghz = frequency_mhz / 1000
|
||||
if freq_ghz > 2.0:
|
||||
octaves = math.log2(freq_ghz / 2.0)
|
||||
freq_correction = self.FREQ_CORRECTION * octaves
|
||||
else:
|
||||
freq_correction = 0.0
|
||||
|
||||
# Floor correction (higher floors = less loss due to better angle)
|
||||
if floor_number > 0:
|
||||
floor_correction = -1.5 * min(floor_number, 10)
|
||||
elif floor_number < 0:
|
||||
# Basement - additional loss
|
||||
floor_correction = 5.0 * abs(floor_number)
|
||||
else:
|
||||
floor_correction = 0.0
|
||||
|
||||
# Depth correction (signal attenuates inside building)
|
||||
# Approximately 0.5 dB per meter for first 10m
|
||||
depth_correction = 0.5 * min(depth_m, 20)
|
||||
|
||||
total_loss = base_loss + freq_correction + floor_correction + depth_correction
|
||||
|
||||
return max(0.0, min(total_loss, 50.0)) # Clamp 0-50 dB
|
||||
|
||||
def calculate_outdoor_to_indoor_coverage(
|
||||
self,
|
||||
outdoor_rsrp: float,
|
||||
building_type: str,
|
||||
frequency_mhz: float,
|
||||
) -> float:
|
||||
"""Calculate expected indoor RSRP from outdoor signal"""
|
||||
indoor_loss = self.calculate_indoor_loss(frequency_mhz, building_type)
|
||||
return outdoor_rsrp - indoor_loss
|
||||
|
||||
|
||||
indoor_service = IndoorService()
|
||||
Reference in New Issue
Block a user