General assumptions for implementation:
(1) Considerations on time-domain notation
sfn + subframe + slot + symbol
SFN: 0~1023 in decimal and 0x000~0x3FF in hex
subframe per radio frame: 10 in decimal and its index is 0x0~0x9 in hex
slot per subframe: 1~16 in decimal, and its index is 0x0~0xF in hex
symbols per slot: 14 or 12 in decimal, and its index is 0x0~0xB or 0xD in hex
for symbols within a frame: 3bits+1bit+1bit+1bit = 6bits in hex
for slots within a frame: 5bits in hex
for subframes within a frame: 4bits in hex
(2) Considerations on grids
time-domain signals are generated per antenna port per scs
we have different scs settings:
*ssb scs: for pss/sss/pbch/dmrs for pbch
*common scs: for sib1, msg2, msg4 and their dmrs; for coreset0 and its dmrs
*msg1 scs: for prach
*carrier scs: for bwp 0/1, coreset1 and its dmrs; for normal pdsch/pusch and their dmrs; for ptrs for pusch/pdsch; for srs/csi-rs; for pucch and its dmrs
*offsetToPointA: scs same as n_crb_ssb
*offsetToCarrier: scs = carrier scs, assumed equal to minGuardBand
*k_ssb: scs = 15k for ssb type A(FR1) and scs=common scs for ssb type B(FR2)
*n_crb_ssb: scs=15k for ssb type A(FR1) and scs=60k for ssb type B(FR2)
for simplicity, assume base scs is 15k for FR1 and 60k for FR2
(3) Considerations on antenna ports
The following antenna ports are defined for the downlink:
- Antenna ports starting with 1000 for PDSCH
- Antenna ports starting with 2000 for PDCCH
- Antenna ports starting with 3000 for channel-state information reference signals
- Antenna ports starting with 4000 for SS/PBCH block transmission
The following antenna ports are defined for the uplink:
- Antenna ports starting with 0 for demodulation reference signals for PUSCH
- Antenna ports starting with 1000 for SRS, PUSCH
- Antenna ports starting with 2000 for PUCCH
- Antenna port 4000 for PRACH
For DL:
- ap=4000 used for SSB and DMRS for PBCH
- ap=2000 used for PDCCH and DMRS for PDCCH
- ap=1000~1011 used for PDSCH and DMRS for PDSCH
- ap=1000~1005 used for PTRS for PDSCH
- ap=3000~3031 used for CSI-RS
For UL:
- ap=4000 used for PRACH
- ap=2000 used for PUCCH and DMRS for PUCCH
- ap=1000~1003 used for SRS and PUSCH
- ap=0~11 used for DMRS for PUSCH
- ap=0~5 used for PTRS for PUSCH
(4) Always-on transmissions
Only SSB and SIB1 are considered as always-on transmissions.
(5) time/frequency range of grid
for TDD:
self.gridNbTdd[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_F.value)
for FDD:
self.gridNbFddDl[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_D.value)
self.gridNbFddUl[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_U.value)
Example codes for above assumptions:
def init(self):
self.ngwin.logEdit.append('---->inside init')
#HSFN not exit in NR specs, but used in 5GNR resource grid for convenience
self.hsfn = 0
self.nrSubfPerRf = 10
self.nrSlotPerSubf = [2 ** mu for mu in range(5)]
self.nrSlotPerRf = [self.nrSubfPerRf * 2 ** mu for mu in range(5)]
self.nrScs2Mu = {15:0, 30:1, 60:2, 120:3, 240:4}
self.nrSymbPerSlotNormCp = 14
self.nrSymbPerSlotExtCp = 12
self.nrScPerPrb = 12
self.baseScsFd = 15 if self.args['freqBand']['freqRange'] == 'FR1' else 60
self.baseScsTd = 60 if self.args['freqBand']['freqRange'] == 'FR1' else 240
self.nrCarrierScs = int(self.args['carrierGrid']['scs'][:-3])
self.nrCarrierMinGuardBand = int(self.args['carrierGrid']['minGuardBand'])
self.nrCarrierNumRbs = int(self.args['carrierGrid']['numRbs'])
self.nrScTot = self.nrScPerPrb * (self.nrCarrierMinGuardBand + self.nrCarrierNumRbs) * (self.nrCarrierScs // self.baseScsFd)
self.nrSymbPerRfNormCp = self.nrSymbPerSlotNormCp * self.nrSlotPerRf[self.nrScs2Mu[self.baseScsTd]]
self.gridNrTdd = OrderedDict()
self.gridNrFddDl = OrderedDict()
self.gridNrFddUl = OrderedDict()
dn = '%s_%s' % (self.hsfn, self.args['mib']['sfn'])
if self.args['freqBand']['duplexMode'] == 'TDD':
self.gridNrTdd[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_F.value)
if not self.initTddUlDlConfig():
return False
self.initTddGrid(self.hsfn, int(self.args['mib']['sfn']))
elif self.args['freqBand']['duplexMode'] == 'FDD':
self.gridNrFddDl[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_D.value)
self.gridNrFddUl[dn] = np.full((self.nrScTot, self.nrSymbPerRfNormCp), NrResType.NR_RES_U.value)
else:
return False
return True
part of initTddGrid function:
tddCfgMap = {'D':NrResType.NR_RES_D.value, 'F':NrResType.NR_RES_F.value, 'U':NrResType.NR_RES_U.value}
scale = self.baseScsTd // self.nrTddCfgRefScs
self.ngwin.logEdit.append('scale=%d where baseScTd=%dKHz and tddCfgRefScs=%dKHz' % (scale, self.baseScsTd, self.nrTddCfgRefScs))
if sfn % 2 == 0:
for i in range(len(self.tddPatEvenRf)):
for j in range(scale):
self.gridNrTdd[dn][:,i*scale+j] = tddCfgMap[self.tddPatEvenRf[i]]
else:
for i in range(len(self.tddPatOddRf)):
for j in range(scale):
self.gridNrTdd[dn][:,i*scale+j] = tddCfgMap[self.tddPatOddRf[i]]