From 75e542c6ad66284016badeb11860839ffec9f5cc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 Jan 2023 18:02:45 +0100 Subject: [PATCH] Restore LDPC decdoer documentation --- .../CODING/nrLDPC_decoder/doc/nrLDPC/logo.png | Bin 0 -> 3723 bytes .../nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex | 960 ++++++++++++++++++ 2 files changed, 960 insertions(+) create mode 100644 openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/logo.png create mode 100644 openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex diff --git a/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/logo.png b/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7b785ca0517c0aa7467aafebff9255b2bdf0b8ef GIT binary patch literal 3723 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, $K-B=140$ filler bits are appended to the information bits. The PCM $\Hbgt$ is of size $2688\times 3328$ and the $640$ bits $\b$ are encoded according to \eqref{eq:29} at a rate $R \approx 0.192$. To achieve the higher base rate of $0.2$, the first $128$ are punctured, i.e. instead of transmitting all $3328$ bits, only $3200$ are transmitted resulting in the desired rate $R=640/3200=0.2$. + +\subsection{LDPC Decoding} +\label{sec:ldpc-decoding} + +The decoding of codeword $\c$ can be achieved via the classical message passing algorithm. This algorithm can be illustrated best using the Tanner graph of the PCM. The rows of the PCM are called check nodes (CN) since they represent the parity check equations. The parity check equation of each of these check nodes involves various bits in the codeword. Similarly, every column of the PCM corresponds to a bit and each bit is involved in several parity check equations. In the Tanner graph representation, the bits are called bit nodes (BN). Let's go back to the previous example of BG2 and assume $\Zc=2$, hence the first 3 rows and 13 columns of BG2 $\Hbgt$ read +\begin{equation*} + \label{eq:36} + \Hbgt = + \begin{bmatrix} + 1 & 1 & 0 & 0 & \emptyset & \emptyset & 1 & \emptyset & \emptyset & 1 & 0 & 0 & \emptyset & \emptyset \\ + 1 & \emptyset & \emptyset & 0 & 1 & 1 & 0 & 0 & 0 & 0 & \emptyset & 0 & 0 & \emptyset \\ + 1 & 0 & \emptyset & 0 & 0 & \emptyset & \emptyset & \emptyset & 0 & \emptyset & 1 & \emptyset & 0 & 0 + \end{bmatrix}. +\end{equation*} +Replacing the elements according to \eqref{eq:35}, we obtain the first 6 rows and 26 columns of the PCM as +\begin{equation*} + \label{eq:39} + \H = + \begin{bmatrix} + 0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\ + 1 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0\\ + 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0\\ + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0\\ + 0 & 1 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0\\ + 1 & 0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 1 + \end{bmatrix}. +\end{equation*} + +The Tanner graph of the first 8 BNs is shown in Figure \ref{fig:tannergraph}. + +\begin{figure}[ht] + \label{fig:tannergraph} + \centering + \def\ww{0.3cm} + \def\hh{0.3cm} + \tikzstyle{cnode}=[fill=white,rectangle,draw=black,thick,inner sep=2pt, minimum height=\hh,minimum width=\ww, rounded corners=1pt,text width=\ww] + \tikzstyle{vnode}=[fill=white,circle,draw=black,thick,inner sep=2pt, minimum height=\hh,minimum width=\ww, rounded corners=1pt,text width=\ww] + \tikzstyle{connector}=[<->,>=latex',semithick] + + \begin{tikzpicture} + \tikzstyle{every node}=[node distance=1.5cm,text centered] + % Check nodes + \node[cnode, label=above:$v_0$] (v0) {}; + \node[cnode, label=above:$v_1$, right of=v0] (v1) {}; + \node[cnode, label=above:$v_2$, right of=v1] (v2) {}; + % Variable nodes + \node[vnode, label=below:$c_3$, below of=v1, node distance=1.5cm] (c3) {}; + \node[vnode, label=below:$c_2$, left of=c3, node distance=1.5cm] (c2) {}; + \node[vnode, label=below:$c_1$, left of=c2, node distance=1.5cm] (c1) {}; + \node[vnode, label=below:$c_0$, left of=c1, node distance=1.5cm] (c0) {}; + \node[vnode, label=below:$c_4$, right of=c3, node distance=1.5cm] (c4) {}; + \node[vnode, label=below:$c_5$, right of=c4, node distance=1.5cm] (c5) {}; + \node[vnode, label=below:$c_6$, right of=c5, node distance=1.5cm] (c6) {}; + + % Draw edges + \draw (c0) edge[connector] (v1); + \draw (c1) edge[connector] (v0); + \draw (c1) edge[connector] (v2); + \draw (c2) edge[connector] (v1); + \draw (c3) edge[connector] (v0); + \draw (c4) edge[connector] (v0); + \draw (c4) edge[connector] (v2); + \draw (c5) edge[connector] (v1); + \draw (c6) edge[connector] (v0); + \draw (c6) edge[connector] (v2); + + \end{tikzpicture} + + \caption{Tanner graph for first 7 bits nodes and 3 check nodes from \eqref{eq:39}.} +\end{figure} + +The message passing algorithm is an iterative algorithm where probabilities of the bits (being either 0 or 1) are exchanged between the BNs and CNs. After sufficient iterations, the probabilities will have either converged to either 0 or 1 and the parity check equations will be satisfied, at this point, the codeword has been decoded correctly. + +\newpage +\section{LDPC Decoder Implementation} +\label{sec:ldpc-implementation} + +The implementation on a general purpose processor (GPP) has to take advantage of potential instruction extension of the processor architecture. We focus on the Intel x86 instruction set architecture (ISA) and its advanced vector extension (AVX). In particular, we utilize AVX2 with its 256-bit single instruction multiple data (SIMD) format. In order to utilize AVX2 to speed up the processing at the CNs and BNs, the corresponding data has to be ordered/aligned in a specific way. The processing flow of the LDPC decoder is depicted in \ref{fig:ldpc_decoder_flow}. + +\begin{figure}[ht] + \label{fig:ldpc_decoder_flow} + \centering + \def\ww{0.3cm} + \def\hh{0.3cm} + \tikzstyle{func}=[,draw=none] + \tikzstyle{connector}=[->,>=latex',semithick] + + \begin{tikzpicture} + \tikzstyle{every node}=[node distance=2.5cm,text centered] + % Check nodes + % First iteration + \node[func] (llr2llrProcBuf) {\texttt{llr2llrProcBuf}}; + \node[func, above of=llr2llrProcBuf] (llr2CnProcBuf) {\texttt{llr2CnProcBuf}}; + \node[func, above right of=llr2CnProcBuf] (cnProc1) {\texttt{cnProc}}; + \node[func, below right of=cnProc1] (cn2bnProcBuf1) {\texttt{cn2bnProcBuf}}; + \node[func, below of=cn2bnProcBuf1] (bnProcPc1) {\texttt{bnProcPc}}; + + % Iterations + \node[func, right of=cnProc1, node distance=7cm] (cnProc) {\texttt{cnProc}}; + \node[func, below right of=cnProc] (cn2bnProcBuf) {\texttt{cn2bnProcBuf}}; + \node[func, below of=cn2bnProcBuf] (bnProcPc) {\texttt{bnProcPc}}; + \node[func, below left of=cnProc] (bn2cnProcBuf) {\texttt{bn2cnProcBuf}}; + \node[func, below of=bn2cnProcBuf] (bnProc) {\texttt{bnProc}}; + + % Post processing + \node[func, below of=bnProcPc] (llrRes2llrOut) {\texttt{llrRes2llrOut}}; + \node[func, below of=llrRes2llrOut, node distance=1cm] (llr2bit) {\texttt{llr2bit}}; + + % Draw edges + \draw (llr2llrProcBuf) edge[connector] (llr2CnProcBuf); + \draw (llr2CnProcBuf) edge[connector] (cnProc1); + \draw (cnProc1) edge[connector] (cn2bnProcBuf1); + \draw (cn2bnProcBuf1) edge[connector] (bnProcPc1); + + \draw (bnProcPc) edge[connector] (bnProc); + \draw (bnProc) edge[connector] (bn2cnProcBuf); + \draw (bn2cnProcBuf) edge[connector] node[above left] {\texttt{cnProcPc}} (cnProc); + \draw (cnProc) edge[connector] (cn2bnProcBuf); + \draw (cn2bnProcBuf) edge[connector] (bnProcPc); + + \draw (bnProcPc1) edge[connector] (bnProc); + + \draw (bnProcPc) edge[connector] node[left] {iterations done} (llrRes2llrOut); + \draw (llrRes2llrOut) edge[connector] (llr2bit); + + % Boxes + \node[inner sep=0pt,above right of=cn2bnProcBuf1, node distance = 2.5cm] (ref) {}; + + \draw[fill=black,opacity=.2, rounded corners] (llr2llrProcBuf.south west) rectangle ($(ref) + (-.5cm,.5cm)$); + \draw[fill=black,opacity=.2, rounded corners] ($(ref) + (.5cm,.5cm)$) rectangle ($(bnProcPc.south east) + (.4cm,0)$); + + \node[func, above of=cnProc1, node distance=.8cm] (iter1) {\textbf{First Iteration}}; + \node[func, above of=cnProc , node distance=.8cm] (iterX) {\textbf{Subsequent Iterations}}; + + \end{tikzpicture} + + \caption{LDPC Decoder processing flow.} +\end{figure} + +The functions involved are described in more detail in Table \ref{tab:sum_func}. + +\begin{table}[ht] + \centering + \begin{tabular}{ll} + \toprule + \textbf{Function} & \textbf{Description} \\ + \midrule + \texttt{llr2llrProcBuf} & Copies input LLRs to LLR processing buffer \\ + \texttt{llr2CnProcBuf} & Copies input LLRs to CN processing buffer \\ + \texttt{cnProc} & Performs CN signal processing \\ + \texttt{cnProcPc} & Performs parity check \\ + \texttt{cn2bnProcBuf} & Copies the CN results to the BN processing buffer \\ + \texttt{bnProcPc} & Performs BN processing for parity check and/or hard-decision \\ + \texttt{bnProc} & Utilizes the results of \texttt{bnProcPc} to compute LLRs for CN processing \\ + \texttt{bn2cnProcBuf} & Copies the BN results to the CN processing buffer \\ + \texttt{llrRes2llrOut} & Copies the results of \texttt{bnProcPc} to output LLRs \\ + \texttt{llr2bit} & Performs hard-decision on the output LLRs \\ + \bottomrule + \end{tabular} + \caption{Summary of the LDPC decoder functions.} + \label{tab:sum_func} +\end{table} + +The input LLRs are assumed to be 8-bit and aligned on 32 bytes. CN processing is carried out in 8-bit whereas BN processing is done in 16 bit. Subsequently, the processing tasks at the CNs and BNs are explained in more detail. + +\newpage +\subsection{Check Node Processing} +\label{sec:check-node-proc} + +Denote $q_{ij}$ the value from BN $j$ to CN $i$ and let $\Bcal_i$ be the set of connected BNs to the $i$th CN. Then, using the min-sum approximation, CN $i$ has to carry out the following operation for each connected BN. +\begin{equation} + \label{eq:40} + r_{ji} = \prod_{j'\in\Bcal_i\setminus j}\sgn q_{ij'}\min_{j'\in\Bcal_i\setminus j} |q_{ij'}| +\end{equation} +where $r_{ji}$ is the value returned to BN $j$ from CN $i$. There are $\Mb = \{46,42\}$ CNs in BG 1 and BG 2, respectively. Each of these CNs is connected to only a small number of BNs. The number of connected BNs to CN $i$ is $|\Bcal_i|$. In BG1 and BG2, $|\Bcal_i|=\{3,4,5,6,7,8,9,10,19\}$ and $|\Bcal_i|=\{3,4,5,6,8,10\}$, respectively. The following tables show the number of CNs $M_{|\Bcal_i|}$ that are connected to the same number of BNs. + +\begin{table}[ht] + \centering + \begin{tabular}{llllllllll} + \toprule + $|\Bcal_i|$ & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 19 \\ + \midrule + $M_{|\Bcal_i|}^\mathrm{BG1}$ & 1 & 5 &18 & 8 & 5 & 2 & 2 & 1 & 4 \\ + $M_{|\Bcal_i|}^\mathrm{BG2}$ & 6 & 20 & 9 & 3 & 0 & 2 & 0 & 2 & 0 \\ + \bottomrule + \end{tabular} + \caption{Ceck node groups for BG1 and BG2.} + \label{tab:checkNodeGroups} +\end{table} + +It can be observed that each CN is at least connected to 3 BNs and there are 9 groups and 5 groups in BG1 and BG2, respectively. Denote the set of CN groups as $\Gcal$ and $M_k$ the number of CNs in group $k\in\Gcal$, e.g. for BG2 $M_4=20\Zc$. Each CN group will be processed separately. The CN processing buffer $p_C^k$ of group $k$ is defined as +\begin{equation} + \label{eq:44} + p_C^k = \{\underbrace{q_{11}q_{21}\dots q_{M_k 1}}_{\text 1. BN},\underbrace{q_{12}q_{22}\dots q_{M_k 2}}_{\text 2. BN},\dots,\underbrace{q_{12}q_{22}\dots q_{M_k k}}_{\text last BN}\} +\end{equation} +Hence, $|p_C^k| = kM_k$, e.g, $\Zc=128$, $|p_C^4| = 4\cdot 20\cdot 128 = 10240$. + +\begin{lstlisting}[frame=single,caption={Example of CN processing for group 3 from \texttt{cnProc}.},label=code_cnproc] % Start your code-block + + const uint8_t lut_idxCnProcG3[3][2] = {{72,144}, {0,144}, {0,72}}; + + // ===================================================================== + // Process group with 3 BNs + + // Number of groups of 32 CNs for parallel processing + M = (lut_numCnInCnGroups[0]*Z)>>5; + // Set the offset to each bit within a group in terms of 32 Byte + bitOffsetInGroup = (lut_numCnInCnGroups_BG2_R15[0]*NR_LDPC_ZMAX)>>5; + + // Set pointers to start of group 3 + p_cnProcBuf = (__m256i*) &cnProcBuf [lut_startAddrCnGroups[0]]; + p_cnProcBufRes = (__m256i*) &cnProcBufRes[lut_startAddrCnGroups[0]]; + + // Loop over every BN + for (j=0; j<3; j++) + { + // Set of results pointer to correct BN address + p_cnProcBufResBit = p_cnProcBufRes + (j*bitOffsetInGroup); + + // Loop over CNs + for (i=0; i>5; + + // Set the offset to each CN within a group in terms of 16 Byte + cnOffsetInGroup = (lut_numBnInBnGroups[2]*NR_LDPC_ZMAX)>>4; + + // Set pointers to start of group 3 + p_bnProcBuf = (__m128i*) &bnProcBuf [lut_startAddrBnGroups [idxBnGroup]]; + p_llrProcBuf = (__m128i*) &llrProcBuf [lut_startAddrBnGroupsLlr[idxBnGroup]]; + p_llrRes = (__m256i*) &llrRes [lut_startAddrBnGroupsLlr[idxBnGroup]]; + + // Loop over BNs + for (i=0,j=0; i