downlink_fair_power_control#
- sionna.sys.downlink_fair_power_control(pathloss: torch.Tensor, interference_plus_noise: float | torch.Tensor, num_allocated_re: int | torch.Tensor, bs_max_power_dbm: float | torch.Tensor = 56.0, guaranteed_power_ratio: float = 0.5, fairness: float = 0.0, return_lagrangian: bool = False, precision: Literal['single', 'double'] | None = None, **kwargs) Tuple[torch.Tensor, torch.Tensor] | Tuple[torch.Tensor, torch.Tensor, torch.Tensor][source]#
Allocates the downlink transmit power fairly across all users served by a single base station (BS).
The maximum BS transmit power \(\overline{P}\) is distributed across users by solving the following optimization problem:
\[\begin{split}\begin{aligned} \mathbf{p}^* = \operatorname{argmax}_{\mathbf{p}} & \, \sum_{u=1}^{U} g^{(f)} \big( r_u \log( 1 + p_u q_u) \big) \\ \mathrm{s.t.} & \, \sum_{u=1}^U r_u p_u = \overline{P} \\ & r_u p_u \ge \rho \frac{\overline{P}}{U} , \quad \forall \, u=1,\dots,U \end{aligned}\end{split}\]where \(q_u\) represents the estimated channel quality, defined as the ratio between the channel gain (being the inverse of pathloss) and the interference plus noise ratio, \(r_u>0\) denotes the number of allocated resources, and \(p_u\) is the per-resource allocated power, for every user \(u\).
The parameter \(\rho\in[0;1]\) denotes the guaranteed power ratio; if set to 1, the power is distributed uniformly across all users.
The fairness function \(g^{(f)}\) is defined as in [MoWalrand]:
\[\begin{split}\begin{aligned} g^{(f)}(x) = \left\{ \begin{array}{l} \log(x), \quad f=1 \\ \frac{x^{1-f}}{1-f}, \quad \forall\, f>0, \ f\ne 1. \end{array} \right. \end{aligned}\end{split}\]When the fairness parameter \(f=0\), the sum of utilities \(\log( 1 + p_u q_u)\) is maximized, leading to a waterfilling-like solution (see, e.g., [Tse]). As \(f\) increases, the allocation becomes increasingly egalitarian. The case \(f=1\) maximizes proportional fairness; as \(f\to \infty\), the solution approaches a max-min allocation.
For optimal power allocations \(p^*_u>\frac{\overline{P}}{U r_u}\), the Karush-Kuhn-Tucker (KKT) conditions can be expressed as:
\[\big[ r_u \log (1+p^*_u q_u) \big]^f (1+p^*_u q_u) = q_u \mu^{-1}, \quad \forall \, u\]where \(\mu\) is the Lagrangian multiplier associated with the constraint on the total transmit power.
This function returns the optimal power allocation \(r_u p_u^*\) and the corresponding utility \(r_u \log( 1 + p^*_u q_u)\), for each user \(u=1,\dots,U\). If
return_lagrangianis True, \(\mu^{-1}\) is returned, too.- Parameters:
pathloss (torch.Tensor) – Pathloss for each user in linear scale. Shape: […, num_ut].
interference_plus_noise (float | torch.Tensor) – Interference plus noise [Watt] for each user. If float, the same value is assigned to all users. Shape: […, num_ut] or scalar.
num_allocated_re (int | torch.Tensor) – Number of allocated resources to each user. If int, the same value is assigned to all users. Shape: […, num_ut] or scalar.
bs_max_power_dbm (float | torch.Tensor) – Maximum transmit power for the base station [dBm]. If float, the same value is assigned to all batches. Defaults to 56.0.
guaranteed_power_ratio (float) – The power allocated to a user is guaranteed to exceed a portion
guaranteed_power_ratioofbs_max_power_dbmdivided by the number of scheduled users. Must be within [0;1]. Defaults to 0.5.fairness (float) – Fairness parameter. If 0, the sum of utilities is maximized; when 1, proportional fairness is achieved. As
fairnessincreases, the optimal allocation approaches a max-min one. Defaults to 0.0.return_lagrangian (bool) – If True, the inverse of the optimal Lagrangian multiplier
mu_inv_staris returned. Defaults to False.precision (Literal['single', 'double'] | None) – Precision used for internal calculations and outputs. If set to None,
precisionis used.kwargs – Additional inputs for
bisection_method()used to compute the optimal power allocation, such aseps_x,eps_y,max_n_iter,step_expand.
- Outputs:
tx_power – […, num_ut], torch.float. Optimal downlink power allocation \(p_u^*\) [Watt] for each user \(u\).
utility – […, num_ut], torch.float. Optimal utility for each user, computed as \(r_u \log( 1 + p^*_u q_u)\) for user \(u\).
mu_inv_star – […], torch.float. Inverse of the optimal Lagrangian multiplier \(\mu\) associated with the total power constraint. Only returned if
return_lagrangianis True.
Examples
import torch import numpy as np import matplotlib.pyplot as plt from sionna.phy import config from sionna.phy.utils import db_to_lin, dbm_to_watt from sionna.sys import downlink_fair_power_control config.seed = 45 # Evaluate the impact of 'fairness' and 'guaranteed_power_ratio' # parameters on the DL power allocation and utility # Guaranteed power ratios guaranteed_power_ratio_vec = [0, .35, .7] # Fairness parameters fairness_vec = [0, 1, 2, 5] # N. users num_ut = 30 # BS tx power bs_max_power_dbm = 56 max_power_bs = dbm_to_watt(bs_max_power_dbm) # Interference plus noise interference_plus_noise = 5e-10 # [W] # Generate random pathloss pathloss_db = config.rng.uniform(70, 110, size=(num_ut,)) # [dB] pathloss = db_to_lin(pathloss_db) # Channel quality cq = 1 / (pathloss * interference_plus_noise) fig, axs = plt.subplots(3, len(guaranteed_power_ratio_vec), figsize=(3.5*len(guaranteed_power_ratio_vec), 8), sharey='row') fig.subplots_adjust(top=0.8) for ax in axs.flatten(): ax.yaxis.set_tick_params(labelbottom=True) ax.grid() ax.set_xlabel(r'User terminal $u$', fontsize=12) # Show channel quality in decreasing order ind_sort = np.argsort(cq.cpu().numpy())[::-1] axs[0, 1].plot(10*np.log10(cq.cpu().numpy())[ind_sort], '.-') axs[0, 1].set_ylabel(r'$q_u$ [dB]', fontsize=12) axs[0, 1].set_title('Channel quality') for ii, guar_ratio in enumerate(guaranteed_power_ratio_vec): # Guaranteed power for each user guaranteed_power = guar_ratio * max_power_bs / num_ut for fairness in fairness_vec: # DL fair power allocation tx_power, utility = downlink_fair_power_control( pathloss, interference_plus_noise=interference_plus_noise, num_allocated_re=1, bs_max_power_dbm=bs_max_power_dbm, guaranteed_power_ratio=guar_ratio, fairness=fairness) # Show utility axs[2, ii].plot(utility.cpu().numpy()[ind_sort], '.-', label=f'fairness = {fairness}') # Show transmit power axs[1, ii].plot(tx_power.cpu().numpy()[ind_sort], '.-', label=f'fairness = {fairness}') axs[1, ii].plot([0, num_ut-1], [guaranteed_power]*2, '--k', label='guaranteed power') axs[1, ii].set_ylabel(r'Power $r_u p^*_u$ [W]', fontsize=12) axs[1, ii].legend(fontsize=9) axs[2, ii].set_ylabel( r'Utility $r_u \log(1+p^*_u q_u)$', fontsize=12) axs[1, ii].set_title( f'Guaranteed power ratio = {guar_ratio}') fig.suptitle('Downlink fair power control', y=.98, fontsize=18) fig.tight_layout() fig.delaxes(axs[0, 0]) fig.delaxes(axs[0, 2]) plt.show()