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
  Num Parity checks (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
codeWords = polarEncoder.encode(codeBlocks)
print("Code Words Shape:        ", codeWords.shape)
print("Code Words first 10 bits:", "".join(str(x) for x in codeWords[0][:10]))

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

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

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

Rate-Matched Shape:   (1, 120)
First 10 bits:        1001110011
[7]:
# QPSK Modulation
modulated = nr.Modem('QPSK').modulate(rateMatchedCodeWords)
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').getLLRsFromSymbols(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:
hardCodeWord = 1*(llrs<0)
print("Hard Decision first 10 bits:", "".join(str(x) for x in hardCodeWord[0][:10]))
print("Org CodeWord first 10 bits: ", "".join(str(x) for x in codeWords[0][:10]))

Hard Decision first 10 bits: 1001110011
Org CodeWord first 10 bits:  1001110011
[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
  Num Parity checks (nPC, nPCwm) : 0,0
  SCL List Size .................: 8
  MinSum 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 MATLAB!!!"

Number of CRC Errors:           0
Decoded Transport Block Shape:  (30,)
Decoded Transport Block:        100100110110000110100110000010
Original Transport Block:       100100110110000110100110000010
Matlab Decoded Transport Block: 100100110110000110100110000010
[ ]:

[ ]: