Source code for UMa_pathloss_model

# Keith Briggs 2022-03-07 NLOS case implemented.
# Keith Briggs 2021-10-29 pathloss function now take two arguments, cell position and UE position.  This allows pathloss to depend on absolute position, not just distance
# Keith Briggs 2021-05-17
# Keith Briggs 2020-10-05; cf. ~/Voronoi-2.1/try_3GPP_UMa_pathloss_01.py
# Self-test (makes a plot): python3 UMa_pathloss_model_01.py

from math import log10,hypot
from numpy.linalg import norm

[docs]class UMa_pathloss: ''' Urban macrocell dual-slope pathloss model, from 3GPP standard 36.873, Table 7.2-1. The model is defined in 36873-c70.doc from https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2574. This code covers the cases 3D-UMa LOS and NLOS. 3D-UMa = three dimensional urban macrocell model. LOS = line-of-sight. NLOS = non-line-of-sight. '''
[docs] def __init__(s,fc_GHz=3.5,h_UT=2.0,h_BS=25.0,LOS=True,h=20.0,W=20.0): ''' Initialize a pathloss model instance. Parameters ---------- fc_GHz : float Centre frequency in GigaHertz (default 3.5). h_UT : float Height of User Terminal (=UE) in metres (default 2). h_BS : float Height of Base Station in metres (default 25). LOS: bool Whether line-of-sight model is to be used (default True). h : float Average building height (default 20, used in NLOS case only) W : float Street width (default 20, used in NLOS case only) ''' s.fc=fc_GHz # GHz s.log10fc=log10(s.fc) s.h_UT=h_UT s.h_BS=h_BS s.LOS=LOS s.h=h s.W=W s.c=3e8 s.h_E=1.0 s.dBP=4.0*(s.h_BS-s.h_E)*(s.h_UT-s.h_E)*s.fc*1e9/s.c # Note 1 s.a=9.0*log10(s.dBP**2+(s.h_BS-s.h_UT)**2) # pre-compute constants to speed up calls... s.const_close=28.0+20.0*s.log10fc s.const_far =28.0+20.0*s.log10fc-s.a
[docs] def __call__(s,xyz_cell,xyz_UE): ''' Return the pathloss between 3-dimensional positions xyz_cell and xyz_UE (in metres). Note that the distances, building heights, etc. are not checked to ensure that this pathloss model is actually applicable. ''' # TODO: could we usefully vectorize this, so that xyz_cell,xyz_UE have shape (n,3) to compute n pathlosses at once? d3D_m=norm(xyz_cell-xyz_UE) # new way 2021-10-29 # TODO 2022-04-27: is the next faster? #dxyz=xyz_cell-xyz_UE; d3D_m=hypot(dxyz[0],hypot(dxyz[1],dxyz[2])) if d3D_m<s.dBP: PL3D_UMa_LOS=s.const_close+22.0*log10(d3D_m) else: PL3D_UMa_LOS=s.const_far +40.0*log10(d3D_m) if s.LOS: return PL3D_UMa_LOS # else NLOS: # Formulas from Table 7.2-1 are... # PL3D-UMa-NLOS=161.04-7.1*log10(W)+7.5*log10(h)-(24.37-3.7*(h/hBS)**2)*log10(hBS)+(43.42-3.1*log10(hBS))*(log10(d3D)-3)+20*log10(fc)-(3.2*(log10(17.625))**2-4.97)-0.6*(hUT-1.5) # PL=max(PL3D-UMa-NLOS,PL3D-UMa-LOS) c1=-9.1904695449517596702522e-4 # =3.2*(log10(17.625))**2-4.97 PL3D_UMa_NLOS=161.04-7.1*log10(s.W)+7.5*log10(s.h)-(24.37-3.7*(s.h/s.h_BS)**2)*log10(s.h_BS)+(43.42-3.1*log10(s.h_BS))*(log10(d3D_m)-3.0)+20*log10(s.fc)-(c1)-0.6*(s.h_UT-1.5) # TODO pre-compute more constants to speed this up! return max(PL3D_UMa_NLOS,PL3D_UMa_LOS)
[docs]def plot(): ' Plot the pathloss model predictions, as a self-test. ' import numpy as np import matplotlib.pyplot as plt from fig_timestamp import fig_timestamp fig=plt.figure(figsize=(8,6)) ax=fig.add_subplot() ax.grid(color='gray',alpha=0.7,lw=0.5) d=np.linspace(10,5000,100) # valid from 10m PL=UMa_pathloss(fc_GHz=1.8,h_UT=1.5,h_BS=17.5,LOS=False) NLOS=np.array([PL(0,di) for di in d]) ax.plot(d,NLOS,lw=2,label='NLOS ($\sigma=6$)') # or semilogx ax.fill_between(d,NLOS-6.0,NLOS+6.0,alpha=0.2) # sigma_{SF}=6 for NLOS case PL=UMa_pathloss(fc_GHz=1.8,h_UT=1.5,h_BS=17.5,LOS=True) LOS=np.array([PL(0,di) for di in d]) ax.plot(d,LOS,lw=2,label='LOS ($\sigma=4$)') # or semilogx ax.fill_between(d,LOS-4.0,LOS+4.0,alpha=0.2) # sigma_{SF}=4 for LOS case ax.set_xlabel('distance (metres)') ax.set_ylabel('pathloss (dB)') ax.set_xlim(0,np.max(d)) ax.set_ylim(40) ax.legend() ax.set_title('3GPP UMa pathloss models') fig.tight_layout() fig_timestamp(fig,rotation=0,fontsize=6,author='Keith Briggs') fnbase='img/UMa_pathloss_model_01' fig.savefig(f'{fnbase}.png') print(f'eog {fnbase}.png &') fig.savefig(f'{fnbase}.pdf') print(f'evince {fnbase}.pdf &')
if __name__=='__main__': plot() # simple self-test