| from get_3GPP_N import get_3GPP_N | |
| from get_3GPP_crc_interleaver_pattern import get_3GPP_crc_interleaver_pattern | |
| from get_3GPP_rate_matching_pattern import get_3GPP_rate_matching_pattern | |
| from get_3GPP_sequence_pattern import get_3GPP_sequence_pattern | |
| from get_3GPP_info_bit_pattern import get_3GPP_info_bit_pattern | |
| from DCKA_polar_decoder import DCKA_polar_decoder | |
| from Scrambler import Scrambler | |
| import IQ_Utils | |
| class MIB_Parser: | |
| ##################################################### | |
| # 38.331. 6.2.2 | |
| # MIB ::= SEQUENCE { | |
| # systemFrameNumber BIT STRING (SIZE (6)), 6 bit | |
| # subCarrierSpacingCommon ENUMERATED {scs15or60, scs30or120}, 1 bit | |
| # ssb_SubcarrierOffset INTEGER (0..15), 4 bit | |
| # dmrs_TypeA_position ENUMERATED {pos2, pos3}, 1 bit | |
| # pdcchConfigSIB1 PDCCH-ConfigSIB1, 8 bit | |
| # cellBarred ENUMERATED {barred, notBarred}, 1 bit | |
| # intraFreqReselection ENUMERATED {allowed, notAllowed}, 1 bit | |
| # spare BIT STRING (SIZE (1)) 1 bit | |
| # | |
| # | |
| #pdcchConfigSIB1 ::= SEQUENCE { | |
| # controlResourceSetZero ControlResourceSetZero, | |
| # searchSpaceZero SearchSpaceZero | |
| #} | |
| ##################################################### | |
| def __init__(self, a_hat, Lmax): | |
| ############# MIB fields parsing for frequency range 1 ############# | |
| mibbits = a_hat | |
| mibbits = ''.join(map(str, mibbits)) | |
| mibbits = mibbits[::-1] #reverse | |
| self.reservedBits = IQ_Utils.bi2de(mibbits[0:2]) | |
| self.k_ssb = mibbits[2] | |
| self.HRF = mibbits[3] | |
| sfnCombinePHYRRC = mibbits[25:31] + mibbits[4:8] | |
| self.systemFrameNumber = IQ_Utils.bi2de(sfnCombinePHYRRC) | |
| if Lmax == 64: | |
| commonSCSs = [60, 120] | |
| else: | |
| commonSCSs = [15, 30] | |
| self.RAN2_sparedBit = mibbits[8] | |
| self.intraFreqSelection = mibbits[9] | |
| self.cellBarred = mibbits[10] | |
| self.pdcchConfigSIB1 = IQ_Utils.bi2de(mibbits[11:19]) | |
| self.dmrs_TypeA_position = 2 + int(mibbits[19]) | |
| self.ssb_SubcarrierOffset = IQ_Utils.bi2de(mibbits[20:24]) | |
| self.subCarrierSpacingCommon = commonSCSs[int(mibbits[24])] | |
| self.msgIndicator = mibbits[31] | |
| print "NFrame: ", self.systemFrameNumber | |
| print "SubcarrierSpacingCommon: ", self.subCarrierSpacingCommon | |
| print "ssb-SubcarrierOffset: ", self.ssb_SubcarrierOffset | |
| print "DL-DMRS_typeA_pos: ", self.dmrs_TypeA_position | |
| print "PDCCHConfigSIB1: ", self.pdcchConfigSIB1 | |
| print "CellBarred: ", self.cellBarred | |
| print "IntraFreqSelection: ", self.intraFreqSelection | |
| print "Spare: ", self.RAN2_sparedBit | |
| print "k_ssb", self.k_ssb | |
| print "HRF: ", self.HRF | |
| print "reservedBits:", self.reservedBits | |
| ############################################################################## | |
| # NR PBCH payload interleaving | |
| # NOTE: N/A | |
| # input: | |
| # payload (32-bit) | |
| # output: | |
| # interleaved payload (32-bit) | |
| ############################################################################## | |
| def get_3GPP_PBCH_payload_intlv(payload_bit): | |
| mib_intlv_pattern = [1,16,23,18,17,8,30,4,9,11,12,13,14,15,19,20,21,22,25, | |
| 26,27,28,29,31,10,6,24,7,0,5,3,2] | |
| intlv_out = [0]*32 | |
| for idx in xrange(31,-1,-1): | |
| intlv_out[idx] = payload_bit[mib_intlv_pattern[idx]] | |
| return intlv_out | |
| ##################################################################################################################################### | |
| # PBCH_DECODER Polar decoder for the Public Broadcast Channel (PBCH) of 3GPP New Radio, as defined in Section 7.1 of TS38.212. | |
| # Implements the Cyclic Redudancy Check (CRC) attachment of Section 7.1.3, the channel coding of Section 7.1.4 and the rate | |
| # matching of Section 7.1.5. | |
| # NOTE: This code does not implement the payload generation of Section 7.1.1 or the scrambling of Section 7.1.2. Function decodes | |
| # the encoded LLR sequence f_tilde, in order to obtain the recovered information bit sequence a_hat. | |
| # input: | |
| # f_tilde should be a real row vector comprising 864 Logarithmic Likelihood Ratios (LLRS), each having a value obtained | |
| # as LLR = ln(P(bit=0)/P(bit=1)). The first LLR corresponds to f_0 from Section 7.1.5 of TS38.212, while the last LLR | |
| # corresponds to f_E-1. | |
| # A should be 32. It specifies the number of bits in the information bit sequence. | |
| # L should be a scalar integer. It specifies the list size to use during Successive Cancellation List (SCL) decoding. | |
| # min_sum shoular be a scalar logical. If it is true, then the SCL decoding process will be completed using the min-sum | |
| # approximation. Otherwise, the log-sum-product will be used. The log-sum-product gives better error correction capability | |
| # than the min-sum, but it has higher complexity. | |
| # Lmax is number of SSB candidates in a burst. | |
| # output: | |
| # a_hat will be a binary row vector comprising 32 bits, each having the value 0 or 1. The first output bit corresponds | |
| # to a'_0 from Section 7.1.3 of TS38.212, while the last output bit corresponds to a'_A-1. | |
| ##################################################################################################################################### | |
| def PBCH_decoder(f_tilde, A, list_size, min_sum, NidCell, Lmax, ibar_SSB): | |
| E = len(f_tilde) | |
| # A is always 32 in PBCH | |
| if A != 32: | |
| raise Exception('polar_3gpp_matlab:UnsupportedBlockLength, A should be 32.') | |
| # E is always 864 in PBCH | |
| if E != 864: | |
| raise Exception('polar_3gpp_matlab:UnsupportedBlockLength, E should be 864.') | |
| # The CRC polynomial used in 3GPP PBCH and PDCCH channel is | |
| # D^24 + D^23 + D^21 + D^20 + D^17 + D^15 + D^13 + D^12 + D^8 + D^4 + D^2 + D + 1 | |
| crc_polynomial_pattern = [1,1,0,1,1,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,1,1,1] | |
| # The CRC has P bits. P-min(P2,log2(L)) of these are used for error | |
| # detection, where L is the list size. Meanwhile, min(P2,log2(L)) of | |
| # them are used to improve error correction. So the CRC needs to be | |
| # min(P2,log2(L)) number of bits longer than CRCs used in other codes, | |
| # in order to achieve the same error detection capability. | |
| P = len(crc_polynomial_pattern) - 1 | |
| P2 = 3 | |
| # Determine the number of information and CRC bits. | |
| K = A + P | |
| # Determine the number of bits used at the input and output of the polar | |
| # encoder kernal. | |
| N = get_3GPP_N(K, E, 9) | |
| # Get the 3GPP CRC interleaver pattern. | |
| crc_interleaver_pattern = get_3GPP_crc_interleaver_pattern(K) | |
| # Get the 3GPP rate matching pattern. | |
| rate_matching_pattern,mode = get_3GPP_rate_matching_pattern(K, N, E) | |
| # Get the 3GPP sequence pattern. | |
| Q_N = get_3GPP_sequence_pattern(N) | |
| # Get the 3GPP information bit pattern. | |
| info_bit_pattern = get_3GPP_info_bit_pattern(K, Q_N, rate_matching_pattern, mode) | |
| # Initialize scrambler | |
| scrambler = Scrambler(NidCell, Lmax) | |
| f_tilde_scrambled = scrambler.get_3GPP_2nd_scramble_s_seq(f_tilde, ibar_SSB) # scramble 864 LLRs | |
| # Perform Distributed-CRC-and-Known-bit-Aided polar decoding. | |
| a_hat = DCKA_polar_decoder(f_tilde_scrambled, crc_polynomial_pattern, crc_interleaver_pattern, info_bit_pattern, rate_matching_pattern, mode, list_size, min_sum, P2) | |
| if (a_hat == 0): | |
| print "no MIB" | |
| else: | |
| cellSfn = 1 # System frame number for cell | |
| scrambled = scrambler.get_3GPP_1st_scramble_s_seq(cellSfn, a_hat) # Get scrambled hard coded bits | |
| out = get_3GPP_PBCH_payload_intlv(scrambled) # Get interleaved payload | |
| MIB_Parser(out, Lmax) # Parse MIB field messages from bit sequence | |