3/17 update:
sendMsg1 is ready now, including:
*PRACH association period determination
*SSB to PRACH occasion mapping
*PRACH time-domain/freq-domain resource mapping
(1) PRACH association period determination
Used method is trying to find minimum valid prach occasions during 160ms (16 frames) period:
self.minNumValidPrachOccasionPerAssociationPeriod = math.ceil(self.numTxSsb / self.nrRachSsbPerRachOccasionM8 * 8)
where:
*numTxSsb is number of transmitted SSBs
*nrRachSsbPerRachOccasionM8 is ssb-perRACH-Occasion multiplied by 8.
Procedure to validate prach occasions:
#refer to 3GPP 38.213 vf40 8.1
#For paired spectrum all PRACH occasions are valid.
#If a UE is provided TDD-UL-DL-ConfigurationCommon, a PRACH occasion in a PRACH slot is valid if
#- it is within UL symbols, or
#- it does not precede a SS/PBCH block in the PRACH slot and starts at least N_gap symbols after a last downlink symbol and at least N_gap symbols after a last SS/PBCH block transmission symbol, where N_gap is provided in Table 8.1-2.
for s in raSlots:
for t in range(self.nrRachCfgNumOccasionsPerSlot):
if self.nrDuplexMode == 'FDD':
for f in range(self.nrRachMsg1Fdm):
validPrachOccasionsPerAssociationPeriod.append([[curHsfn, curSfn, s], t, f])
else:
scaleTd = self.baseScsTd // self.prachScs
rachFirstSymbInBaseScsTd = (s * self.nrSymbPerSlotNormCp + self.nrRachCfgStartSymb + t * self.nrRachCfgDuration) * scaleTd
rachSymbsInbaseScsTd = [rachFirstSymbInBaseScsTd+k for k in range(self.nrRachCfgDuration*scaleTd)]
nGapInBaseScsTd = 0 if self.nrRachScs in ('1.25', '5') or self.nrRachCfgFormat == 'B4' else 2*(self.baseScsTd//self.prachScs)
valid = True
for k in rachSymbsInbaseScsTd:
if tdGrid[k] !=