""" 无线资源分配信道模型 / Channel model for OFDMA wireless resource allocation. 该模块实现了 3GPP 风格的路径损耗模型和多用户 OFDMA 下行链路系统的复信道增益生成。 所有公式遵循论文中的公式 (5)-(8)。 This module implements the 3GPP-style path loss model and complex channel gain generation for a multi-user OFDMA downlink system. All formulas follow the paper's equations (5)–(8). 作者/Author: Sisyphus-Junior 日期/Date: 2026-02-28 论文引用/Paper Reference: Co-MADDPG based Resource Allocation for Semantic Communication 依赖/Dependencies: numpy """ import numpy as np class ChannelModel: """ 多用户 OFDMA 系统的频率选择性信道模型。 Frequency-selective channel model for multi-user OFDMA systems. 生成包含距离相关路径损耗和瑞利衰落的每子载波复信道增益,并计算每子载波的信噪比 (SNR)。 Generates per-subcarrier complex channel gains incorporating distance-dependent path loss with Rayleigh fading, and computes per-subcarrier SNR values. Parameters ---------- config : dict 完整的配置字典(必须包含 "env" 部分,且具有 carrier_freq, noise_psd 和 subcarrier_spacing 键)。 Full configuration dictionary (must contain an "env" section with keys "carrier_freq", "noise_psd", and "subcarrier_spacing"). """ def __init__(self, config: dict) -> None: # 初始化环境配置 / Initialize environment configurations self.config = config env = config["env"] # 载波频率 (GHz) / Carrier frequency in GHz self._carrier_freq_ghz: float = env["carrier_freq"] # 噪声功率谱密度 (dBm/Hz) / Noise power spectral density in dBm/Hz self._noise_psd_dbm: float = env["noise_psd"] # 子载波间隔 (Hz) / Subcarrier spacing in Hz self._subcarrier_spacing: float = env["subcarrier_spacing"] # ------------------------------------------------------------------ # 路径损耗 / Path loss # ------------------------------------------------------------------ def path_loss(self, distance: float) -> float: """ 计算与距离相关的路径损耗 (dB)。 Compute distance-dependent path loss in dB. 使用 3GPP Urban Micro (UMi) NLOS 模型 (公式 5): Uses the 3GPP Urban Micro (UMi) NLOS model (Eq. 5): PL(d) = 36.7 * log10(d) + 22.7 + 26 * log10(fc) 其中 d 的单位为米,fc 的单位为 GHz。 where *d* is in metres and *fc* is in GHz. Parameters ---------- distance : float or np.ndarray 收发机之间的距离,单位为米。 Transmitter–receiver distance(s) in metres. Returns ------- float or np.ndarray 路径损耗值,单位为 dB。 Path loss value(s) in dB. """ fc = self._carrier_freq_ghz # 应用 3GPP UMi NLOS 公式 / Apply 3GPP UMi NLOS formula - Eq.(5) return 36.7 * np.log10(distance) + 22.7 + 26.0 * np.log10(fc) # ------------------------------------------------------------------ # 信道生成 / Channel generation # ------------------------------------------------------------------ def generate_channel( self, distances: np.ndarray, num_subcarriers: int ) -> np.ndarray: """ 生成所有用户和子载波的复信道增益。 Generate complex channel gains for all users and subcarriers. 每个元素 h_{k,n} 服从复高斯分布 CN(0, 10^{-PL/10}) (公式 6)。 即:独立循环对称复高斯分布,其方差等于线性尺度的逆路径损耗。 Each element h_{k,n} is drawn from CN(0, 10^{-PL/10}) (Eq. 6), i.e. independent circularly-symmetric complex Gaussian with variance equal to the linear-scale inverse path loss. Parameters ---------- distances : array_like, shape (K,) 每个用户距离基站的距离(米)。 Distance of each user from the base station (metres). num_subcarriers : int OFDM 子载波数量 N。 Number of OFDM subcarriers *N*. Returns ------- np.ndarray, shape (K, N) 复信道增益矩阵。 Complex channel gain matrix. """ distances = np.asarray(distances, dtype=np.float64) K = len(distances) N = num_subcarriers # 每用户路径损耗 -> 线性尺度信道方差 / Per-user path loss -> linear-scale channel variance pl_db = self.path_loss(distances) # (K,) # 方差 = 10^(-PL/10) / Variance = 10^(-PL/10) - Eq.(6) variance = 10.0 ** (-pl_db / 10.0) # (K,) variance = variance.reshape(K, 1) # (K, 1) 用于广播 / for broadcasting # 复高斯:每个分量服从 N(0, var/2) / Complex Gaussian: each component ~ N(0, var/2) std = np.sqrt(variance / 2.0) # 生成实部和虚部 / Generate real and imaginary parts real_part = np.random.randn(K, N) * std imag_part = np.random.randn(K, N) * std # 返回复增益 / Return complex gains return real_part + 1j * imag_part # ------------------------------------------------------------------ # SNR 计算 / SNR computation # ------------------------------------------------------------------ def compute_snr( self, channel_gains: np.ndarray, power_alloc: np.ndarray, noise_power: float, ) -> np.ndarray: """ 计算每个用户的每子载波信噪比 (SNR)。 Compute per-subcarrier SNR for every user. γ_{k,n} = p_{k,n} * |h_{k,n}|² / σ² (公式 8) γ_{k,n} = p_{k,n} · |h_{k,n}|² / σ² (Eq. 8) Parameters ---------- channel_gains : np.ndarray, shape (K, N) 复信道增益矩阵。 Complex channel gain matrix. power_alloc : np.ndarray, shape (K, N) 每个用户在每个子载波上分配的功率(瓦特)。 Power allocated by each user on each subcarrier (Watts). noise_power : float 每子载波的噪声功率 σ²(瓦特)。 Noise power σ² per subcarrier (Watts). Returns ------- np.ndarray, shape (K, N) SNR 值(线性尺度)。 SNR values (linear scale). """ # 计算 SNR = 功率 * 增益平方 / 噪声 / Compute SNR = Power * Gain^2 / Noise - Eq.(8) return power_alloc * (np.abs(channel_gains) ** 2) / noise_power # ------------------------------------------------------------------ # 噪声功率属性 / Noise power property # ------------------------------------------------------------------ @property def noise_power(self) -> float: """ 每子载波的热噪声功率 (瓦特)。 Thermal noise power per subcarrier (Watts). σ² = N₀ * Δf (公式 7) σ² = N₀ · Δf (Eq. 7) 其中 N₀ 是从 dBm/Hz 转换为线性 (W/Hz) 的噪声功率谱密度: where N₀ is the noise PSD converted from dBm/Hz to linear (W/Hz): N₀_linear = 10^((N₀_dBm - 30) / 10) Returns ------- float 噪声功率(瓦特)。 Noise power in Watts. """ n0_dbm = self._noise_psd_dbm delta_f = self._subcarrier_spacing # 转换为线性功率谱密度 / Convert to linear PSD - Eq.(7) n0_linear = 10.0 ** ((n0_dbm - 30.0) / 10.0) # 计算总噪声功率 / Compute total noise power return n0_linear * delta_f