Source code for pytwinnet.physics.propagation


from __future__ import annotations
import math
import numpy as np
from abc import ABC, abstractmethod
from ..core.node import WirelessNode
from .environment import Environment

[docs] class PropagationModel(ABC):
[docs] @abstractmethod def calculate_path_loss(self, tx: WirelessNode, rx: WirelessNode, environment: Environment) -> float: ...
[docs] class FreeSpacePathLoss(PropagationModel):
[docs] def calculate_path_loss(self, tx: WirelessNode, rx: WirelessNode, environment: Environment) -> float: dx = tx.position[0] - rx.position[0] dy = tx.position[1] - rx.position[1] dz = tx.position[2] - rx.position[2] d_m = math.sqrt(dx*dx + dy*dy + dz*dz) d_km = max(d_m, 1e-3) / 1000.0 f_mhz = max(tx.transceiver_properties.carrier_frequency_hz, 1.0) / 1e6 return 20.0 * math.log10(d_km) + 20.0 * math.log10(f_mhz) + 32.44
[docs] def faded_shadowed_model(d: float, freq_ghz: float, tx_power_dbm: float, n: float = 2.0, sigma: float = 6.0) -> float: """Log-distance with lognormal shadowing + Rayleigh fading; returns Rx power (dBm).""" f_hz = freq_ghz * 1e9 # FSPL baseline fspl = FreeSpacePathLoss().calculate_path_loss_scalar(d, f_hz) \ if hasattr(FreeSpacePathLoss(), "calculate_path_loss_scalar") \ else FreeSpacePathLoss()._path_loss_scalar(d, f_hz) # Log-distance tweak ref1 = FreeSpacePathLoss()._path_loss_scalar(1.0, f_hz) pl_db = ref1 + 10*n*np.log10(max(d, 1e-3)) # Shadowing + fading shadow = np.random.normal(0.0, sigma) ray = np.random.rayleigh(1.0) fading_db = 20*np.log10(ray + 1e-12) path_loss = 0.5*(fspl + pl_db) + shadow - fading_db return tx_power_dbm - path_loss