Comparing the polar coding results with MATLAB

Applying Polar encoding/decoding on random transport blocks and comparing the results with the equivalent MATLAB code “MatlabFiles/Polar.mlx”. Here is the execution results of this code in MATLAB.

[1]:
import numpy as np
import scipy.io
import time

import neoradium as nr

matlabFilesPath = "./MatlabFiles"

[2]:
payloadLen = 30           # A (Must be no larger than 1706)
rateMatchedLen = 120

ebNo = 0.8
codeRate = (payloadLen+24)/rateMatchedLen  # Effective code rate

bps = 2;                             # bits per symbol = 2 for QPSK
esNo = ebNo + 10*np.log10(bps)       # energy per symbol over noise
snrdB = esNo + 10*np.log10(codeRate) # SNR in dB
noiseVar = 1/(10**(snrdB/10))
noiseStd = np.sqrt(noiseVar)
print("Code Rate:     ", codeRate)
print("SNR:           ", snrdB, "dB")
print("Noise Variance:", noiseVar)
print("Noise STD:     ", noiseStd)

Code Rate:      0.45
SNR:            0.3424250943932492 dB
Noise Variance: 0.9241819678918566
Noise STD:      0.9613438343755353
[3]:
# Create a Polar Encoder
polarEncoder = nr.PolarEncoder(payloadLen, rateMatchedLen, 'dci')
polarEncoder.print()


Polar Encoder Properties:
  dataType:                        DCI
  payloadSize (A):                 30
  rateMatchedLen (E):              120
  codeBlockSize (K):               54
  polarCodeSize (N):               128
  Max Log2(N) (nMax):              9
  Segmentation (iSeg):             Disabled
  Code Block CRC (crcPoly):        24C
  Input Interleaving (iIL):        Enabled
  Coded bit Interleaving (iBIL):   Disabled
  Parity-check bits (nPC, nPCwm):  0,0

[4]:
# Read input bits from MATLAB-generated file
txpBlock = scipy.io.loadmat(matlabFilesPath+'/msg.mat')['msg'].reshape(-1)
print("Transport Block Shape: ", txpBlock.shape)
print("Transport Block:       ", "".join(str(x) for x in txpBlock))

# Segmentation
codeBlocks = polarEncoder.doSegmentation(txpBlock)
print("Code Blocks Shape:     ", codeBlocks.shape)
print("Code Blocks:           ", "".join(str(x) for x in codeBlocks[0]))

# Compare with MATLAB
codeBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/msgcrc.mat')['msgcrc'].T
assert np.abs(codeBlocks-codeBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"

Transport Block Shape:  (30,)
Transport Block:        100100110110000110100110000010
Code Blocks Shape:      (1, 54)
Code Blocks:            100100110110000110100110000010111100001010001110100010
[5]:
# Encode
codedBlocks = polarEncoder.encode(codeBlocks)
print("Coded blocks Shape:        ", codedBlocks.shape)
print("Coded blocks first 10 bits:", "".join(str(x) for x in codedBlocks[0][:10]))

# Compare with MATLAB
codedBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/encOut.mat')['encOut'].T
assert np.abs(codedBlocks-codedBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"

Coded blocks Shape:         (1, 128)
Coded blocks first 10 bits: 1001110011
[6]:
# Rate Matching
rateMatchedCodeBlocks = polarEncoder.rateMatch(codedBlocks)
print("Rate-Matched Shape:  ", rateMatchedCodeBlocks.shape)
print("First 10 bits:       ", "".join(str(x) for x in rateMatchedCodeBlocks[0][:10]))

# Compare with MATLAB
rateMatchedCodeBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/modIn.mat')['modIn'].T
assert np.abs(rateMatchedCodeBlocks-rateMatchedCodeBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"

Rate-Matched Shape:   (1, 120)
First 10 bits:        1001110011
[7]:
# QPSK Modulation
modulated = nr.Modem('QPSK').modulate(rateMatchedCodeBlocks)
print("modulated Shape:     ", modulated.shape)

# Compare with MATLAB
modulatedMatlab = scipy.io.loadmat(matlabFilesPath+'/modOut.mat')['modOut'].T
assert np.abs(modulated-modulatedMatlab).max()<1e-12, "MISMATCH WITH MATLAB!!!"
print("Max Diff. with MATLAB:", np.abs(modulated-modulatedMatlab).max())
print("First 5 symbols:\n", modulated[0,:5])

modulated Shape:      (1, 60)
Max Diff. with MATLAB: 1.5700924586837752e-16
First 5 symbols:
 [-0.70710678+0.70710678j  0.70710678-0.70710678j -0.70710678-0.70710678j
  0.70710678+0.70710678j -0.70710678-0.70710678j]
[8]:
# Read the noise from the MATLAB file
complexNoise = scipy.io.loadmat(matlabFilesPath+'/chanNoise.mat')['chanNoise'].T
print("Noise Shape:     ", complexNoise.shape)

# Add noise to the modulated signal
rxSymbols = modulated + complexNoise
print("First 5 Rx Symbols:\n", rxSymbols[0,:5])
Noise Shape:      (1, 60)
First 5 Rx Symbols:
 [-0.51312371+0.76995541j  0.88901799-1.41258547j -1.44741359-1.38917752j
  0.49504718+0.34599014j -1.58021683-0.80163037j]
[9]:
# Demodulation: Calculate LLR values from symbols:
llrs = nr.Modem('QPSK').getLLRs(rxSymbols, noiseVar)
print("LLR Shape:     ", llrs.shape)
print("First 10 LLRs: \n", llrs[0,:10])

# Compare with MATLAB
llrsMatlab = scipy.io.loadmat(matlabFilesPath+'/rxLLR.mat')['rxLLR'].T
print("MATLAB First 10 LLRs: \n", llrsMatlab[0,:10])

assert np.abs(llrs-llrsMatlab).max()<1e-12, "MISMATCH WITH MATLAB!!!"
print("Max Diff. with MATLAB:", np.abs(llrs-llrsMatlab).max())

LLR Shape:      (1, 120)
First 10 LLRs:
 [-1.57039747  2.35642204  2.72080897 -4.32316924 -4.42975952 -4.25153001
  1.51507488  1.05889091 -4.83619924 -2.45336219]
MATLAB First 10 LLRs:
 [-1.57039747  2.35642204  2.72080897 -4.32316924 -4.42975952 -4.25153001
  1.51507488  1.05889091 -4.83619924 -2.45336219]
Max Diff. with MATLAB: 3.552713678800501e-15
[10]:
#Hard Decision:
hardCodeBlock = 1*(llrs<0)
print("Hard Decision first 10 bits:       ", "".join(str(x) for x in hardCodeBlock[0][:10]))
print("Original code block first 10 bits: ", "".join(str(x) for x in codeBlocks[0][:10]))

Hard Decision first 10 bits:        1001110011
Original code block first 10 bits:  1001001101
[11]:
# Create a Polar Decoder
polarDecoder = nr.PolarDecoder(payloadLen, rateMatchedLen, 'dci',
                               sclListSize=8, useMinsum=True)
polarDecoder.print()

Polar Decoder Properties:
  dataType:                        DCI
  payloadSize (A):                 30
  rateMatchedLen (E):              120
  codeBlockSize (K):               54
  polarCodeSize (N):               128
  Max Log2(N) (nMax):              9
  Segmentation (iSeg):             Disabled
  Code Block CRC (crcPoly):        24C
  Input Interleaving (iIL):        Enabled
  Coded bit Interleaving (iBIL):   Disabled
  Parity-check bits (nPC, nPCwm):  0,0
  SCL List Size:                   8
  Min-sum Approximation:           Enabled

[12]:
# Recover rate
rateRecoveredRxBlocks = polarDecoder.recoverRate(llrs)
print("Rate Recovered Shape:     ", rateRecoveredRxBlocks.shape)
print("First 10 LLRs: \n", rateRecoveredRxBlocks[0,:10])

# Compare with MATLAB
rateRecoveredRxBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/decIn.mat')['decIn'].T
print("MATLAB First 10 LLRs: \n", rateRecoveredRxBlocksMatlab[0,:10])

assert np.abs(rateRecoveredRxBlocks-rateRecoveredRxBlocksMatlab).max()<1e-12, "MISMATCH WITH MATLAB!!!"
print("Max Diff. with MATLAB:", np.abs(rateRecoveredRxBlocks-rateRecoveredRxBlocksMatlab).max())

Rate Recovered Shape:      (1, 128)
First 10 LLRs:
 [-1.57039747  2.35642204  2.72080897 -4.32316924 -4.42975952 -4.25153001
  1.51507488  1.05889091 -4.83619924 -2.45336219]
MATLAB First 10 LLRs:
 [-1.57039747  2.35642204  2.72080897 -4.32316924 -4.42975952 -4.25153001
  1.51507488  1.05889091 -4.83619924 -2.45336219]
Max Diff. with MATLAB: 3.552713678800501e-15
[13]:
# Decode the rate-recovered transport blocks
decTxBlock, numCrcErrors = polarDecoder.decode(rateRecoveredRxBlocks)
print("Number of CRC Errors:          ", numCrcErrors)
print("Decoded Transport Block Shape: ", decTxBlock.shape)
print("Decoded Transport Block:       ", "".join(str(x) for x in decTxBlock))
print("Original Transport Block:      ", "".join(str(x) for x in txpBlock))

# Compare with MATLAB
decTxBlockMatlab = scipy.io.loadmat(matlabFilesPath+'/decBits.mat')['decBits'].reshape(-1)[:payloadLen]
print("MATLAB Decoded Transport Block:", "".join(str(x) for x in decTxBlockMatlab))

assert np.abs(txpBlock-decTxBlock).sum()==0, "MISMATCH WITH INPUT BITS!!!"
Number of CRC Errors:           0
Decoded Transport Block Shape:  (30,)
Decoded Transport Block:        100100110110000110100110000010
Original Transport Block:       100100110110000110100110000010
MATLAB Decoded Transport Block: 100100110110000110100110000010
[ ]:

[ ]: