# 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).

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.ChannelModels      import AntennaArrays, SimulationLayout, ParameterGenerator, ChannelGenerator


## 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)

##############################################
##############################################
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

##########################
# 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

####################
# 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)

################################
################################
# 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,:]
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]..!
##########################################################################


[ ]: