Skip to main content
Ctrl+K

Sionna

  • Installation
  • Ray Tracing (RT)
  • Physical Layer (PHY)
  • System Level (SYS)
  • Research Kit (RK)
    • “Made with Sionna”
    • Citation
  • GitHub
  • PyPI
  • Installation
  • Ray Tracing (RT)
  • Physical Layer (PHY)
  • System Level (SYS)
  • Research Kit (RK)
  • “Made with Sionna”
  • Citation
  • GitHub
  • PyPI

Section Navigation

  • Tutorials
    • Beginners
      • Physical Layer Abstraction
      • Link Adaptation
      • Proportional Fairness Scheduler
      • Hexagonal Grid Topology
      • Power Control
    • Experts
      • Sionna SYS meets Sionna RT
      • System-Level Simulations
  • API Documentation
    • PHY Abstraction
      • EffectiveSINR
      • EESM
      • PHYAbstraction
    • Link Adaptation
      • InnerLoopLinkAdaptation
      • OuterLoopLinkAdaptation
    • Power Control
      • open_loop_uplink_power_control
      • downlink_fair_power_control
    • Scheduling
      • PFSchedulerSUMIMO
    • Multicell Topology
      • Hexagon
      • HexGrid
      • gen_hexgrid_topology
      • get_num_hex_in_grid
      • convert_hex_coord
    • Utils
      • is_scheduled_in_slot
      • get_pathloss
      • spread_across_subcarriers
  • References
  • System Level (SYS)
  • API Documentation
  • Power Control
  • downlink_fair_power_control

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_lagrangian is 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_ratio of bs_max_power_dbm divided 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 fairness increases, 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_star is returned. Defaults to False.

  • precision (Literal['single', 'double'] | None) – Precision used for internal calculations and outputs. If set to None, precision is used.

  • kwargs – Additional inputs for bisection_method() used to compute the optimal power allocation, such as eps_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_lagrangian is 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()
../../_images/fair_DL_tx_power.png

previous

open_loop_uplink_power_control

next

Scheduling

On this page
  • downlink_fair_power_control()

This Page

  • Show Source

© Copyright 2021-2026 NVIDIA CORPORATION.

Created using Sphinx 9.1.0.

Built with the PyData Sphinx Theme 0.16.1.