Comparing the LDPC results with MATLAB
Applying LDPC encoding/decoding on random transport blocks and comparing the results with the equivalent MATLAB code “MatlabFiles/LDPC.mlx”. Here is the execution results of this code in MATLAB.
[1]:
import numpy as np
import scipy.io
import time
from neoradium import LdpcCodec
matlabFilesPath = "./MatlabFiles"
[2]:
# Read input bits from MATLAB-generated file
inBits = scipy.io.loadmat(matlabFilesPath+'/in.mat')['in'].reshape(-1)
print(f"First 10 bits: {inBits[:10]}")
# Create an LDPC encoder object
ldpc = LdpcCodec(modulations='QPSK', coderates=449/1024, txBlockSizes=len(inBits), numLayers=1)
print(ldpc)
First 10 bits: [0 0 1 1 0 0 1 1 0 1]
LDPC Encode/Decode Properties:
Num layers: 1
Num codewords: 1
numIter: 5
nRef: 0
Modulation: QPSK
Coderate: 449/1024
TBS: 10000
numLayers: 1
Base Graph: 1
Code Block Size: 5280
Num Code Blocks: 2
Lifting Size: 240
[3]:
# Transport block padded with a 24-bit CRC
cwCodec = ldpc.cwCodecs[0] # The LDPC codec for the first codeword
tbWithCrc = cwCodec.appendCrc(inBits,'24A')
tbWithCrc.shape
[3]:
(10024,)
[4]:
# Do the segmentation:
codeBlocksCrc = cwCodec.doSegmentation(tbWithCrc)
# NeoRadium does not set filler bits to -1. To match with MATLAB, we need to set these bits
# to -1. This is only needed when comparing segmentation results with MATLAB.
fillerStart = cwCodec.codeBlockSize-cwCodec.numFillerBits
codeBlocksCrc[:, fillerStart : fillerStart+cwCodec.numFillerBits] = -1
# Compare results with MATLAB:
codeBlocksCrcMatlab = scipy.io.loadmat(matlabFilesPath+'/cbsIn.mat')['cbsIn'].T
assert np.abs(codeBlocksCrc-codeBlocksCrcMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
print("CodeBlocks Shape (Including CRC):", codeBlocksCrc.shape)
print("liftingSize (Zc): ", cwCodec.liftingSize)
print("setIndex (Zero-Based): ", cwCodec.setIndex)
print("numFillerBits: ", cwCodec.numFillerBits)
CodeBlocks Shape (Including CRC): (2, 5280)
liftingSize (Zc): 240
setIndex (Zero-Based): 7
numFillerBits: 244
[5]:
print("Base Graph Shape:", cwCodec.baseGraph.shape)
print("8x8 sub-matrix at the \"Double Diagonal\" section:")
for r in cwCodec.baseGraph[0:8,22:30]: print(" " + " ".join("%3d"%x for x in r))
Base Graph Shape: (46, 68)
8x8 sub-matrix at the "Double Diagonal" section:
1 0 -1 -1 -1 -1 -1 -1
0 0 0 -1 -1 -1 -1 -1
-1 -1 0 0 -1 -1 -1 -1
1 -1 -1 0 -1 -1 -1 -1
-1 -1 -1 -1 0 -1 -1 -1
180 -1 -1 -1 -1 0 -1 -1
-1 -1 -1 -1 -1 -1 0 -1
-1 -1 -1 -1 -1 -1 -1 0
[6]:
# Check the valid LDPC coded blocks:
# Do not puncture first 2 columns because we need the whole coded blocks for the
# "isValidCodedBlock" function below
testCodedBlocks = cwCodec.encodeCodeBlocks(codeBlocksCrc, puncture=False)
(cwCodec.isValidCodedBlock(testCodedBlocks[0]),
cwCodec.isValidCodedBlock(testCodedBlocks[1]),
cwCodec.isValidCodedBlock(np.zeros(68*cwCodec.liftingSize)), # Always valid
cwCodec.isValidCodedBlock(np.ones(68*cwCodec.liftingSize))) # Intentionally Invalid
[6]:
(True, True, True, False)
[7]:
# Normal usage (1st 2 columns punctured, zero filler bits)
# Do segmentation
codeBlocksCrc = cwCodec.doSegmentation(tbWithCrc)
# Encoding:
codedBlocks = cwCodec.encodeCodeBlocks(codeBlocksCrc)
print("codedBlocks Shape:", codedBlocks.shape)
# NeoRadium does not set filler bits to -1. To match with MATLAB, we need to set these bits
# to -1. This is only needed when comparing encoder output (before rate matching) with MATLAB.
fillerStart = cwCodec.codeBlockSize-cwCodec.numFillerBits-2*cwCodec.liftingSize
codedBlocks[:, fillerStart : fillerStart+cwCodec.numFillerBits] = -1
# Compare results with MATLAB:
codedBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/enc.mat')['enc'].T
assert np.abs(codedBlocks-codedBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
codedBlocks Shape: (2, 15840)
[8]:
rateMatchedCodeBlocks = cwCodec.rateMatch(codedBlocks)
print("Rate-Matched coded blocks Shape:", rateMatchedCodeBlocks.shape)
# Compare results with MATLAB:
rateMatchedCodeBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/chIn.mat')['chIn'].T
assert np.abs(rateMatchedCodeBlocks-rateMatchedCodeBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
Rate-Matched coded blocks Shape: (22808,)
[9]:
# Do all of it with one call
rateMatchedCodeBlocks = cwCodec.encode(inBits)
# Compare results with MATLAB:
assert np.abs(rateMatchedCodeBlocks-rateMatchedCodeBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
[10]:
# Simple bipolar channel with no noise:
channelOutput = 1 - 2.0*rateMatchedCodeBlocks
[11]:
# Recover rate
rxCodedBlocks = cwCodec.recoverRate(channelOutput)
# Compare results with MATLAB:
rxCodedBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/raterec.mat')['raterec'].T
rxCodedBlocksMatlab[rxCodedBlocksMatlab==np.inf]=cwCodec.LARGE_LLR # Replace inf with our LARGE_LLR
assert np.abs(rxCodedBlocks-rxCodedBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
rxCodedBlocks.shape
[11]:
(2, 15840)
[12]:
# Decode the rate-recovered message
rxCodeBlocks = cwCodec.decodeCodeBlocks(rxCodedBlocks)
rxCodeBlocks.shape
[12]:
(2, 5280)
[13]:
# Compare results with MATLAB:
rxCodeBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/decBits.mat')['decBits'].T
assert np.abs(rxCodeBlocks-rxCodeBlocksMatlab).sum()==0, "MISMATCH WITH MATLAB!!!"
[14]:
# Undo Segmentation and CRC checking
rxCodeBlocksWithoutCrc, crcMatch = cwCodec.checkCrcAndMerge(rxCodeBlocks)
print("CRC Matched:", crcMatch)
# Compare results with MATLAB:
rxCodeBlocksWithoutCrcMatlab = scipy.io.loadmat(matlabFilesPath+'/decBlk.mat')['decBlk'].T
assert np.abs(rxCodeBlocksWithoutCrc-rxCodeBlocksWithoutCrc).sum()==0, "MISMATCH WITH MATLAB!!!"
rxCodeBlocksWithoutCrc.shape
CRC Matched: [ True True]
[14]:
(10024,)
[15]:
# The transport block CRC checking
print(cwCodec.checkCrc(rxCodeBlocksWithoutCrc,'24A'))
True
[16]:
# Compare with original input
assert np.abs(rxCodeBlocksWithoutCrc[:-24]-inBits).sum()==0, "MISMATCH WITH INPUT BITS!!!"
[17]:
# Do the whole decoding process in one call:
rxBlock, crcMatch = cwCodec.decode(channelOutput)
print("CRC Matched:", crcMatch)
# Compare results with MATLAB:
rxTxBlocksWithCrcMatlab = scipy.io.loadmat(matlabFilesPath+'/decBlk.mat')['decBlk'].T
assert np.abs(rxTxBlocksWithCrcMatlab[:,:-24]-rxBlock).sum()==0, "MISMATCH WITH MATLAB!!!"
# Compare with original input
assert np.abs(rxBlock-inBits).sum()==0, "MISMATCH WITH INPUT BITS!!!"
CRC Matched: [ True True True]
[ ]: