CRRM documentation

Last modified: 2025-11-12 14:10

Purpose

CRRM stands for Cellular Radio Reference Model. This is a system-level network simulator which aims to predict the performance of a cellular radio system. It follows 5G concepts and channel models. The intention is to have an easy-to-use and fast system written in pure Python with minimal dependencies. It is especially designed to be suitable for interfacing to AI engines such as tensorflow or pytorch. One of the main application areas is testing the performance of novel network management algorithms.

Note that CRRM is a system-level simulator, not a link-level simulator. This means that it takes a coarse-grained approach, specifically meaning that it does not model concepts like packet flows and queueing at all. Resource allocation is modelled, but only as a continuous process that ignores discrete resource blocks. These simplifications are necessary if large systems are to be simulated. The main application areas are the evaluation of high-level network management strategies, not the accurate estimation of throughputs to indvidual devices. Other software is available for that type of link-level simulation.

CRRM is carefully designed to be very fast and to be able to handle large systems. It achieves this by a novel compute-on-demand mechanism, whereby internal data is only computed when needed. Moreover, only data which is known to have changed, normally because of User Equipment (UE) movement, is actually computed. The system knows internally what has not changed and thus does not need to be re-computed.

CRRM builds on the previous projects AIMM-simulator by Keith Briggs, and Cellular Reference Model by Kishan Sthankiya, especially for pathloss models. However, CRRM has a completely new and much more efficient internal design and a new API, and essentially is a new project. Further technical documentation is at https://arxiv.org/abs/2511.02692.

Authors

Software dependencies

  1. Python 3.11 or higher.

  2. NumPy.

  3. SciPy.

  4. matplotlib.

Installation from PyPi

pip install CRRM

Installation from source

First download the source as a zipfile from https://github.com/keithbriggs/CRRM-2.0/tree/master. Then perform these steps in your terminal:

unzip CRRM-2.0.zip
cd CRRM-2.0
pip install .

You should of course develop new projects using CRRM in your own folders, not under the CRRM-2.0 folder!

Performance

The plot below shows the typical computation time for a range of system sizes. Note the proportionality of computation to both the number of cells, and to the number of UEs. This indicates that there are no significant computational overheads.

Download script: CRRM_large_system_timing_tests.py

CRRM_large_system_timing_tests.png

CRRM performance metrics.


Tutorial examples

Note: as with other python packages like numpy, there are alternative ways of importing which are functionally equivalent but result in a different namespace set-up. With CRRM, these two options are equivalent:

1from CRRM import Simulator,Parameters
2params=Parameters()
3sim=Simulator(params)
4# or...
5import CRRM
6params=CRRM.Parameters()
7sim=CRRM.Simulator(params)

Important: the parameters class is used to set the initial conditions for the simulation. If these are changed during a simulation run, it is not safe to assume that the new values will be used by the simulation kernel. For only a few parameters is it meaningful to change them during a run, and for these methods with names like CRRM.Simulator.set_power_matrix() methods are provided. See the documentation of all available such methods under Simulator below. Further technical documentation is at https://arxiv.org/abs/2511.02692.

Example 01: Quick start

The following example will test the installation and introduce the basic concepts.

1from CRRM import Simulator,Parameters
2crrm_parameters=Parameters(n_ues=20)
3crrm_simulator=Simulator(crrm_parameters)
4crrm_simulator.layout_plot()
5print(f'UE throughputs={crrm_simulator.get_UE_throughputs()} Mb/s')

The minimal steps required to build and run a simulation are:

  1. Import Simulator, and Parameters.

  2. Create a Parameters instance.

  3. Create a Simulator instance with the Parameters instance as its only argument.

  4. Draw a plot to confirm the system layout (see below).

  5. Print out the computed values of any variables of interest.

The output should be something like this:

UE throughputs=[16 16  9  7  5  9 16 33 33  8 33 28 16 43 43 16 22 29 66 26] Mb/s

Note that the default locations for cells and UEs used are 7 cells in a hexagonal layout, and UEs distributed as a Poisson Point Process (PPP), with mean 50 (in the approximate area covered by the cells). These default locations can be over-ridden by using the cell_locations and ue_initial_locations arguments when creating the CRRM_parameters instance. In this example we simply use the n_ues parameter to use 20 UEs rather than the default 50, but we keep the PPP distribution.

Download script: CRRM_example_01_quick-start.py

CRRM_example_01_quick-start_layout.png

CRRM example 01 quick-start layout.

Example 02: Adding a logger

Normally we want to log or capture data during a simulation run, in order to plot it at the end of the run, or to do statistical analyses. The Logger class is used for this, as outlined in this code example:

 1from CRRM import Parameters,Simulator,Logger
 2crrm_parameters=Parameters(...)
 3crrm=Simulator(crrm_parameters)
 4logger=Logger(crrm,captures=('cqi','mcs','sinr','se_Shannon','tp'))
 5for i in range(crrm_parameters.n_moves):
 6  logger.capture()
 7  # now move some UEs...
 8logger.plot(fields=('cqi','mcs','sinr','se_Shannon','tp'),
 9            fnbase='img/CRRM_example_02_logger',
10            title='CRRM logger',
11            averages=('tp',),
12            smooth_averages=True)
  1. Import the required classes.

  2. Create a Parameters instance.

  3. Create a Simulator instance.

  4. Create a Logger instance, specifying which quantities are to be captured, and optionally for which UEs (the default is all UEs).

  5. Start the main simulation loop.

  6. On each loop iteration, capture the data.

  7. Move some or all UEs according to some mobility model.

  8. Plot the results. The averages field causes the average of the captured data to also be plotted.

Download script: CRRM_example_02_logger.py

CRRM_example_02_logger

CRRM example 02: logger.

Example 03: Resource allocation

This example demonstrates the resource_allocation_fairness parameter (denoted as \(p\)). This parameter controls how resources are shared among UEs attached to the same cell. The model calculates the throughput \(T_i\) for a user \(i\) with spectral efficiency \(S_i\) using the equation \(T_i = a S_i^{1-p}\). Here, \(p\) is the fairness parameter, and \(a\) is a proportionality factor calculated for each cell, which represents the total subband bandwidth divided by the sum of the “costs” (\(S_j^{-p}\)) of all UEs attached to that same cell. The script plots the throughput of all UEs as this parameter is swept from a negative value (favouring strong users) to a positive value (favouring weak users).

1crrm_parameters=Parameters(..., resource_allocation_fairness=pmin, ...)
2crrm=Simulator(crrm_parameters)
3crrm_log=Logger(crrm, captures=('tp',), ...)
4ps=np.linspace(pmin, pmax, crrm_parameters.n_moves)
5for p in ps:
6  crrm.set_resource_allocation_fairness(p)
7  crrm_log.capture()
8crrm_log.plot(fields=('tp',), x_axis=ps, ...)

The key steps are:

  1. A Logger instance is created, configured to capture throughput (tp) for all UEs.

  2. A numpy.linspace array of fairness values (ps) is generated.

  3. The main loop iterates over this ps array, not over time steps.

  4. Inside the loop, set_resource_allocation_fairness() is called to update the simulator’s parameter.

  5. logger.capture() logs the resulting throughputs for all UEs at this fairness value.

  6. Finally, logger.plot() is called with x_axis=ps to plot throughput vs the fairness parameter.

Download script: CRRM_example_03_resource_allocation.py

CRRM_example_03_resource_allocation.png

CRRM example 03: resource allocation.

Example 04: Pathloss model comparison

This script compares the available pathloss models from the simulator. It simulates a single UE moving radially away from the cell and captures its throughput at each step. This process is repeated for each long-distance model (RMa, UMa, UMi, and power-law), and the results are plotted on a single graph to show the significant impact of the propagation model on performance.

 1model_names = ['RMa', 'UMa', 'UMi', 'power-law']
 2all_tps = []
 3for model_name in model_names:
 4  crrm_parameters = Params(..., pathloss_model_name=model_name, ...)
 5  crrm = Sim(crrm_parameters)
 6  tp = np.empty(n_points)
 7  for i in range(n_points):
 8    tp[i] = crrm.get_UE_throughputs()[0, 0]
 9    crrm.move_ue_locations(...)
10  all_tps.append(tp)
11plot(distances, all_tps, labels=model_names, ...)

The key steps are:

  1. Define the list of models to iterate over.

  2. Create an empty list to store the final throughput array from each run.

  3. Begin the main loop, iterating over the model names.

  4. Inside the loop, create a new Params instance, critically setting the pathloss_model_name for this iteration.

  5. Create a new Sim instance for this model.

  6. Run the inner simulation loop, moving the UE and capturing throughput into a temporary array tp.

  7. Append the completed throughput array tp to the main all_tps list.

  8. After the main loop, pass all the collected data to the plot function.

Download script: CRRM_example_04_pathloss_model_comparison.py

The script prints simulation progress to the console and generates the plot shown below. Note how the simple power-law model (exponent 3.0) is more pessimistic at short distances than the dual-slope 3GPP models (like RMa), which start with a pathloss exponent closer to 2.0.

CRRM_example_04_pathloss_model_comparison.png

Throughput vs distance for several standard pathloss models.

Example 05: Antenna pattern visualisation

This script provides a visualisation of the 3-sector antenna gain pattern model. It plots the throughput of a single UE moving in a 360-degree circle at a constant radius from the cell. The test is run for both the 1-sector (omnidirectional) case and the 3-sector case, allowing a direct comparison.

 1thetas   = np.linspace(-np.pi, np.pi, n_steps, ...)
 2xs       = r_m * np.cos(thetas)
 3ys       = r_m * np.sin(thetas)
 4...
 5all_tps = []
 6for n_sec in [1, 3]:
 7  crrm_parameters = Params(..., n_sectors=n_sec, ...)
 8  crrm = Sim(crrm_parameters)
 9  tp = np.empty(n_steps)
10  for i in range(n_steps):
11    pos = np.array([[xs[i], ys[i], h_ut]])
12    crrm.set_ue_locations([0], pos)
13    tp[i] = crrm.get_UE_throughputs()[0, 0]
14  all_tps.append(tp)
15plot(degrees, all_tps, ...)

The core logic is:

  1. Generate the array of \((x, y)\) coordinates for the circular path.

  2. Loop over the desired sector configurations (1 and 3).

  3. Inside this loop, create a Params instance with the correct n_sectors for this run.

  4. Create the corresponding Sim instance.

  5. Run an inner loop over all path coordinates.

  6. Use the set_ue_locations() method to explicitly place the UE at the position for this step.

  7. Capture the UE’s throughput at that position.

  8. Store the throughput arrays and pass them to the plot function.

Download script: CRRM_example_05_antenna_pattern.py

The resulting plot clearly shows the gain “lobes” from the 3-sector antenna pattern compared to the flat omnidirectional (1-sector) case, confirming the antenna gain model is working correctly.

CRRM_example_05_antenna_pattern.png

Plot showing 1-sector vs 3-sector throughput for a UE moving in a circle.

Example 06: Subbanding and Interference

This script demonstrates the use of subbanding. It defines a worst-case scenario: one UE placed exactly between two cells. In the first test (1 subband), the UE experiences full interference from both cells, resulting in near-zero SINR. In the second test (2 subbands), the cells are configured via the power_matrix parameter to transmit on different subbands, eliminating the interference at the UE and showing the resulting massive throughput gain.

 1# Case 1: n_subbands=1
 2params_case1 = Params(
 3  ...,
 4  n_subbands             = 1,
 5  power_matrix           = [[100.0], [100.0]],
 6  ...
 7)
 8crrm_case1 = Sim(params_case1)
 9crrm_case1.update()
10sinr_case1 = crrm_case1.sinr.data[0, 0]
11
12# Case 2: n_subbands=2
13params_case2 = Params(
14  ...,
15  n_subbands             = 2,
16  power_matrix           = [[100.0, 1.0], [1.0, 100.0]],
17  ...
18)
19crrm_case2 = Sim(params_case2)
20crrm_case2.update()
21sinrs_case2 = crrm_case2.sinr.data[0]

This demo runs two separate simulations:

  1. A Params instance is created for 1 subband.

  2. The power_matrix is set so both cells transmit on that single band, creating high interference.

  3. The simulation is run and the resulting (low) SINR is captured.

  4. A second Params instance is created for 2 subbands.

  5. The power_matrix is set to coordinate power: Cell 0 transmits on subband 0, and Cell 1 on subband 1.

  6. The simulation is run and the SINR for both subbands is captured, showing high SINR on the subband with no interference.

Download script: CRRM_example_06_subbanding.py

This script prints its results directly to the console. The output shows the SINR and throughput for both cases, demonstrating a clear performance gain.

Case 1: n_subbands=1
UE SINR:    -0.00 dB
UE Throughput:   17.54 Mb/s
Case 2: n_subbands=2
UE SINR (on subband 0): 20.00 dB (note: high signal, no interference)
UE SINR (on subband 1): -20.00 dB (note: minimal signal)
UE Throughput: 61.25 Mbps (note: from SB 0 only)

Example 07: Adding UEs during a run

This example demonstrates how to dynamically add UEs to a running simulation using the add_ue() method. It starts with a single cell and a single UE, then iteratively adds new UEs in a loop, printing the throughput of all UEs at each step.

1crrm_parameters=Parameters(...)
2crrm=Simulator(crrm_parameters)
3for i in range(2, 2+nmax):
4  crrm.update()
5  ue_throughputs=crrm.get_UE_throughputs()[:,0]
6  print(f'i={i} ue_throughput={ue_throughputs}')
7  crrm.add_ue(np.array([[10.0*i, 0.0, 2.0]]))

The key steps are:

  1. A Simulator instance is created with a single cell and a single UE.

  2. A loop is started to add nmax new UEs.

  3. Inside the loop, update() is called to get the current state.

  4. The throughputs for all currently active UEs are fetched and printed.

  5. The add_ue() method is called with a new location, adding one more UE to the simulation for the next loop iteration.

The console output demonstrates the effect of cell load. As more UEs are added to the same cell, the total cell throughput is shared among them, and the per-UE throughput decreases.

Download script: CRRM_example_07_adding_ues.py

i=2 ue_throughput=[148.126]
i=3 ue_throughput=[74.063 74.063]
i=4 ue_throughput=[49.375 49.375 49.375]
i=5 ue_throughput=[37.032 37.032 37.032 37.032]
i=6 ue_throughput=[29.625 29.625 29.625 29.625 29.625]
i=7 ue_throughput=[24.688 24.688 24.688 24.688 24.688 24.688]

Example 08: The InH Indoor Hotspot model

This script is a minimal example of how to select and use the InH (Indoor Hotspot) pathloss model. It sets up a simple scenario with two cells and one UE (in a high-interference, midpoint location) and prints the resulting throughput.

 1crrm_parameters=Params(
 2  n_ues=1,
 3  pathloss_model_name="InH",
 4  ue_initial_locations=[[100.0, 0.0, 1.5]],
 5  cell_locations=[[0.0, 0.0, 20.0], [200, 0.0, 20.0]],
 6  ...
 7)
 8crrm=Sim(crrm_parameters)
 9crrm.update()
10ue_throughput=crrm.get_UE_throughputs()
11print(f"throughput for one UE...is {ue_throughput[0,0]} Mb/s")

The key steps are:

  1. A Params instance is created.

  2. The pathloss_model_name is explicitly set to "InH".

  3. A 2-cell, 1-UE layout is defined.

  4. The Sim is created, updated, and the final throughput for the single UE is printed.

Download script: CRRM_example_08_InH.py

This script prints a single line to the console reporting the throughput for this specific indoor scenario.

throughput for one UE...is 19.4 Mb/s

Example 09: Indoor Hotspot model in 3d

This is an advanced example demonstrating a 3D animated simulation using the InH model. It shows multiple UEs moving within the 3D boundaries of a building, including randomly moving between floors. The script generates a series of 3D plot frames showing the UE locations and their current throughputs, which can then be compiled into a video.

 1parameters = Parameters(..., pathloss_model_name="InH", ...)
 2crrm = Simulator(parameters)
 3house_geom = Building(...)
 4
 5for step in range(n_steps):
 6  # ... manual UE 3D mobility logic (bouncing off walls) ...
 7  s_plus_Δs = s + Δs
 8  # ... logic to randomly change floors (s_plus_Δs[i, 2] = ...) ...
 9  crrm.move_ue_locations(range(n_ues), Δs)
10  throughputs = crrm.get_UE_throughputs(...)
11  # ... matplotlib 3D plotting logic ...
12  draw_building_3d(house_geom, dots=crrm.ue_locations.data, ...)
13  ax.text(ue_loc[0],ue_loc[1],ue_loc[2]+0.5,label=f'{throughputs[i]} Mb/s', ...)
14  fig.savefig(f'ani/frame_{step:04d}.png')
15  plt.close()
16
17print(f"ffmpeg ... && xdg-open mp4/InH_test_ani.mp4")

The core logic is:

  1. A Params instance is created, specifying the InH pathloss model.

  2. A 3D building geometry is defined.

  3. A main simulation loop begins, where custom code calculates the next UE position, including “bouncing” off the defined building walls and randomly triggering floor changes.

  4. crrm.move_ue_locations() is called with the new 3D positions.

  5. get_UE_throughputs() is called to get the performance at this new state.

  6. A 3D plot is generated showing the building, cells, and UEs annotated with their throughputs.

  7. The plot is saved as an animation frame.

  8. After the loop, an ffmpeg command is printed to compile the frames into a video.

Download script: CRRM_example_09_InH_3d.py

This script outputs a series of .png frames to the ani/ directory and prints a command to compile and open the resulting .mp4 video.

CRRM_example_09_InH_3d_screenshot.png

CRRM example 09: Indoor Hotspot with 3d geometry.

Example 10: Base-station sectorization

This example computes an average throughput, firstly with one sector per base station, and then with three.

n_sectors=1 average UE throughput over 100 UE PPP layouts = 4.22 Mb/s
n_sectors=3 average UE throughput over 100 UE PPP layouts = 8.23 Mb/s

The layout plot indicates that the attachement is not to the nearest cell in the three-sector case.

CRRM_example_10_sectors_layout.png

CRRM example 10 sectors layout.

Download script: CRRM_example_10_sectors.py

Example 11: One-cell throughput tests

This example simply demonstrates that repeatedly adding UEs to a single cell results in throughputs inversely proportional to the number of UEs. See comments in the script for further details.

CRRM_example_11_one-cell_throughput_tests_vs_number_equal_distance.png

CRRM example 11 throughput tests.

Download script: CRRM_example_11_one-cell_throughput_tests.py

Example 12: Signal-to-Interference ratio cumulative distribution

This example simply demonstrates a close match to a theoretical cumulative distribution in the case of both cells and UEs randomly distributed according to a Poisson Point Process (PPP). See comments in the script for further details.

Reference: Haenggi, Stochastic Geometry for Wireless Networks, CUP 2013, section 5.2.

CRRM_example_12_sinr_cdf.png

CRRM example 12 SIR cumulative distribution.

Download script: CRRM_example_12_sinr_cdf.py

Example 13: Timing tests

This script is able to run a variety of tests demonstrating the speed-ups attainable by using the smart updating algorithm in the CRRM kernel. An important check which it performs is that the smart updating gives identical results to the non-smart. It can also make an animation. See comments in the script for further details.

Typical console output is:

Without smart updating:
sinr for subband[0]=[-3.598  3.415 -2.172  1.317 -1.293 ... ] dB
se_Shannon for subband[0]=[0.523 1.676 0.684 1.235 0.801 ...]

With smart updating:
sinr for subband[0]=[-3.598  3.415 -2.172  1.317 -1.293 ... ] dB
se_Shannon for subband[0]=[0.523 1.676 0.684 1.235 0.801 ...]

The smart and the non-smart results match!
speed-up factor=1.84 😁

Download script: CRRM_example_13_timing_tests.py

Example 14: Fading demonstration

A demonstration of the effects of different types of fading on a cell-edge user.

CRRM_example_14_fading_tests

CRRM example 14: fading.

Download script: CRRM_example_14_fading_tests.py

Example 15: MIMO

CRRM 2.0 implements MIMO only for computing channel spectral efficiency; the UE throughput computations based on MCS selection are unaffected by this setting.

This example simply sets up a system with several different MIMO schemes, and prints the predicted UE spectral efficiencies.

from CRRM import Simulator, Parameters
for MIMO in ((1,1),(2,2),(4,4),(8,2),(8,4),(8,8),(64,64),):
  crrm=Simulator(Parameters(n_ues=20,MIMO=MIMO))
  se=crrm.get_spectral_efficiency(ues=(0,1,2,3,4,5,),subbands=0)
  print(f"MIMO={MIMO} {se} b/s/Hz")

This code prints:

MIMO=( 1,  1) [  4.6    4.53   2.63  1.76  1.27  1.43] b/s/Hz
MIMO=( 2,  2) [  7.51   7.37   4.2   2.85  2.1   2.35] b/s/Hz
MIMO=( 4,  4) [ 14.76  14.49   8.31  5.66  4.17  4.66] b/s/Hz
MIMO=( 8,  2) [  8.85   8.7    5.0   3.35  2.42  2.72] b/s/Hz
MIMO=( 8,  4) [ 16.87  16.57   9.45  6.33  4.6   5.17] b/s/Hz
MIMO=( 8,  8) [ 29.38  28.86  16.58 11.29  8.33  9.31] b/s/Hz
MIMO=(64, 64) [234.72 230.55 132.56 90.3  66.59 74.48] b/s/Hz

Download full script: CRRM_example_15_MIMO.py

Example 16: callback demo

This is a very simple example of how to use the callback facility for user access to internal CRRM data during a simulation run.

from CRRM import Simulator, Parameters
def show_attachments(a): print(f"attachment_vector = {a}")
crrm = Simulator(Parameters(n_ues=20))
crrm.a.set_callback(show_attachments)
crrm.update()

This code prints the following. The meaning of the attachment_vector is that UE[i] is attached to cell[attachment_vector[i]].

attachment_vector = [0 0 0 0 0 1 1 2 4 4 2 5 3 1 5 3 5 3 6 3]

Download full script: CRRM_example_16_callback_demo.py


CRRM internal structure and mathematical model

Most users do not need to know anything about this.

  • UE locations \(u_i\) (one row per UE, three columns \(x,y,x\)).

  • Cells locations \(c_j\) (one row per cell, three columns \(x,y,x\))

  • \(\text{Cell}_j\) transmits with power \(p_j\) (\(p_{jk}\) with subbands).

  • Distance matrix \(D_{ij}=||u_i-c_j||\).

  • Attachment vector: \(\text{UE}_i\) attaches to cell \(a_j\) with best signal.

  • Gain matrix \(G=g(D)\) (\(\implies0<G<1\)).

  • RSRP matrix \(R_{ij}=p_j G_{ij}\).

  • With subbands: \(R_{ijk}=p_{jk} G_{ij}\).

  • Wanted signal vector \(w_i=R_{i,a_i}\).

  • Unwanted interference vector \(u_i=\sum_j R_{ij}-w_i\).

  • SINR vector \(\gamma=\frac{w}{\sigma^2+u}\) (element-wise division).

  • CQI is computed by discretizing the SINR.

  • MCS selection is done by standard look-up tables.

  • Resource allocation and throughput calculation are done by the function CRRM.Simulator.get_UE_throughputs and the class CRRM.Throughput documented below.

The horizontal arrows in the block diagram below indicate dependencies of one block upon others. Blocks drawn with the same height have the same numbers of rows (\(n_{\text{UEs}}\)), and blocks drawn with the same width have the same numbers of columns (either \(n_{\text{cells}}\), or 1). Stacks indicate the third dimension, which stores the data for each subband.

CRRM block diagram

CRRM simulator block structure.

CRRM block diagram with strip

CRRM simulator block structure, with the horizontal red strip showing the rows of vectors and matrices which are updated when a UE moves.


API reference

CRRM module

CRRM.get_version()

Get the version number of the CRRM module.

_Node class

Generic base class for smart updating of node data. Not for direct use by a normal user

CRRM._Node.set_callback(self, f)

Register user function f to be called with self.data as argument at every update. Inherited by all subclasses.

Parameters class

Container for physical, behavioral, and visualization parameters of a CRRM (Cellular Radio Reference Model) simulation. This class encapsulates metadata, system geometry, physical layer parameters, pathloss modeling options, UE mobility control, animation settings, and display preferences.

Important: the parameters class is used to set the initial conditions for the simulation. If these are changed during a simulation run, it is not safe to assume that the new values will be used by the simulation kernel. For only a few parameters is it meaningful to change them during a run, and for these methods with names like CRRM.Simulator.set_power_matrix() methods are provided. See the documentation on all available such methods under Simulator below.

Metadata parameters

jobint = 0

User-defined job ID.

descriptionstr = ‘’

User-defined problem description.

authorstr = ‘’

Simulation author.

date_timestr (= current local date and time)

Timestamp of configuration creation.

Simulation control parameters

rng_seedsint or (int,int,int) = 0

Seeds for the three random-number generators, used for UE movements, shadow fading, and Rayleigh fading respectively.

smart_updatebool = True

If True, enable optimized internal updates.

verbosebool = False

If True, print general simulation debug information.

do_assertsbool = False

If True, enable runtime assertions for debugging.

display_flatbool = False

If True, display parameters in a single-line format.

display_coloredbool = True

If True, use colored output when printing parameters.

omit_from_displaytuple = (‘cell_locations’,’ue_locations’,’power_matrix’)

Fields to exclude from parameter display output.

System geometry and technology parameters

n_cell_locationsint = 7

Number of base station (cell) locations.

n_uesint = 50

Number of user equipment (UEs).

ue_initial_locationsNone

Placeholder for UE positions (to be populated later).

cell_locationsNone

Placeholder for cell positions (to be populated later).

system_areafloat

Area of the system (computed at initialization).

h_UT_defaultfloat = 1.8

Default height of a user terminal (meters).

h_BS_defaultfloat = 20.0

Default height of a base station (meters).

fc_GHzfloat = 3.5

Carrier frequency in GHz.

bw_MHzfloat = 20.0

Channel bandwidth in MHz.

σ2float = 2.0e-20 W/Hz

Noise power spectral density

n_subbandsint = 1

Number of subbands.

n_sectorsint = 1

Number of sectors per base station.

distance_scalefloat = 1e3

Spatial scaling factor (e.g., 1000 for km to meters).

p_Wfloat = 100.0

Transmit power in Watts.

power_matrixNDArray

Matrix of transmit powers across subbands (populated during initialization).

MIMONone|tuple[int]

Order (t,r) of the MIMO scheme, where t is the number of transmit antennas, and r the number of receive antennas. CRRM 2.0 implements MIMO only for computing channel spectral efficiency; the UE throughput computations based on MCS selection are unaffected by this setting.

MCS_table_numberint = 2

Index of the modulation and coding scheme table (most users will not need to change this).

resource_allocation_fairnessfloat = 0.0

Fairness factor (0.0 = proportional fair scheduling).

Pathloss model parameters

pathloss_model_namestr = ‘UMa’

Name of the 3GPP pathloss model: options are ‘UMa’ (Urban Macrocell), ‘UMi’ (Urban Microcell), ‘RMa_discretised’ (Rural Macrocell, the fastest implementation, recommended for general rural use), ‘RMa’ (slower), ‘RMa_constant_height’ (for use when all cell and all UEs have the same height above ground), ‘InH’ (Indoor Hotspot), and ‘power-law’ (simple model for comparison purposes only).

pathloss_modelNone or str

Pathloss model instance (assigned during set-up, not by the user).

pathgain_functionCallable[[NDArray, NDArray], float]

Function to compute path gain between transmitter and receiver (assigned during set-up, not by the user).

pathloss_exponentfloat = 3.0

Pathloss exponent, used only for the power-law pathloss model.

LOSbool = True

Whether line-of-sight conditions are assumed.

shadow_fadingbool = False

If true, shadow fading is used in the pathloss models.

rayleigh_fadingbool = False

If true, Rayleigh fading is used in the pathloss models.

UE mobility parameters

n_movesint = 1000

Number of UE movement steps in the simulation.

move_fractionfloat = 0.1

Fraction of UEs that move during each step.

move_meanfloat = 0.0

Mean movement distance (meters).

move_stdevfloat = 10.0

Standard deviation of movement (meters).

Layout plotting parameters

layout_plot_fnbasestr = ‘img/CRRM_layout_plot’

Base filename for layout plot image output.

label_ues_in_layout_plotbool = False

Whether to label UEs in the layout plot.

frame_intervalint = 0

Time between animation frames (0 disables animation).

Simulator class

Main class representing a cellular system, and computing all internal performance data. It takes one argument of type CRRM_parameters.

The simulator internally uses a list of three random number generators, each with their own seed. This allows for fading to be switched on and off but not affect UE moves.

  • rng[0]: used for moving UEs

  • rng[1]: used for shadow fading

  • rng[2]: used for Rayleigh fading

CRRM.Simulator.add_ue(self, location)

Add one UE to the system, at the given location.

Parameters:

location (a 3-vector representing the (x,y,z) coordinates)

CRRM.Simulator.change_power_matrix(self, indices, deltas)

Shift some or all rows of the power matrix, by the given deltas. To reset all powers, use CRRM.Simulator.set_power_matrix().

Parameters:
  • indices (a list of cell indices, or 'all')

  • deltas (float, or 2d array (one row for each index, one column per subband))

CRRM.Simulator.get_UE_throughputs(self, ues=slice(None, None, None), subbands=slice(None, None, None))

Get the current UE throughputs for specified lists of ues (default all UEs), and of subbands (default all subbands).

CRRM.Simulator.get_power_matrix(self)

Return a reference to the current power matrix.

CRRM.Simulator.get_resource_allocation_fairness(self)

Get the current resource allocation fairness parameter.

CRRM.Simulator.get_rngs(self, i=slice(None, None, None))

Get the current rngs, or some or one of them.

CRRM.Simulator.get_ue_locations(self)

Get the current UE locations.

CRRM.Simulator.layout_plot(self, grid=False, title='', show_attachment_type='attachment', show_plot=False, show_voronoi=True, padding_factor=1.02, show_kilometres=True, show_system_rmax_circle=True, show_UE_radius_circle=True, show_pathloss_circles=True, cell_image=None, UE_image=None, cell_image_zoom=0.05, UE_image_zoom=0.08, return_figure=False, fmt=('png', 'pdf'), no_ticks=False, dbg=False, quiet=False, dpi=200, figsize=(6, 6), label_ues=True)

Plot the cellular reference model layout with various optional overlays.

Parameters:
  • grid (bool, optional) – Whether to display grid lines on the plot.

  • title (str, optional) – Title for the plot.

  • fnbase (str, optional) – Base filename for saving the plot.

  • show_attachment_type (str, optional) – If not empty, show UE-to-cell attachment lines.

  • show_plot (bool, optional) – If True, display the plot interactively.

  • show_voronoi (bool, optional) – If True, overlay Voronoi tessellation of cell locations.

  • padding_factor (float, optional) – Factor to expand plot limits beyond system radius.

  • show_kilometres (bool, optional) – If True, display axes in kilometres.

  • show_system_rmax_circle (bool, optional) – If True, draw a circle at the system maximum radius.

  • show_UE_radius_circle (bool, optional) – If True, draw a circle at the UE radius.

  • show_pathloss_circles (bool, optional) – If True, overlay circles for specific pathloss values.

  • cell_image (array-like or None, optional) – Image to use for cell markers.

  • UE_image (array-like or None, optional) – Image to use for UE markers.

  • cell_image_zoom (float, optional) – Zoom factor for cell images.

  • UE_image_zoom (float, optional) – Zoom factor for UE images.

  • return_figure (bool, optional) – If True, return the plot object instead of saving.

  • fmt (list of str, optional) – List of file formats for saving the plot.

  • dbg (bool, optional) – If True, print debug information.

Returns:

plot – The plot object if return_figure is True, otherwise None.

Return type:

Plot_CRRM_layout or None

CRRM.Simulator.move_ue_locations(self, indices, deltas)

Move UEs with given indices, by the given deltas.

Parameters:
  • indices (a list of UE indices, or 'all')

  • deltas (an array of shape (len(indices),3) representing the displacements)

CRRM.Simulator.scale_ue_locations(self, indices='all', scale_factor=1.0)

Scale UEs with given indices, by the given factor.

Parameters:
  • indices (a list of UE indices, or 'all')

  • scale_factor (float)

CRRM.Simulator.set_n_sectors(self, n_sectors)

Set the number of sectors for all base stations.

CRRM.Simulator.set_noise_power_spectral_density(self, σ2)

Set the noise power spectral density to a new value. The actual noise power in the channel or subbands will be computed and used in subsequent SIR calculations.

CRRM.Simulator.set_power_matrix(self, p)

Set the power matrix to a new value. The matrix must have shape (n_cell_locations,n_subbands). It will be repeated across sectors if there are more than 1. To change just some cell powers by given deltas, use CRRM.Simulator.change_power_matrix().

CRRM.Simulator.set_resource_allocation_fairness(self, p)

Set the resource allocation fairness parameter.

CRRM.Simulator.set_rng_seeds(self, seeds)

Re-set the rngs with a new seeds.

CRRM.Simulator.set_ue_locations(self, indices, locations)

Set the UE locations to new values.

class CRRM.Throughput(crrm_parameters, name='Throughput', smart_update=True)

Calculate all UE throughputs, with a tunable resource allocation heuristic. Though this class is for internal use only, the internal details are of some interest. Authors: Keith Briggs & Ibrahim Nur 2025-09-04.

This model allocates a share of the total bandwidth to each user in proportion to an abstract notion of their cost, and then calculates the resulting throughput.

The cost for user i is defined as \(1/S_i^p\), where \(S_i\) is the user’s spectral efficiency and \(p\) is a tunable fairness parameter.

This leads to the final throughput formula for user \(i\):

\[T_i = a S_i^{1-p}\]

where \(a\) is a proportionality constant calculated for the cell:

\(a\) = (total bandwidth) \(/\) (sum of all user costs)

The fairness parameter \(p\) controls the distribution skew as follows:

  • \(p > 1\): favours weak users (e.g., \(p=2\) gives \(T ∝ 1/S\)).

  • \(p = 1\): results in equal throughput for all users on the cell.

  • \(p < 1\): favours strong users (e.g., \(p=0\) gives \(T ∝ S\)).

  • \(p = 0\): proportional fair scheduling.

The parameter \(p\) is set in the CRRM_parameters class, and can be changed during a run using the CRRM.set_resource_allocation_fairness() method.

update_data()

This will be over-ridden by specific methods for each sub-class

Logger class

Create an object which will log data during a simulation run.

param captures:
The quantities to capture; allowed values are:
  • ‘UE_location’

  • ‘rsrp’ (received signal reference power)

  • ‘a’ (attachment vector)

  • ‘sinr’ (signal to interference plus noise matrix in dB)

  • ‘se_Shannon’ (Shannon capacity in b/s/Hz)

  • ‘cqi’ (channel quality index)

  • ‘mcs’ (modulation and coding scheme index)

  • ‘se_from_mcs’ (actual spectral efficiency in b/s/Hz)

  • ‘tp’ (UE downlink throughput in Mb/s)

param ues:

UE indices to log

param block_size:

size of pre-allocated internal data. Not normally altered.

Antenna_gain class

Calculates the antenna gain (not in dB) based on the 3GPP standard horizontal pattern.

This method applies a sectored antenna pattern as defined in 3GPP TR 38.901. The gain for each UE-cell link is determined by the absolute angular difference between the UE’s direction and the sector’s boresight. If the simulation is configured with only one sector per cell, a constant omnidirectional gain is applied instead.

The horizontal attenuation (in dB) is given by the formula:

\[A_H(\phi') = -\min\left(12 \left(\frac{\phi'}{\phi_\text{3dB}}\right)^2, A_\text{max}\right)\]

where \(\phi'\) is the angular deviation from the boresight.

param φ:

An array of horizontal angles \(\phi\) (in radians) from each cell to each UE. Its shape must be broadcastable with the internal array of sector angles.

type φ:

numpy.ndarray

rtype:

An array of linear (i.e., not in dB) gain values for each UE-cell link as type numpy.ndarray.

Reference

  • 3GPP TR 38.901, Table 7.3-1

RMa (Rural Macrocell) pathloss model

class RMa_pathloss_model_08.RMa_pathloss(fc_GHz=3.5, LOS=True, **args)

The complete Rural Macrocell (RMa) pathloss model from 3GPP TR 38.901.

Implements the full RMa model where antenna heights can vary for each link, calculating pathloss coefficients dynamically.

References

__init__(fc_GHz=3.5, LOS=True, **args)

Initialises the RMa_pathloss model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz. Must be <= 7 GHz. Defaults to 3.5.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations.

  • C (numpy.ndarray) – Array of cell locations.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculates the linear pathloss based on the general 3GPP RMa model.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3). The 3rd column (height) must be in the range [1.0, 10.0].

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3). The 3rd column (height) must be in the range [10.0, 150.0].

Raises:

ValueError – If any h_UT or h_BS value is outside its valid range.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells. Does not take into account height.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations. Not used in calculation.

  • C (numpy.ndarray) – Array of cell locations. Not used in calculation.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

class RMa_pathloss_model_08.RMa_pathloss_constant_height(fc_GHz=3.5, h_UT=1.5, h_BS=35.0, LOS=True, **args)

Rural Macrocell (RMa) pathloss model assuming constant antenna heights.

Simplified version of the 3GPP TR 38.901 RMa model where the heights of the User Terminal (UT) and Base Station (BS) are constant for all links, leading to a performance gain.

References

__init__(fc_GHz=3.5, h_UT=1.5, h_BS=35.0, LOS=True, **args)

Initialises the RMa_pathloss_constant_height model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz. Must be <= 7 GHz. Defaults to 3.5.

  • h_UT (float, optional) – Height of the User Terminal in metres. Must be in [1.0, 10.0]. Defaults to 1.5.

  • h_BS (float, optional) – Height of the Base Station in metres. Must be in [10.0, 150.0]. Defaults to 35.0.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

Raises:

ValueError – If h_UT or h_BS are outside their valid ranges.

get_pathgain(d2D_m, d3D_m)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations.

  • C (numpy.ndarray) – Array of cell locations.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m)

Calculates the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells. Does not take into account height.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations. Not used in calculation.

  • C (numpy.ndarray) – Array of cell locations. Not used in calculation.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

class RMa_pathloss_model_08.RMa_pathloss_discretised(fc_GHz=3.5, LOS=True, h_ut_res=0.5, h_bs_res=1.0, **args)

Rural Macrocell (RMa) pathloss model with discretised heights.

Pre-calculates pathloss coefficients for a grid of discrete UE and BS heights. At runtime, it rounds the actual heights to the nearest grid point to look up coefficients, trading accuracy for computational speed.

The accuracy trade-off is minimal. This can be shown by running the plot_RMa_pathloss_runtime_comparison program.

References

__init__(fc_GHz=3.5, LOS=True, h_ut_res=0.5, h_bs_res=1.0, **args)

Initialises the RMa_pathloss_discretised model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz. Must be <= 7 GHz. Defaults to 3.5.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • h_ut_res (float, optional) – Resolution of the discrete UT height grid in metres. Defaults to 0.5.

  • h_bs_res (float, optional) – Resolution of the discrete BS height grid in metres. Defaults to 1.0.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations.

  • C (numpy.ndarray) – Array of cell locations.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculates the linear pathloss based on the general 3GPP RMa model.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3). The 3rd column (height) must be in the range [1.0, 10.0].

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3). The 3rd column (height) must be in the range [10.0, 150.0].

Raises:

ValueError – If any h_UT or h_BS value is outside its valid range.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells. Does not take into account height.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations. Not used in calculation.

  • C (numpy.ndarray) – Array of cell locations. Not used in calculation.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

RMa_pathloss_model_08.plot_RMa_pathloss_or_pathgain(plot_type='pathloss', fc_GHz=3.5, h_UT=1.5, h_BS=35.5, zoom_box=False, print_10m_pl=False, author=' ', x_min=35.0, x_max=5000.0)

Plot 3GPP RMa pathloss or pathgain model predictions as a self-test.

This function generates a plot comparing various 3GPP RMa pathloss or pathgain models for both Line-of-Sight (LOS) and Non-Line-of-Sight (NLOS) scenarios. It includes a free-space pathloss reference and an optional zoomed-in view for detailed analysis.

Parameters:
  • plot_type (str, optional) – Type of plot to generate. Options are ‘pathloss’ (default) to plot pathloss in dB, or ‘pathgain’ to plot linear pathgain.

  • fc_GHz (float, optional) – Carrier frequency in GHz, defaults to 3.5.

  • h_UT (float, optional) – Height of the User Terminal (UE) in metres, defaults to 1.5.

  • h_BS (float, optional) – Height of the Base Station (BS) in metres, defaults to 35.5.

  • zoom_box (bool, optional) – If True, includes a zoomed-in inset on the plot. Defaults to False.

  • print_10m_pl (bool, optional) – If True, prints pathloss values at 10 metres to the console for LOS, NLOS, and free-space scenarios. Defaults to False.

  • author (str, optional) – Author name to include in the plot timestamp. Defaults to ‘ ‘.

  • x_min (float, optional) – Minimum distance for the plot’s x-axis in metres. Defaults to 35.0.

  • x_max (float, optional) – Maximum distance for the plot’s x-axis in metres. Defaults to 5000.0.

Raises:

ImportError – If required plotting modules (e.g., matplotlib) are not installed.

Notes

The function uses the RMa_pathloss, RMa_pathloss_constant_height, and RMa_pathloss_discretised classes to compute the values for the different scenarios.

RMa_pathloss_model_08.plot_RMa_pathloss_runtime_comparison(author='')

Compare RMa pathloss model runtimes.

This function provides a lightweight performance benchmark for three distinct implementations of the RMa pathloss model:

  1. RMa_pathloss: The full model with dynamic height calculations.

  2. RMa_pathloss_constant_height: A simplified model assuming fixed antenna heights.

  3. RMa_pathloss_discretised: A model that uses pre-calculated coefficients

    based on a discrete grid of antenna heights.

It directly measures the execution time required to calculate pathloss for an increasing number of UEs, thereby isolating the computational cost of each model from the overhead of the full CRRM simulation framework. The primary purpose is to visually demonstrate the performance gains achieved by the simplified and discretised models.

Parameters:

author (str, optional) – The name of the author to be included in the plot’s timestamp metadata. If not provided, the author field will be empty.

Returns:

This function does not return any values. Its primary outputs are plot files (.png, .pdf) saved to the local directory and status messages printed to the console.

Return type:

None

See also

RMa_pathloss, RMa_pathloss_constant_height, RMa_pathloss_discretised

Notes

The comparison methodology involves the following steps for each specified UE count: 1. Randomly generate locations for UEs and a fixed set of cell sites. 2. Calculate the 2D and 3D distance matrices between every UE and cell. 3. Time the get_pathloss method for each of the three model variants using these distance matrices.

The resulting plot displays two sets of data: - The absolute runtime in milliseconds for each model on the primary y-axis. - The runtime ratio of the exact model to the optimised models on a secondary y-axis, quantifying the speed-up factor.

Examples

To run the comparison and generate the output plots, simply call the function from a script where the necessary modules are in the Python path.

>>> plot_RMa_pathloss_runtime_comparison(author='Ibrahim Nur')

This will produce ‘plot_RMa_pathloss_runtime_comparison.png’ and ‘plot_RMa_pathloss_runtime_comparison.pdf’ in the current directory.

RMa pathloss model

RMa pathloss model

RMa pathloss runtime comparison

RMa pathloss models, runtime comparison

UMa (Urban Macrocell) pathloss model

class UMa_pathloss_model_06.UMa_pathloss(fc_GHz=3.5, LOS=True, **args)

Urban Macrocell (UMa) pathloss model from 3GPP TR 38.901.

Calculates pathloss for urban macrocell environments where UE and BS heights can vary. This model includes the stochastic calculation of the effective environment height (h_E).

fc_GHz

Centre frequency in gigahertz.

Type:

float

LOS

Indicates if the Line-of-Sight model is active.

Type:

bool

References

__init__(fc_GHz=3.5, LOS=True, **args)

Initialises the UMa_pathloss model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in gigahertz, by default 3.5.

  • LOS (bool, optional) – Specifies whether the Line-of-Sight (LOS) model should be used, by default True.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations.

  • C (numpy.ndarray) – Array of cell locations.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculates the linear pathloss based on the 3GPP UMa model.

Implements the full UMa logic, including the stochastic calculation of the effective environment height h_E and the breakpoint distance d_BP, which depends on the effective antenna heights.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3). The 3rd column (height) must be in the range [1.5, 22.5].

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3).

Raises:

ValueError – If any h_UT value is outside its valid range.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3).

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3).

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

UMa pathloss model

UMa pathloss model

UMi (Urban Microcell) pathloss model

class UMi_pathloss_model_00.UMi_pathloss(fc_GHz=3.5, h_UT=1.5, h_BS=10.0, LOS=True, **args)

The complete Urban Microcell (UMi) pathloss model from 3GPP TR 38.901.

This class implements the full UMi model where antenna heights can vary for each link. Unlike UMi_pathloss_constant_height, it calculates all pathloss coefficients dynamically at runtime based on the specific heights of the UE and BS involved in each link. This provides maximum accuracy at the cost of computational performance.

See also

UMi_pathloss_constant_height

Simplified model with fixed heights.

UMi_pathloss_discretised

Performance-oriented model with quantised heights.

References

  • 3GPP TR 38.901, Section 7.4.1, Table 7.4.1-1.

__init__(fc_GHz=3.5, h_UT=1.5, h_BS=10.0, LOS=True, **args)

Initialise the UMi_pathloss model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz, by default 3.5.

  • h_UT (float, optional) – Default height of the User Terminal in metres, used for plotting. Defaults to 1.5.

  • h_BS (float, optional) – Default height of the Base Station in metres, used for plotting. Defaults to 10.0.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculate the linear pathgain.

Pathgain is defined as the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations and heights.

  • C (numpy.ndarray) – Array of cell locations and heights.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculate linear pathloss with dynamic antenna heights.

This method computes pathloss by dynamically calculating coefficients for each UE-cell link based on their specific heights, extracted from the U and C arrays.

Parameters:
  • d2D_m (numpy.ndarray) – A matrix of 2D distances in metres. Shape: (n_ues, n_cells).

  • d3D_m (numpy.ndarray) – A matrix of 3D distances in metres. Shape: (n_ues, n_cells).

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3). The 3rd column (height) must be in the range [1.5, 22.5].

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3).

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

Raises:

ValueError – If any h_UT value is outside its valid range of [1.5, 22.5]m.

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculate the pathloss in decibels (dB).

This method is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations and heights, shape (n_ues, 3).

  • C (numpy.ndarray) – Array of cell locations and heights, shape (n_cells, 3).

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

class UMi_pathloss_model_00.UMi_pathloss_constant_height(fc_GHz=3.5, h_UT=1.5, h_BS=10.0, LOS=True, **args)

Urban Microcell (UMi) pathloss model assuming constant antenna heights.

This class implements a simplified version of the 3GPP TR 38.901 UMi model. By assuming that the heights of the User Terminal and Base Station are constant for all links, it can pre-calculate several coefficients during initialisation. This leads to a significant performance gain during runtime compared to the full model, which must compute these values dynamically for each link.

fc_GHz

Centre frequency in GHz.

Type:

float

h_BS

Height of the base station in metres.

Type:

float

h_UT

Height of the user terminal in metres.

Type:

float

LOS

Indicates if the Line-of-Sight (True) or Non-Line-of-Sight (False) model is active.

Type:

bool

References

  • 3GPP TR 38.901, Section 7.4.1, Table 7.4.1-1.

__init__(fc_GHz=3.5, h_UT=1.5, h_BS=10.0, LOS=True, **args)

Initialise the UMi_pathloss_constant_height model instance.

This constructor sets up the model’s parameters and pre-calculates the constant terms used in the pathloss formulas, based on the fixed antenna heights.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz, by default 3.5.

  • h_UT (float, optional) – Height of the User Terminal in metres. Must be in [1.5, 22.5]. Defaults to 1.5.

  • h_BS (float, optional) – Height of the Base Station in metres, by default 10.0.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

Raises:

ValueError – If h_UT is outside its valid range of [1.5, 22.5]m.

get_pathgain(d2D_m, d3D_m)

Calculate the linear pathgain.

Pathgain is defined as the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m)

Calculate the linear pathloss for each UE-cell link.

This method computes the pathloss using pre-calculated coefficients. For Line-of-Sight (LOS) conditions, it applies a dual-slope model based on the breakpoint distance d_BP. For Non-Line-of-Sight (NLOS), it calculates the NLOS pathloss and returns the maximum of the two.

Parameters:
  • d2D_m (numpy.ndarray) – A matrix of 2D distances (ground distances) in metres between UEs and cells. Shape: (n_ues, n_cells).

  • d3D_m (numpy.ndarray) – A matrix of 3D distances (direct line-of-sight distances) in metres between UEs and cells. Shape: (n_ues, n_cells).

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m)

Calculate the pathloss in decibels (dB).

This method is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres between UEs and cells.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

class UMi_pathloss_model_00.UMi_pathloss_discretised(fc_GHz=3.5, h_ut_res=0.5, h_bs_res=1.0, h_bs_min=10.0, h_bs_max=25.0, LOS=True, **args)

Urban Microcell (UMi) pathloss model with discretised heights.

This class implements a performance-optimised version of the UMi model. It pre-calculates pathloss coefficients for a grid of discrete UE and BS heights. At runtime, it rounds the actual antenna heights to the nearest grid point and uses the corresponding pre-calculated values. This approach trades a small amount of accuracy for a significant gain in computational speed, making it suitable for large-scale simulations.

See also

UMi_pathloss

The full, exact UMi pathloss model implementation.

UMi_pathloss_constant_height

Simplified model with fixed heights.

References

  • 3GPP TR 38.901, Section 7.4.1, Table 7.4.1-1.

__init__(fc_GHz=3.5, h_ut_res=0.5, h_bs_res=1.0, h_bs_min=10.0, h_bs_max=25.0, LOS=True, **args)

Initialise the UMi_pathloss_discretised model instance.

This constructor defines the discrete height grids for UEs and BSs and pre-calculates the pathloss coefficient matrices for every combination of heights on those grids.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in GHz, by default 3.5.

  • h_ut_res (float, optional) – Resolution of the discrete UT height grid in metres, by default 0.5.

  • h_bs_res (float, optional) – Resolution of the discrete BS height grid in metres, by default 1.0.

  • h_bs_min (float, optional) – The minimum BS height for the discretisation grid. Defaults to 10.0. 3GPP does not specify a constraint on BS height, hence the user might want to change this value to suit their scenario.

  • h_bs_max (float, optional) – The maximum BS height for the discretisation grid. Defaults to 10.0. 3GPP does not specify a constraint on BS height, hence the user might want to change this value to suit their scenario.

  • LOS (bool, optional) – Specifies whether to use the Line-of-Sight model. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculate the linear pathgain.

Pathgain is defined as the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations and heights.

  • C (numpy.ndarray) – Array of cell locations and heights.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculate linear pathloss using discretised height lookups.

This method determines the appropriate indices in the pre-calculated coefficient matrices by rounding the actual UE and BS heights. It then uses these indexed values to compute the pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – A matrix of 2D distances in metres. Shape: (n_ues, n_cells).

  • d3D_m (numpy.ndarray) – A matrix of 3D distances in metres. Shape: (n_ues, n_cells).

  • U (numpy.ndarray) – Array of UE locations and heights. The 3rd column must be within the defined grid range.

  • C (numpy.ndarray) – Array of cell locations and heights. The 3rd column must be within the defined grid range.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

Raises:

ValueError – If any h_UT or h_BS value is outside its valid grid range.

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculate the pathloss in decibels (dB).

This method is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations and heights, shape (n_ues, 3).

  • C (numpy.ndarray) – Array of cell locations and heights, shape (n_cells, 3).

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

UMi pathloss model

UMi pathloss model

InH (Indoor Hotspot) pathloss model

class InH_pathloss_model_01.InH_pathloss(fc_GHz=3.5, LOS=True, **args)

Indoor Hotspot (InH) pathloss model from 3GPP TR 38.901.

Calculates pathloss for indoor office environments, supporting both Line-of-Sight (LOS) and Non-Line-of-Sight (NLOS) scenarios.

fc_GHz

Centre frequency in gigahertz.

Type:

float

LOS

Flag indicating if the Line-of-Sight model is active.

Type:

bool

References

__init__(fc_GHz=3.5, LOS=True, **args)

Initialises the InH_pathloss model instance.

Parameters:
  • fc_GHz (float, optional) – Centre frequency in gigahertz. Defaults to 3.5.

  • h_UT (float, optional) – Default User Terminal height in metres. Defaults to 1.5.

  • h_BS (float, optional) – Default Base Station height in metres. Defaults to 3.0.

  • LOS (bool, optional) – Specifies whether the Line-of-Sight (LOS) model should be used. Defaults to True.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix in metres.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations.

  • C (numpy.ndarray) – Array of cell locations.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, U, C)

Calculates the linear pathloss based on the 3GPP InH model.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix (metres). Not used in calculation.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations. Not used in calculation.

  • C (numpy.ndarray) – Array of cell locations. Not used in calculation.

Raises:

ValueError – If any d3D_m value is outside the valid range of [1.0, 150.0] metres.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m, U, C)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix (metres). Not used in calculation.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • U (numpy.ndarray) – Array of UE locations. Not used in calculation.

  • C (numpy.ndarray) – Array of cell locations. Not used in calculation.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

InH_pathloss_model_01.plot_InH_pathloss_or_pathgain(plot_type='pathloss', fc_GHz=3.5, h_UT=1.5, h_BS=3.0, zoom_box=False, print_10m_pl=False, author=' ', x_min=1.0, x_max=120.0)

Plots 3GPP InH pathloss or pathgain model predictions as a self-test.

This function generates a plot of the 3GPP InH pathloss or pathgain models for both Line-of-Sight (LOS) and Non-Line-of-Sight (NLOS) scenarios. It also includes a free-space pathloss reference and an optional zoomed-in view of the plot for detailed analysis.

Parameters:
  • plot_type (str, optional) – Type of plot to generate. Options are ‘pathloss’ (default) to plot pathloss in dB, or ‘pathgain’ to plot linear pathgain.

  • fc_GHz (float, optional) – Carrier frequency in GHz, defaults to 3.5.

  • h_UT (float, optional) – Height of the User Terminal (UE) in metres, defaults to 1.5.

  • h_BS (float, optional) – Height of the Base Station (BS) in metres, defaults to 3.0.

  • zoom_box (bool, optional) – If True, includes a zoomed-in inset on the plot. Defaults to False.

  • print_10m_pl (bool, optional) – If True, prints pathloss values at 10 metres to the console for LOS, NLOS, and free-space scenarios. Defaults to False.

  • author (str, optional) – Author name to include in the plot timestamp. Defaults to ‘ ‘.

  • x_min (float, optional) – Minimum distance for the plot’s x-axis in metres. Defaults to 1.0.

  • x_max (float, optional) – Maximum distance for the plot’s x-axis in metres. Defaults to 120.0.

Raises:

ImportError – If required plotting modules (e.g., matplotlib) are not installed.

Notes

The function uses the InH_pathloss class to compute the pathloss and pathgain values for the different scenarios.

InH pathloss model

InH pathloss model

Power-law pathloss model

class power_law_pathloss_model_02.Power_law_pathloss(fc_GHz, exponent, **args)

Simple power-law (or log-distance) pathloss model.

Calculates pathloss using the formula: PL(d) [dB] = PL(d0) + 10 * n * log10(d / d0)

This implementation fixes the reference distance d0 = 1 metre and calculates the reference pathloss PL(d0) using the free-space formula at 1m.

fc_GHz

Centre frequency in gigahertz (used to calculate PL at 1m).

Type:

float

exponent

The pathloss exponent ‘n’.

Type:

float

L_0

The linear pathloss at the 1-metre reference distance.

Type:

float

L_0_dB

The pathloss in dB at the 1-metre reference distance.

Type:

float

References

      1. Barclay (Ed.), “Propagation of Radiowaves,” 2nd ed., IET, 2003.

__init__(fc_GHz, exponent, **args)

Initialises the Power_law_pathloss model instance.

Parameters:
  • fc_GHz (float) – Centre frequency in gigahertz.

  • exponent (float) – The pathloss exponent ‘n’.

  • **args – Catches unused keyword arguments for API compatibility.

get_pathgain(d2D_m, d3D_m, U, C, **args)

Calculates the linear pathgain.

Pathgain is the reciprocal of the linear pathloss.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix (metres). Unused by this model.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres.

  • U (numpy.ndarray) – Array of UE locations, shape (n_ues, 3). Unused.

  • C (numpy.ndarray) – Array of cell locations, shape (n_cells, 3). Unused

  • **args – Catches unused keyword arguments.

Returns:

The linear pathgain for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss(d2D_m, d3D_m, **args)

Calculates the linear pathloss.

Implements the formula: PL_linear = L_0 * (d ^ exponent) where L_0 is the free-space pathloss at 1 metre. This model only uses the 3D distance.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix (metres). Unused by this model.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • **args – Catches unused keyword arguments.

Returns:

The calculated linear pathloss for each UE-cell link.

Return type:

numpy.ndarray

get_pathloss_dB(d2D_m, d3D_m, **args)

Calculates the pathloss in decibels (dB).

This is a convenience wrapper around get_pathloss() that converts the linear pathloss value to the dB scale.

Parameters:
  • d2D_m (numpy.ndarray) – 2D distance matrix (metres). Unused by this model, but included for API compatibility.

  • d3D_m (numpy.ndarray) – 3D distance matrix in metres between UEs and cells.

  • **args – Catches unused keyword arguments.

Returns:

The pathloss in decibels.

Return type:

numpy.ndarray

power_law_pathloss_model_02.plot_power_law_pathloss_or_pathgain(plot_type='pathloss', fc_GHz=3.5, exponent=3.0, print_10m_pl=False, author='', x_min=35.0, x_max=5000.0)

Plot 3GPP power_law pathloss or pathgain model predictions as a self-test.

Generates a plot comparing the power_law pathloss or pathgain models. It includes a free-space pathloss reference and an optional zoomed-in view for detailed analysis.

Parameters:
  • plot_type (str, optional) – Type of plot to generate. Options are ‘pathloss’ (default) to plot pathloss in dB, or ‘pathgain’ to plot linear pathgain.

  • fc_GHz (float, optional) – Carrier frequency in GHz, by default 3.5.

  • exponent (float, optional) – Exponent used in the power-law model, by default 3.0.

  • print_10m_pl (bool, optional) – If True, prints pathloss values at 10 metres to the console. Defaults to False.

  • author (str, optional) – Author name to include in the plot timestamp, empty by default.

  • x_min (float, optional) – Minimum distance for the plot’s x-axis in metres, by default 35.0.

  • x_max (float, optional) – Maximum distance for the plot’s x-axis in metres, by default 5000.0.

Raises:

ImportError – If required plotting modules (e.g., matplotlib) are not installed.

power_law_pathloss_model

Power-law pathloss model


Last modified: 2025-11-12 14:10