Blockage#

The following helpers implement the two alternative blockage add-on models from Section 7.6.4 of 3GPP TR 38.901 [TR38901V1920]:

  • Model A is the stochastic angular-region model from Section 7.6.4.1. It generates generic self- and non-self-blocking regions around each UT and is computationally efficient.

  • Model B is the geometric rectangular-screen model from Section 7.6.4.2. It uses explicitly positioned physical screens and computes attenuation for every ray, making it suitable for a specified blocker layout.

Comparison of angular-region and rectangular-screen blockage models

Fig. 21 Model A samples self- and non-self-blocking angular regions around each UT. Model B evaluates explicitly positioned rectangular screens. Both produce additional attenuation for LOS and individual rays.#

Blockage models additional attenuation caused by objects close to the UT or by known physical screens that obstruct only some arrival directions or rays. It is modelled separately from pathloss and shadow fading because these losses can be direction-selective and different for LOS and individual multipath components.

TR 38.901 defines temporal variability as an optional procedure that can be activated on demand. That procedure is currently not supported: blockage attenuation does not evolve over the time samples of a generated channel realization.

Model A is available for UMi, UMa, RMa, and InH. Model B is available for those models and InF.

Table 4 Blockage-model support#

Model

Channel classes

Required configuration

A

UMi, UMa, RMa, InH

Explicit portrait or landscape self-blocking mode and the number of stochastic non-self-blockers.

B

UMi, UMa, RMa, InH, InF

Explicit screen centre, width, and height for every physical blocker.

A compliant Model A realization includes one self-blocking region from Table 7.6.4.1-1, so public channels require an explicit "portrait" or "landscape" selection when Model A is enabled. The explicit value blockage_self_blocking="none" is available for experiments that intentionally omit self-blocking, but this is a non-standard Model A variant.

InF intentionally supports only Model B. Tables 7.6.4.1-2 and 7.6.4.1-4 provide Model A blocker distributions and spatial-correlation distances for UMi, UMa, SMa, RMa, and InH, but contain no InF parameters. In contrast, Table 7.6.4.2-5 explicitly recommends Model B dimensions and mobility patterns for InF humans, automated guided vehicles, and industrial robots. Consequently, InF(enable_blockage=True, ...) always selects Model B and requires explicit screen centres, widths, and heights. This is a standards-parameter restriction, not a claim that stochastic blockage is physically impossible in a factory.

BlockageModelA(scenario, self_blocking[, ...])

Stochastic blockage model A from 3GPP TR 38.901.

BlockageModelB(scenario, blocker_centers, ...)

Geometric blockage model B from 3GPP TR 38.901.

Examples#

Model A is selected by setting enable_blockage=True. The following example uses a UMi channel with the landscape self-blocking region from Table 7.6.4.1-1 of TR 38.901 [TR38901V1920].

import math
import torch
from sionna.phy.channel import tr38901

device = "cuda:0" if torch.cuda.is_available() else "cpu"
precision = "single"
dtype = torch.float32
carrier_frequency = 30e9

bs_array = tr38901.PanelArray(num_rows_per_panel=1,
                              num_cols_per_panel=1,
                              polarization="single",
                              polarization_type="V",
                              antenna_pattern="omni",
                              carrier_frequency=carrier_frequency,
                              precision=precision,
                              device=device)
ut_array = tr38901.PanelArray(num_rows_per_panel=1,
                              num_cols_per_panel=1,
                              polarization="single",
                              polarization_type="V",
                              antenna_pattern="omni",
                              carrier_frequency=carrier_frequency,
                              precision=precision,
                              device=device)

channel = tr38901.UMi(carrier_frequency=carrier_frequency,
                      o2i_model="low",
                      ut_array=ut_array,
                      bs_array=bs_array,
                      direction="downlink",
                      enable_blockage=True,
                      blockage_model="A",
                      blockage_self_blocking="landscape",
                      blockage_num_non_self_blockers=0,
                      precision=precision,
                      device=device)

channel.set_topology(
    ut_loc=torch.tensor([[[100.0, 0.0, 1.5]]],
                        dtype=dtype,
                        device=device),
    bs_loc=torch.tensor([[[0.0, 0.0, 10.0]]],
                        dtype=dtype,
                        device=device),
    ut_orientations=torch.tensor([[[math.pi / 2, 0.0, 0.0]]],
                                 dtype=dtype,
                                 device=device),
    bs_orientations=torch.zeros(1, 1, 3, dtype=dtype, device=device),
    ut_velocities=torch.zeros(1, 1, 3, dtype=dtype, device=device),
    in_state=torch.zeros(1, 1, dtype=torch.bool, device=device),
    los=True)

channel.return_rays = True
h, tau, rays = channel(num_time_samples=1, sampling_frequency=1.0)

print("Per-ray blockage loss shape:", tuple(rays.blockage_loss_db.shape))
print("LOS blockage loss [dB]:", rays.los_blockage_loss_db.cpu())

This produces:

Per-ray blockage loss shape: (1, 1, 1, 19, 20)
LOS blockage loss [dB]: tensor([[[30.]]])

The first output contains one loss value for each of the 19 clusters and 20 rays. The second output is the LOS-path loss for the single BS–UT link. For this UT orientation, the LOS direction is inside the landscape self-blocking region and therefore receives the specified 30 dB attenuation. Random non-self-blockers are disabled here so that the example has deterministic output.

Model B uses explicit rectangular blocker screens. The screen centre coordinates, widths, and heights are in metres. In this example, the screen is placed between the BS and UT so that both LOS and ray-level blockage losses can be inspected through the returned Rays object.

import torch
from sionna.phy.channel import tr38901

device = "cuda:0" if torch.cuda.is_available() else "cpu"
precision = "single"
dtype = torch.float32
carrier_frequency = 30e9

bs_array = tr38901.PanelArray(num_rows_per_panel=1,
                              num_cols_per_panel=1,
                              polarization="single",
                              polarization_type="V",
                              antenna_pattern="omni",
                              carrier_frequency=carrier_frequency,
                              precision=precision,
                              device=device)
ut_array = tr38901.PanelArray(num_rows_per_panel=1,
                              num_cols_per_panel=1,
                              polarization="single",
                              polarization_type="V",
                              antenna_pattern="omni",
                              carrier_frequency=carrier_frequency,
                              precision=precision,
                              device=device)

channel = tr38901.UMi(
    carrier_frequency=carrier_frequency,
    o2i_model="low",
    ut_array=ut_array,
    bs_array=bs_array,
    direction="downlink",
    enable_blockage=True,
    blockage_model="B",
    blockage_screen_centers=torch.tensor([[80.0, 10.0, 1.5]],
                                         dtype=dtype,
                                         device=device),
    blockage_screen_widths=torch.tensor([2.0],
                                        dtype=dtype,
                                        device=device),
    blockage_screen_heights=torch.tensor([10.0],
                                         dtype=dtype,
                                         device=device),
    precision=precision,
    device=device)

channel.set_topology(
    ut_loc=torch.tensor([[[100.0, 10.0, 1.5]]],
                        dtype=dtype,
                        device=device),
    bs_loc=torch.tensor([[[0.0, 0.0, 30.0]]],
                        dtype=dtype,
                        device=device),
    ut_orientations=torch.zeros(1, 1, 3, dtype=dtype, device=device),
    bs_orientations=torch.zeros(1, 1, 3, dtype=dtype, device=device),
    ut_velocities=torch.zeros(1, 1, 3, dtype=dtype, device=device),
    in_state=torch.zeros(1, 1, dtype=torch.bool, device=device),
    los=True)

channel.return_rays = True
h, tau, rays = channel(num_time_samples=1, sampling_frequency=1.0)

print("Per-ray blockage loss shape:", tuple(rays.blockage_loss_db.shape))
print("LOS blockage loss [dB]:", rays.los_blockage_loss_db.cpu())

This produces:

Per-ray blockage loss shape: (1, 1, 1, 19, 20)
LOS blockage loss [dB]: tensor([[[0.0495]]])

Here the screen intersects the LOS path and causes approximately 0.05 dB of LOS attenuation. The precise final digits can differ slightly between devices and floating-point implementations.