Source code for urbanmarl.models.channel

"""UrbanMARL Radio Channel Model.

Vectorized mmWave radio channel propagation model calculating Friis path loss,
LoS/NLoS attenuation exponent shifts, interference, and Shannon channel capacity.
"""

import torch


[docs] class VectorizedChannelModel: """Computes batched path loss, received power, interference, and data rates. Attributes: device (torch.device): Compute device for PyTorch tensor calculations. freq_ghz (float): Carrier frequency in Gigahertz (e.g. 29.0 GHz mmWave). bandwidth (float): Transmit channel bandwidth in Hertz. noise_figure_db (float): Receiver noise figure in decibels. noise_power (float): Receiver thermal noise power in Watts. """
[docs] def __init__(self, config: dict, device: torch.device) -> None: """Initializes the VectorizedChannelModel. Args: config (dict): Channel configuration dictionary containing optional keys: - 'frequency_ghz': carrier frequency in GHz (default: 29.0). - 'g2a_bandwidth': channel bandwidth in Hz (default: 10e6). - 'noise_figure_db': noise figure in dB (default: 7.0). device (torch.device): Compute device. """ self.device = device self.freq_ghz = config.get("frequency_ghz", 29.0) self.bandwidth = config.get("g2a_bandwidth", 10e6) self.noise_figure_db = config.get("noise_figure_db", 7.0) k_b = 1.380649e-23 t_k = 290.0 thermal_noise = k_b * t_k * self.bandwidth self.noise_power = thermal_noise * (10 ** (self.noise_figure_db / 10.0))
[docs] def compute_data_rates( self, tx_pos: torch.Tensor, rx_pos: torch.Tensor, tx_power: torch.Tensor, los_mask: torch.Tensor, ) -> torch.Tensor: """Calculates achievable transmission data rates (bps) using Shannon capacity. Args: tx_pos (torch.Tensor): Transmitter positions (UEs) of shape (B, M, 3). rx_pos (torch.Tensor): Receiver positions (UAVs) of shape (B, N, 3). tx_power (torch.Tensor): Transmission power (Watts) of shape (B, M). los_mask (torch.Tensor): Line-of-sight boolean tensor of shape (B, N, M). Returns: torch.Tensor: Achievable channel capacity data rates in bps of shape (B, N, M). """ B, M, _ = tx_pos.shape _, N, _ = rx_pos.shape diff = rx_pos.unsqueeze(2) - tx_pos.unsqueeze(1) distances = torch.clamp(torch.norm(diff, dim=-1), min=1.0) c = 299792458.0 freq_hz = self.freq_ghz * 1e9 wavelength = c / freq_hz fspl = (4.0 * torch.pi * distances / wavelength) ** 2 pl_exponent = torch.where(los_mask, 2.0, 3.5) pathloss = fspl * (distances ** (pl_exponent - 2.0)) rx_power = tx_power.unsqueeze(1) / pathloss total_interference = torch.sum(rx_power, dim=2, keepdim=True) - rx_power sinr = rx_power / (total_interference + self.noise_power) capacity = self.bandwidth * torch.log2(1.0 + sinr) return capacity