{ "cells": [ { "cell_type": "markdown", "id": "22bf3c88", "metadata": {}, "source": [ "# Comparing the LDPC results with Matlab\n", "Applying LDPC encoding/decoding on random transport blocks and comparing the results with the equivalent Matlab code \"MatlabFiles/LDPC.mlx\". [Here](MatlabFiles/LDPC.html) is the execution results of this code in Matlab." ] }, { "cell_type": "code", "execution_count": 1, "id": "0fc98acd", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import scipy.io\n", "import time\n", "\n", "from neoradium import LdpcEncoder, LdpcDecoder\n", "\n", "matlabFilesPath = \"./MatlabFiles\"" ] }, { "cell_type": "code", "execution_count": 2, "id": "52694194", "metadata": {}, "outputs": [], "source": [ "# Create an LDPC encoder object\n", "ldpcEncoder = LdpcEncoder(baseGraphNo=1, modulation='QPSK', rv=0, txLayers=1, nRef=0, targetRate=449/1024)" ] }, { "cell_type": "code", "execution_count": 3, "id": "0d906bd2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 0, 1, 1, 0, 0, 1, 1, 0, 1], dtype=int8)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Read input bits from Matlab-generated file\n", "inBits = scipy.io.loadmat(matlabFilesPath+'/in.mat')['in'].reshape(-1)\n", "inBits[:10]" ] }, { "cell_type": "code", "execution_count": 4, "id": "36d3e1de", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(10024,)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Transport block padded with a 24-bit CRC\n", "tbWithCrc = ldpcEncoder.appendCrc(inBits,'24A')\n", "tbWithCrc.shape" ] }, { "cell_type": "code", "execution_count": 5, "id": "762447be", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CodeBlocks Shape (Including CRC): (2, 5280)\n", "liftingSize (Zc): 240\n", "setIndex (Zero-Based): 7\n", "numFillerBits: 244\n" ] } ], "source": [ "# Do the segmentation:\n", "# To compare with Matlab, we need to use -1 for filler bits\n", "codeBlocksCrc = ldpcEncoder.doSegmentation(tbWithCrc, fillerBit=-1)\n", "\n", "# Compare results with Matlab:\n", "codeBlocksCrcMatlab = scipy.io.loadmat(matlabFilesPath+'/cbsIn.mat')['cbsIn'].T\n", "assert np.abs(codeBlocksCrc-codeBlocksCrcMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\"\n", "\n", "print(\"CodeBlocks Shape (Including CRC):\", codeBlocksCrc.shape)\n", "print(\"liftingSize (Zc): \", ldpcEncoder.liftingSize)\n", "print(\"setIndex (Zero-Based): \", ldpcEncoder.setIndex)\n", "print(\"numFillerBits: \", ldpcEncoder.numFillerBits)\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "89a47c7b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Base Graph Shape: (46, 68)\n", "8x8 sub-matrix at the \"Double Diagonal\" section:\n", " 1 0 -1 -1 -1 -1 -1 -1\n", " 0 0 0 -1 -1 -1 -1 -1\n", " -1 -1 0 0 -1 -1 -1 -1\n", " 1 -1 -1 0 -1 -1 -1 -1\n", " -1 -1 -1 -1 0 -1 -1 -1\n", " 180 -1 -1 -1 -1 0 -1 -1\n", " -1 -1 -1 -1 -1 -1 0 -1\n", " -1 -1 -1 -1 -1 -1 -1 0\n" ] } ], "source": [ "print(\"Base Graph Shape:\", ldpcEncoder.baseGraph.shape)\n", "print(\"8x8 sub-matrix at the \\\"Double Diagonal\\\" section:\")\n", "for r in ldpcEncoder.baseGraph[0:8,22:30]: print(\" \" + \" \".join(\"%3d\"%x for x in r))" ] }, { "cell_type": "code", "execution_count": 7, "id": "81369392", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, True, True, False)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Check the valid LDPC codewords:\n", "# Set Filler bits to zero before encoding and do not puncture first 2 columns\n", "codeBlocksCrc = ldpcEncoder.setFillerBits(codeBlocksCrc, 0)\n", "testCodeWords = ldpcEncoder.encode(codeBlocksCrc, zeroFillerBits=True, puncture=False)\n", "\n", "(ldpcEncoder.isValidCodeword(testCodeWords[0]),\n", " ldpcEncoder.isValidCodeword(testCodeWords[1]),\n", " ldpcEncoder.isValidCodeword(np.zeros(68*ldpcEncoder.liftingSize)), # Always valid\n", " ldpcEncoder.isValidCodeword(np.ones(68*ldpcEncoder.liftingSize))) # Intentionally Invalid\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "ca7abd99", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "codeWords Shape: (2, 15840)\n" ] } ], "source": [ "# Normal usage (1st 2 columns punctured, zero filler bits)\n", "# Do segmentation\n", "codeBlocksCrc = ldpcEncoder.doSegmentation(tbWithCrc)\n", "# Encoding:\n", "codeWords = ldpcEncoder.encode(codeBlocksCrc)\n", "print(\"codeWords Shape:\", codeWords.shape)\n", "\n", "# Compare results with Matlab:\n", "codeWordsMatlab = scipy.io.loadmat(matlabFilesPath+'/enc.mat')['enc'].T\n", "assert np.abs(codeWords-codeWordsMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" \n", "\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "22f117e8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rate-Matched codeWords Shape: (22808,)\n" ] } ], "source": [ "rateMatchedCodeWords = ldpcEncoder.rateMatch(codeWords)\n", "print(\"Rate-Matched codeWords Shape:\", rateMatchedCodeWords.shape)\n", "\n", "# Compare results with Matlab:\n", "rateMatchedCodeWordsMatlab = scipy.io.loadmat(matlabFilesPath+'/chIn.mat')['chIn'].T\n", "assert np.abs(rateMatchedCodeWords-rateMatchedCodeWordsMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" \n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "53fb09a0", "metadata": {}, "outputs": [], "source": [ "# Do all of it with one call end to end\n", "rateMatchedCodeWords = ldpcEncoder.getRateMatchedCodeWords(inBits)\n", "\n", "# Compare results with Matlab:\n", "assert np.abs(rateMatchedCodeWords-rateMatchedCodeWordsMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" \n" ] }, { "cell_type": "code", "execution_count": 11, "id": "ad7c6371", "metadata": {}, "outputs": [], "source": [ "# Simple bipolar channel with no noise:\n", "channelOutput = 1 - 2.0*rateMatchedCodeWords" ] }, { "cell_type": "code", "execution_count": 12, "id": "622ee6fd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 15840)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create an LDPC decoder\n", "ldpcDecoder = LdpcDecoder(baseGraphNo=1, modulation='QPSK', rv=0, txLayers=1, nRef=0);\n", "\n", "# Recover rate\n", "rxCodedBlocks = ldpcDecoder.recoverRate(channelOutput, len(inBits))\n", "\n", "# Compare results with matlab:\n", "rxCodedBlocksMatlab = scipy.io.loadmat(matlabFilesPath+'/raterec.mat')['raterec'].T\n", "rxCodedBlocksMatlab[rxCodedBlocksMatlab==np.inf]=LdpcDecoder.LARGE_LLR # Replace inf with our LARGE_LLR\n", "assert np.abs(rxCodedBlocks-rxCodedBlocksMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" \n", "\n", "rxCodedBlocks.shape\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "04b77059", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 5280)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Decode the rate-recovered message\n", "rxCodeWords = ldpcDecoder.decode(rxCodedBlocks)\n", "rxCodeWords.shape" ] }, { "cell_type": "code", "execution_count": 14, "id": "1d9893d6", "metadata": {}, "outputs": [], "source": [ "# Compare results with matlab:\n", "rxCodeWordsMatlab = scipy.io.loadmat(matlabFilesPath+'/decBits.mat')['decBits'].T\n", "assert np.abs(rxCodeWords-rxCodeWordsMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" " ] }, { "cell_type": "code", "execution_count": 15, "id": "eebdd6c5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CRC Matched: [ True True]\n" ] }, { "data": { "text/plain": [ "(10024,)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Undo Segmentation and CRC checking\n", "rxDecodedWordsWithoutCrc, crcMatch = ldpcDecoder.checkCrcAndMerge(rxCodeWords)\n", "print(\"CRC Matched:\", crcMatch)\n", "\n", "# Compare results with matlab:\n", "rxDecodedWordsWithoutCrcMatlab = scipy.io.loadmat(matlabFilesPath+'/decBlk.mat')['decBlk'].T\n", "assert np.abs(rxDecodedWordsWithoutCrc-rxDecodedWordsWithoutCrcMatlab).sum()==0, \"MISMATCH WITH MATLAB!!!\" \n", "rxDecodedWordsWithoutCrc.shape" ] }, { "cell_type": "code", "execution_count": 16, "id": "9dad40f6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "# The transport block CRC checking\n", "print(ldpcDecoder.checkCrc(rxDecodedWordsWithoutCrc,'24A'))" ] }, { "cell_type": "code", "execution_count": 17, "id": "9334c2c1", "metadata": {}, "outputs": [], "source": [ "# Compare with original input\n", "assert np.abs(rxDecodedWordsWithoutCrc[:-24]-inBits).sum()==0, \"MISMATCH WITH MATLAB!!!\"" ] }, { "cell_type": "code", "execution_count": null, "id": "8268b5a2", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "8f2a34b1", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" } }, "nbformat": 4, "nbformat_minor": 5 }