Search space, CORESET and blind decoding of PDCCH channels in 5G Networks
The purpose of this tutorial is to simulate PDCCH Blind Decoding.
In this tutorial, we assume that the Base Station (BS) transimts DCI corresponding to a UE chosing an aggregation level of 2.
The number of PDCCH candidates that a UE has to search blindly is [2,4,0,0,0]. i.e., UE has to search blindly for 4 candidates of AL 2.
The PDCCH occupies a specific number of REs according to its aggregation level (AL) chosen by Base Station (BS).
An AL is quantified in terms of the number of Control Channel Elements (CCE) that it occupies.
Aggregation level of L = L * 72 Resource Elements (REs) on a down link (DL) grid including DMRS of PDCCH.
Possible PDCCH AL can be any value from the set {1,2,4,8,16}.
For every CCE of 1 OFDM symbol (i.e 72 REs) 54 REs are reserved for PDCCH payload and remaining 18 are reserved for PDCCH DMRS respectively. 54 + 18 = 72 and the ratio 54/18 = 3.
PDCCH Aggregation level is chosen based on search space type and is either common search space (CSS) or UE specific search space (USS).
Table of Contents
Note:
1 CCE = 6 REGs = 6 RBs with 1 OFDM symbol = 6*12 REs = 72 REs
1 CCE = 6/(num of OFDM symbol) RBs. i.e.,
For 3 OFDM symbol 1 CCE = 2 RBs = 2 * 12 * 3 = 24 * 3 = 72 REs.
For 2 OFDM symbol 1 CCE = 3 RBs = 3 * 12 * 2 = 36 * 2 = 72 REs.
For 1 OFDM symbol 1 CCE = 6 RBs = 6 * 12 * 1 = 72 * 1 = 72 REs.
1 REG = 1 RB with 1 OFDM symbol = 12 REs
1 RB = 12 SCs with any number of OFDM symbol = 12 REs with any number of OFDM symbol
1 RE = 1 SC with 1 OFDM symbol
Import Libraries
Python Libraries
[1]:
import numpy as np
import matplotlib as mpl
%matplotlib widget
# %matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
5G Toolkit Libraries
[2]:
import sys
sys.path.append("../../../")
from toolkit5G.PhysicalChannels import PDCCH, PDCCHDecoder, PDCCHCandidateBlindDecoding
from toolkit5G.ResourceMapping import ResourceMappingPDCCH, CORESET, SearchSpaceSet
from toolkit5G.ReceiverAlgorithms import ChannelEstimationAndEqualizationPDCCH
from toolkit5G.ChannelModels import AntennaArrays, SimulationLayout, ParameterGenerator, ChannelGenerator
from toolkit5G.ChannelProcessing import AddNoise
Simulation Parameters
[3]:
terrain = "CDL-A" # Propagation Scenario or Terrain for BS-UE links
carrierFrequency = 3.6*10**9 # carrier frequency in Hz
mu = 0 # numerology
scs = (2**mu)*(15*10**3) # sub-carrier spacing
slotNumber = 0 # slot number. Note that number of slots per sub-frame of 1 ms is 2**mu
numRBs = 270 # max number of PRBs. Please don't change this. The simulation will break down
Bandwidth = numRBs*scs
nBSs = 1 # number of BSs
nUEs = 1 # number of UEs
bsArrayGeometry = np.array([1,1,1,2,2])
ueArrayGeometry = np.array([1,1,1,1,2])
Nt = bsArrayGeometry.prod()
Nr = ueArrayGeometry.prod()
rnti = np.random.randint(1,65519+1)
nID = np.random.randint(2**16)
nBatches = 10 # number of batches
nOFDMSymPerSlot = 14 # number of ofdm symbols per slot
nSCs = numRBs*12 # max number of Sub-Carriers
CORESET and Search Space Set Parameters
[4]:
frequencyDomainResources = np.array([1,1,1,1,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0], dtype = int)
duration = 3
monitoringSymbolsWithinSlot = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype = int)
startSymIndex = np.nonzero(monitoringSymbolsWithinSlot)[0][0]
coresetID = 1
cce_reg_Mapping = "interleaved" # CCE to REG mapping type
L = 3 # REG-Bundle size
R = 3 # Interleaver size
nshift = 0 # cyclic-shift index after interleaving
coresetObj = CORESET(duration,frequencyDomainResources)
coresetPRBIndices = coresetObj(cce_REG_MappingType = cce_reg_Mapping,
reg_BundleSize=L, interleaverSize = R, shiftIndex = nshift)
coresetSize = coresetObj.numCCESInCoreset
ssType = "USS"
AggLevel = 2 # Aggregation level
coresetSize = coresetObj.numCCESInCoreset # CORESET size in number of CCEs
numCandidatesPerAL = np.array([2,4,0,0,0], dtype=int) # number of pdcch candidates per Aggregation Level.
ssObj = SearchSpaceSet(numerology = mu, searchSpaceType = ssType,
numCandidates = numCandidatesPerAL, coresetDuration = duration)
##############
# CCE indices
##############
M = numCandidatesPerAL[int(np.log2(AggLevel))]
ueCand = ssObj(AggLevel,rnti,coresetSize,slotNumber,coresetID)
ueCCEs = ueCand[np.random.randint(M)]
print("#####################################################################")
print("Duration of CORESET:", duration)
print()
print("Frequency Domain Resources:", frequencyDomainResources)
print()
print("CORESET size in CCEs:", coresetObj.numCCESInCoreset)
print()
print("Monitoring Symbols With in a Slot:", monitoringSymbolsWithinSlot)
print()
print("CORESET Start symbol index:", startSymIndex)
print()
print("#####################################################################")
print("Candidates Corresponding to UE with a chosen Aggregation Level of " + str(AggLevel) + ":\n", ueCand)
print()
print("CCEs Corresponding to UE:\n", ueCCEs)
#####################################################################
Duration of CORESET: 3
Frequency Domain Resources: [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0]
CORESET size in CCEs: 15
Monitoring Symbols With in a Slot: [0 0 1 0 0 0 0 0 0 0 0 0 0 0]
CORESET Start symbol index: 2
#####################################################################
Candidates Corresponding to UE with a chosen Aggregation Level of 2:
[[10 11]
[12 13]
[ 2 3]
[ 6 7]]
CCEs Corresponding to UE:
[6 7]
Transmitter Side Processing
[5]:
numPDCCHSym = int(54*AggLevel) # number of PDCCH symbol
numPDCCHdmrs = int(18*AggLevel) # number of PDCCH DMRS symbol
E = numPDCCHSym*2 # number of target bits
Kmax = 100 # max payload size in bits
K = int(12 + np.random.randint(np.minimum(Kmax, E)-24, dtype = int)) # payload size in bits
dciBits = np.random.randint(0, 2, [nBatches, K])
##############################################
# PDCCH chain and generation of QPSK symbols
##############################################
pdcchObj = PDCCH(K, E, rnti, nID)
symb = pdcchObj(dciBits)
###################
# Resource Mappping
###################
rmObj = ResourceMappingPDCCH(mu, frequencyDomainResources, duration, monitoringSymbolsWithinSlot)
resGrid = rmObj(symb, cce_reg_Mapping, L, R, nshift, slotNumber, nID, ueCCEs)
##############################################
# Loading resource grid in transmission grid
##############################################
Nfft = 2**np.random.randint(np.ceil(np.log2(12*numRBs)), 13) # fft size
txGrid = np.zeros(resGrid.shape[0:-1]+(Nfft,),dtype = np.complex64)
bwpOffset = np.random.randint(Nfft - 12*numRBs)
txGrid[..., bwpOffset:bwpOffset+12*numRBs] = resGrid
#################################################
# Beamformed Grid.
# Currently repeating across each antenna element
#################################################
Xf = txGrid[...,np.newaxis].repeat(Nt, axis = -1)
print()
print(" BWP Offset: "+str(bwpOffset))
print()
print(" Transmission Grid Shape: "+str(txGrid.shape)) # (nBatches,nSymbols,nSCs)
print()
print(" Beamformed Grid Shape: "+str(Xf.shape)) # (nBatches,nSymbols,nSCs,Nr)
BWP Offset: 27
Transmission Grid Shape: (10, 14, 4096)
Beamformed Grid Shape: (10, 14, 4096, 4)
[13]:
resGrid.shape
[13]:
(10, 14, 3240)
Displaying Resource Grid
[20]:
fig, ax = plt.subplots(figsize = (10,20))
colors = ['white', 'palegreen', 'lightcoral', 'gold', 'midnightblue', 'purple']
bounds = [0,1,2,3,4,5,6]
cmap = mpl.colors.ListedColormap(colors)
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
Grid = resGrid[...,0:400].sum(axis=0)
plt.imshow(np.abs(Grid.T), interpolation='none', aspect = "auto", cmap=cmap, norm=norm, origin='lower')
ax.set_xticks(np.arange(-0.5, Grid.shape[0], 1), minor=True)
ax.set_xticks(np.arange( 0, Grid.shape[0], 1), minor=False)
ax.set_yticks(np.arange(0, Grid.shape[1]+1, 4), minor=True)
ax.set_yticks(np.arange(0, Grid.shape[1]+1, 12), minor=False)
ax.tick_params(axis='both',which='minor', grid_linewidth= 2, width=0)
ax.tick_params(axis='both',which='major', grid_linewidth=0.5, grid_linestyle = '--')
ax.grid(which='both')
plt.show()
Wireless Channel : CDL-A
[7]:
##########################
# Antenna Array at UE side
##########################
# assuming antenna element type to be "OMNI"
# with 2 panel and 2 single polarized antenna element per panel.
ueAntArray = AntennaArrays(antennaType = "OMNI", centerFrequency = carrierFrequency,
arrayStructure = ueArrayGeometry)
ueAntArray()
# # Radiation Pattern of Rx antenna element
# ueAntArray.displayAntennaRadiationPattern()
##########################
# Antenna Array at BS side
##########################
# assuming antenna element type to be "3GPP_38.901", a parabolic antenna
# with 4 panel and 4 single polarized antenna element per panel.
bsAntArray = AntennaArrays(antennaType = "3GPP_38.901", centerFrequency = carrierFrequency,
arrayStructure = bsArrayGeometry)
bsAntArray()
# # Radiation Pattern of Tx antenna element
# bsAntArray[0].displayAntennaRadiationPattern()
####################
# Layout Parameters
####################
isd = 200 # inter site distance
minDist = 10 # min distance between each UE and BS
ueHt = 1.5 # UE height
bsHt = 25 # BS height
bslayoutType = "Hexagonal" # BS layout type
ueDropType = "Hexagonal" # UE drop type
htDist = "equal" # UE height distribution
ueDist = "equal" # UE Distribution per site
nSectorsPerSite = 1 # number of sectors per site
maxNumFloors = 1 # Max number of floors in an indoor object
minNumFloors = 1 # Min number of floors in an indoor object
heightOfRoom = 3 # height of room or ceiling in meters
indoorUEfract = 0.5 # Fraction of UEs located indoor
lengthOfIndoorObject = 3 # length of indoor object typically having rectangular geometry
widthOfIndoorObject = 3 # width of indoor object
forceLOS = False # boolen flag if true forces every link to be in LOS state
# simulation layout object
simLayoutObj = SimulationLayout(numOfBS = nBSs,
numOfUE = nUEs,
heightOfBS = bsHt,
heightOfUE = ueHt,
minUEBSDistance = minDist,
ISD = isd,
layoutType = bslayoutType,
ueDropMethod = ueDropType,
UEdistibution = ueDist,
UEheightDistribution = htDist,
numOfSectorsPerSite = nSectorsPerSite,
ueRoute = None)
simLayoutObj(terrain = terrain, carrierFreq = carrierFrequency,
ueAntennaArray = ueAntArray, bsAntennaArray = bsAntArray,
indoorUEfraction = indoorUEfract,
lengthOfIndoorObject = lengthOfIndoorObject,
widthOfIndoorObject = widthOfIndoorObject, forceLOS = forceLOS)
paramGen = simLayoutObj.getParameterGenerator()
##############################
# MIMO OFDM channel generation
##############################
channel = paramGen.getChannel()
Hf = channel.ofdm(scs, Nfft, normalizeChannel = True)[0,0,0]
print()
print(" Hf shape: "+str(Hf.shape)) #(nUEs,Nfft, Nr, Nt)
print()
print(" Xf shape: "+str(Xf.shape)) # (numBatches, numSym, nSCs, Nt)
Hf shape: (1, 4096, 2, 4)
Xf shape: (10, 14, 4096, 4)
Receiver Side Processing and Blind Decoding of UE
[8]:
#########################
# SNR for Blind Decoding
########################
snrdB = 10
snrBD = 10**(snrdB/10)
################################
# Received Grid and Equalization
################################
# Output of channel
Y = ((Hf[:,np.newaxis,np.newaxis,...]@Xf[np.newaxis,...,np.newaxis])[...,0])[0]
# Reshaped channel
Hp = ((Hf.sum(axis = -1).transpose(0,2,1)[:,:,bwpOffset:bwpOffset+12*numRBs])[0]).sum(axis=0)[np.newaxis,np.newaxis,:]
# Added noise
Yf = AddNoise(False)(Y, 1/snrBD, 0)
# received grid and Equalization
rxGrid = Yf[...,bwpOffset:bwpOffset+12*numRBs,:]
equalizedGrid = rxGrid.sum(axis=-1)/Hp
#########################
# Intiate Blind Decoding
#########################
bdObj = PDCCHCandidateBlindDecoding(coresetPRBIndices, duration, startSymIndex,
ssType, AggLevel ,ueCand)
bdObj(equalizedGrid, K, E, snrBD, rnti, nID, decoderType="SC", demappingMethod="app")
print("##########################################################################")
print()
Warning: 5G Polar codes use an integrated CRC that cannot be materialized with SC decoding and, thus, causes a degraded performance. Please consider SCL decoding instead.
------------------------------------------------------------------------------------------
Checking the CRC:
[[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]]
Blind Decoding UnSuccessful for CCE Indices [10 11]..!Re-running the script by choosing different candidate
**********************************************************************************************
Warning: 5G Polar codes use an integrated CRC that cannot be materialized with SC decoding and, thus, causes a degraded performance. Please consider SCL decoding instead.
------------------------------------------------------------------------------------------
Checking the CRC:
[[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]]
Blind Decoding UnSuccessful for CCE Indices [12 13]..!Re-running the script by choosing different candidate
**********************************************************************************************
Warning: 5G Polar codes use an integrated CRC that cannot be materialized with SC decoding and, thus, causes a degraded performance. Please consider SCL decoding instead.
------------------------------------------------------------------------------------------
Checking the CRC:
[[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]
[False]]
Blind Decoding UnSuccessful for CCE Indices [2 3]..!Re-running the script by choosing different candidate
**********************************************************************************************
Warning: 5G Polar codes use an integrated CRC that cannot be materialized with SC decoding and, thus, causes a degraded performance. Please consider SCL decoding instead.
------------------------------------------------------------------------------------------
Checking the CRC:
[[ True]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]]
Blind Decoding Successful for the CCE Indices [6 7]..!
##########################################################################
[ ]: