Binary BCH (31,16,7) linear cyclic code work out

Building on my previous post on the simple Hamming linear cyclic code, I decide to push on for a little bit more usefull class of cyclic code, the BCH code. This will not be based on the same generator polynomial, \(h(x)=1+x+x^4\) using the powers of \(\beta\) as worked out in the last post since it is only a \(t=1\) FEC. While it is possible to achieve \(t > 1\), but it comes with the expense of information bits. For this workout problem I choose higher degree primitive polynomial.

One important class of cyclic codes is BCH codes. It is quite extensive and easy to decode and because of that it is quite practical for its use in real-life application. By definition, any \(r \ge 3, t \leq 2^{r-1}-1\) there exists BCH error-correcting codes of length \(n=2^r -1\), parity check length \((n-k) \le rt\), minimum distance \(d \ge 2t + 1\) and having dimension \(k \geq n-rt\). The \(t=1\) error-correcting BCH codes of length \(n=2^r-1\) is a Hamming code (old post).

I will use the primitive \(p(x)=x^5+x^2+1\) as a basis for the \((n,k,d) \equiv (31,16,7)\) BCH codes.

Some more field algebra

The minimal polynomial of \(\alpha\), \(m_{\alpha}(x)\) is the smallest polynomial in \(K[x]\) of smallest degree having \(\alpha\) as a root, that is, if \(f(x)=a_0+ a_1x+a_2x^2+..+a_kx^k\), that is \(f(\alpha)=a_0+a_1\alpha+a_2\alpha^2+..+a_k\alpha^k = 0\)

The order of nonzero element \(\alpha\) in \(GF(2^r)\) is the smallest positive \(m\) such that \(\alpha^m = 1\). If \(\alpha\) is of order \(2^r-1\) then it is a primitive element. It not easy to find the primitive polynomial of higher degree. Luckily the hard part of finding them has been done and tabulated for our use and this is what I will use for my implementation.

If \(\alpha\) has order \(m\), then \(\alpha\) is a root of \(1+x^m\). Relative to my previous post, defining \(\beta\) as primitive element, \(\alpha=\beta^i\), then \(\alpha^{2r-1}=(\beta^i)^{2r-1}= (\beta^{2r-1})^i = 1^i = 1\). \(\alpha\) is therefore a root of \(1+x^{2r-1}\) and \(m_\alpha(x)\) is a factor of \(1+x^{2r-1}\). In the last post \(g(x) | (1+x^{15})\). \(g(x)\) must be the least common multiple of \(m_i(x),m_2(x),..,m_{2t}(x)\). Taking the conjugate roots into account, the t-error-correcting BCH of code length \(n=2^r-1\) has its generator \(g(x)\) reduced to,

\begin{equation*} g(x) = LCM[m_1(x),m_3(x),\cdots,m_{2t-1}(x)] \end{equation*}

Since the degree of of each minimal polynomial is \(m\) or less, \(g(x)\) has degree at most \(mt = (n-k)\), its parity check digits. Base on the theorem that the set of all roots of \(m_\alpha(x)\) is \(\{\alpha,\alpha^2,\alpha^4,..,\alpha^{2t-1}\}\), the single error-correcting BCH codes will have the generator polynomial, \(g(x) = m_{\alpha^1}(x)\). The two error-correcting codes will have the generator polynomial, \(g(x) = m_\alpha(x)m_{\alpha^3}(x)\).

I can generate the elements of \(GF(2^5)\) based on \(p(x)=x^5+x^2+1\) as the primitive polynomial numerically using deconv of MATHLAB/Octave,

     >> n=31;
     >> I=eye(n);
     >> gx=[1 0 0 1 0 1];
     >> I=I(n:-1:1,:);
     >> for i=1:n [a,r(i,:)]=deconv(I(i,:),gx);end
     >> r=mod(r(:,27:31),2);

then tabulate the result,

word

\(x^i mod(x^5+x^2+1)\)

Power of \(\alpha\)

00000

00001

1

\(\alpha^0\)

00010

\(x\)

\(\alpha^1\)

00100

\(x^2\)

\(\alpha^2\)

01000

\(x^3\)

\(\alpha^3\)

10000

\(x^4\)

\(\alpha^4\)

00101

\(x^2+1\)

\(\alpha^5\)

01010

\(x^3+x\)

\(\alpha^6\)

10100

\(x^4+x^2\)

\(\alpha^7\)

01101

\(x^3+x^2+1\)

\(\alpha^8\)

11010

\(x^4+x^3+x\)

\(\alpha^9\)

10001

\(x^4+1\)

\(\alpha^{10}\)

00111

\(x^2+x+1\)

\(\alpha^{11}\)

01110

\(x^3+x^2+x\)

\(\alpha^{12}\)

11100

\(x^4+x^3+x^2\)

\(\alpha^{13}\)

11101

\(x^4+x^3+x^2+1\)

\(\alpha^{14}\)

11111

\(x^4+x^3+x^2+x+1\)

\(\alpha^{15}\)

11011

\(x^4+x^3+x+1\)

\(\alpha^{16}\)

10011

\(x^4+x+1\)

\(\alpha^{17}\)

00011

\(x+1\)

\(\alpha^{18}\)

00110

\(x^2+x\)

\(\alpha^{19}\)

01100

\(x^3+x^2\)

\(\alpha^{20}\)

11000

\(x^4+x^3\)

\(\alpha^{21}\)

10101

\(x^4+x^2+1\)

\(\alpha^{22}\)

01111

\(x^3+x^2+x+1\)

\(\alpha^{23}\)

11110

\(x^4+x^3+x^2+x\)

\(\alpha^{24}\)

11001

\(x^4+x^3+1\)

\(\alpha^{25}\)

10111

\(x^4+x^2+x+1\)

\(\alpha^{26}\)

01011

\(x^3+x+1\)

\(\alpha^{27}\)

10110

\(x^4+x^2+x\)

\(\alpha^{28}\)

01001

\(x^3+1\)

\(\alpha^{29}\)

10010

\(x^4+x\)

\(\alpha^{30}\)

Note that \(\alpha^{31}=1\).

b'\nn "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\n\n\n\nm1\n\npolynomial m1(x)\n\n\n0\ninput\n\n\n\nA\n\n\n+\n\n\n\n0->A\n\n\n\n\n\n1\noutput\n\n\n\na\n\nx\n\n\n\nb\n\nx2\n\n\n\na->b\n\n\n\n\n\nC\n\n\n+\n\n\n\nb->C\n\n\n\n\n\nc\n\nx3\n\n\n\nd\n\nx4\n\n\n\nc->d\n\n\n\n\n\ne\n\nx5\n\n\n\nd->e\n\n\n\n\n\nE\n\n\n\n\ne->E\n\n\n\n\n\nE->1\n\n\n\n\n\nE1\n\n\n\n\nE->E1\n\n\n\n\n\nA->a\n\n\n\n\n\nB\n\n\n\n\nB->A\n\n\n\n\n\nC->c\n\n\n\n\n\nD\n\n\n\n\nD->B\n\n\n\n\n\nD->C\n\n\n\n\n\nE1->D\n\n\n\n\n\n'

The elements obtained above can also be calculated by hand, for example, \(\alpha^{25}\) can be obtained by first, set \(p(\alpha) = \alpha^5+\alpha^2+1=0\) then solve for it using the table above,

\begin{align*} \alpha^5+\alpha^2+1 = 0 \\ \alpha^5 = \alpha^2+1 \\ \alpha^{25}=(\alpha^5)^5 = (\alpha^2+1)^5 = (\alpha^2+1)^2(\alpha^2+1)^2(\alpha^2+1) \\ \alpha^{25}=(\alpha^4+1)^2(\alpha^2+1) \\ =(\alpha^8+1)(\alpha^2+1) \\ =(\alpha^3\alpha^5+1)(\alpha^2+1) \\ =(\alpha^3(\alpha^2+1)+1)(\alpha^2+1) \\ =(\alpha^5+\alpha^3+1)(\alpha^2+1) \\ =\alpha^7+\alpha^3+(\alpha^2+1) \\ =\alpha^7+\alpha^5+\alpha^3 \\ = x^4+x^2+x^2+1+x^3 = x^4+x^3+1 \\ \end{align*}

The result agrees with what is obtained numerically by MATLAB/Octave. I think it is fine just to randomly verify the result for couple of elements after \(\alpha^5\).

Next is to get the generator polynomial by performing the calculation for minimal polynomials, \(m_1(x)=p(x), m_3(x)\) and \(m_5(x)\), that is the root based on \(\alpha, \alpha_3\) and \(\alpha^5\) because I need \(g(x)=m_1(x)m_3(x)m_5(x)\) for this exercise. I can avoid the tedious calculation by opting to use the tabulated generator polynomials of \((n,k,d)\) BCH code. For the \((31,16,7), t=3\), \(m_3(x)=x^5+x^4+x^3+x^2+1\), and \(m_5(x)=x^5+x^4+x^2+x+1\).

\begin{align*} g(x)=LCM[m_1(x)m_3(x)m_5(x)] \\ = LCM[(x^5+x^2+1)(x^5+x^4+x^3+x^2+1)(x^5+x^4+x^2+x+1)] \end{align*}

Using MATLAB/Octave's conv to multiply the polynomial,

\begin{equation*} g(x) = x^{15}+ x^{11}+x^{10}+x^9+ x^8+x^7+ x^5+x^3 + x^2+x+1 \end{equation*}

This matches to the tabulated octal table value, \((107657)_8 = 001 000 111 110 101 111\). I can verify that \(g(x) | (x^{31} + 1)\) using Octave's deconv operation. This is to confirm that any irreducible polynomial over GF(2) of degree \(m\) divides \(X^{2^m-1}+1\).

b'\nn "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\n\n\n\nm3\n\npolynomial m3(x)\n\n\n0\ninput\n\n\n\nA\n\n\n+\n\n\n\n0->A\n\n\n\n\n\n1\noutput\n\n\n\na\n\nx\n\n\n\nb\n\nx2\n\n\n\na->b\n\n\n\n\n\nC\n\n\n+\n\n\n\nb->C\n\n\n\n\n\nc\n\nx3\n\n\n\nG\n\n\n+\n\n\n\nc->G\n\n\n\n\n\nd\n\nx4\n\n\n\nF\n\n\n+\n\n\n\nd->F\n\n\n\n\n\ne\n\nx5\n\n\n\nE\n\n\n\n\ne->E\n\n\n\n\n\nE->1\n\n\n\n\n\nE1\n\n\n\n\nE->E1\n\n\n\n\n\nA->a\n\n\n\n\n\nB\n\n\n\n\nB->A\n\n\n\n\n\nC->c\n\n\n\n\n\nD\n\n\n\n\nD->B\n\n\n\n\n\nD->C\n\n\n\n\n\nI\n\n\n\n\nI->D\n\n\n\n\n\nI->G\n\n\n\n\n\nH\n\n\n\n\nH->I\n\n\n\n\n\nH->F\n\n\n\n\n\nE1->H\n\n\n\n\n\nG->d\n\n\n\n\n\nF->e\n\n\n\n\n\n'

b'\nn "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\n\n\n\nm5\n\npolynomial m5(x)\n\n\n0\ninput\n\n\n\nA\n\n\n+\n\n\n\n0->A\n\n\n\n\n\n1\noutput\n\n\n\na\n\nx\n\n\n\nC\n\n\n+\n\n\n\na->C\n\n\n\n\n\nb\n\nx2\n\n\n\nG\n\n\n+\n\n\n\nb->G\n\n\n\n\n\nc\n\nx3\n\n\n\nd\n\nx4\n\n\n\nc->d\n\n\n\n\n\nI\n\n\n+\n\n\n\nd->I\n\n\n\n\n\ne\n\nx5\n\n\n\nE\n\n\n\n\ne->E\n\n\n\n\n\nE->1\n\n\n\n\n\nE1\n\n\n\n\nE->E1\n\n\n\n\n\nA->a\n\n\n\n\n\nB\n\n\n\n\nB->A\n\n\n\n\n\nC->b\n\n\n\n\n\nD\n\n\n\n\nD->B\n\n\n\n\n\nD->C\n\n\n\n\n\nI->e\n\n\n\n\n\nH\n\n\n\n\nH->I\n\n\n\n\n\nF\n\n\n\n\nH->F\n\n\n\n\n\nE1->H\n\n\n\n\n\nG->c\n\n\n\n\n\nF->D\n\n\n\n\n\nF->G\n\n\n\n\n\n'

By definition, a t-error-correcting BCH code of lengt \(2^m-1\) having a binary n-tuple \(u(X)=u_0+u_1+\cdots+u_{n-1}\) is a code word iff \(u(X)\) has \(\alpha,\alpha^2, \cdots,\alpha^{2t}\) as roots, that is,

\begin{equation*} u(\alpha^i) = u_o + u_1(\alpha^i) + u_2(\alpha^{2i}) + \cdots + u_{n-1}(\alpha^{(n-1)i}) = 0 \end{equation*}

and for this exercise,

\begin{align*} u(\alpha) = u_o + u_1(\alpha) + u_2(\alpha^2) + \cdots + u_{n-1}(\alpha^{30}) = 0 \\ u(\alpha^3) = u_o + u_1(\alpha^3) + u_2(\alpha^{6}) + \cdots + u_{n-1}(\alpha^{90}) = 0 \\ u(\alpha^5) = u_o + u_1(\alpha^5) + u_2(\alpha^{10}) + \cdots + u_{n-1}(\alpha^{150}) = 0 \end{align*}

note that the power of \(\alpha\) will wrap on this finite field, for example, \(\alpha^{35} = \alpha^{31} \alpha^4 = \alpha^{4}\). Put it in matrix form,

\begin{equation*} (u_0 u_1 \cdots u_{n-1}) \left [ \begin{array}{cc} 1 & 1 & 1 \\ \alpha & \alpha^3 & \alpha^5 \\ \cdots & \cdots & \cdots \\ \alpha^{30} & (\alpha^3)^{30} & (\alpha^5)^{30} \end{array} \right] = 0 \end{equation*}

The equation above is in the form,

\begin{equation*} UH^t = 0 \end{equation*}

note \((\alpha^i)^0 = 1\). The transpose of the parity-check matric, \(H\) is a 31x15 matrix. It will follow that if \(U=(u_0,u_1,\cdots,u_{31})\) is a code word, then \(UH^t = 0\). \(\alpha^3 \equiv x^i mod(m_3(x))\) and so on.

Each column of power of \(\alpha\) is arranged below for \(H^t\) parity check matrix. It is not important as to whether to go for head first or bottom first as long as it stays consistent. The matrix below has the highest power of \(\alpha\) at its top row.

\begin{equation*} H^t= \left[ \begin{array}{cc} 1 0 0 1 0& 1 0 1 1 0 & 1 0 1 1 1 \\ 0 1 0 0 1& 1 1 0 0 1 & 1 1 0 0 0 \\ 1 0 1 1 0& 1 0 1 0 1 & 1 1 0 1 1 \\ 0 1 0 1 1& 0 0 1 1 0 & 0 0 1 1 1 \\ 1 0 1 1 1& 1 1 0 1 1 & 0 1 0 1 0 \\ 1 1 0 0 1& 1 1 1 0 0 & 0 0 0 1 0 \\ 1 1 1 1 0& 1 0 0 0 1 & 0 1 0 1 1 \\ 0 1 1 1 1& 1 0 1 0 0 & 1 0 1 0 1 \\ 1 0 1 0 1& 1 0 0 0 0 & 1 0 0 1 1 \\ 1 1 0 0 0& 0 0 0 1 0 & 0 1 1 1 0 \\ 0 1 1 0 0& 0 1 0 0 1 & 1 0 1 0 0 \\ 0 0 1 1 0& 1 0 1 1 1 & 0 0 1 0 0 \\ 0 0 0 1 1& 0 1 1 1 1 & 1 0 1 1 0 \\ 1 0 0 1 1& 0 1 1 0 0 & 0 1 1 1 1 \\ 1 1 0 1 1& 1 0 0 1 1 & 0 0 0 1 1 \\ 1 1 1 1 1& 1 1 1 0 1 & 1 1 1 0 0 \\ 1 1 1 0 1& 0 0 1 1 1 & 0 1 1 0 1 \\ 1 1 1 0 0& 0 1 1 0 1 & 0 1 0 0 0 \\ 0 1 1 1 0& 0 0 1 0 1 & 0 1 0 0 1 \\ 0 0 1 1 1& 0 0 1 0 0 & 1 1 1 1 0 \\ 1 0 0 0 1& 1 0 0 1 0 & 0 0 1 1 0 \\ 1 1 0 1 0& 0 1 0 1 1 & 1 1 1 0 1 \\ 0 1 1 0 1& 1 1 1 1 0 & 1 1 0 1 0 \\ 1 0 1 0 0& 1 1 0 0 0 & 1 0 0 0 0 \\ 0 1 0 1 0& 0 0 0 1 1 & 1 0 0 1 0 \\ 0 0 1 0 1& 1 1 1 1 1 & 1 1 0 0 1 \\ 1 0 0 0 0& 0 1 1 1 0 & 0 1 1 0 0 \\ 0 1 0 0 0& 1 1 0 1 0 & 1 1 1 1 1 \\ 0 0 1 0 0& 0 1 0 1 0 & 1 0 0 0 1 \\ 0 0 0 1 0& 0 1 0 0 0 & 0 0 1 0 1 \\ 0 0 0 0 1& 0 0 0 0 1 & 0 0 0 0 1 \end{array} \right] \end{equation*}

MATLAB/Octave is used to generate the power of \(\alpha\) above,

     % minimum polynomials
     m1=[1 0 0 1 0 1];
     m3=[1 1 1 1 0 1];
     m5=[1 1 0 1 1 1];
     % generator poly
     gx=mod(conv(conv(m1,m3),m5),2);
     % will produce gx=[1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1];
     for i=1:n
              j=mod(3*i,31);
              l=mod(5*i,31);
              if j==0
                     j=31;
              end
              if l == 0
                     l=31;
              end
              R3(i,:)=r1(j,:);
              R5(i,:)=r1(l,:);
     end

The parity check is not in systematic form.

Likewise the generator matrix can be obtained from the generator polynomial, \(g(x)\),

\begin{equation*} G = \left[ \begin{array}{cc} I_{k} & P_{k,n-k} \end{array} \right] =\left[ \begin{array}{c|c} 1000000000000000&100011111010111 \\ 0100000000000000&110010000111100 \\ 0010000000000000&011001000011110 \\ 0001000000000000&001100100001111 \\ 0000100000000000&100101101010000 \\ 0000010000000000&010010110101000 \\ 0000001000000000&001001011010100 \\ 0000000100000000&000100101101010 \\ 0000000010000000&000010010110101 \\ 0000000001000000&100010110001101 \\ 0000000000100000&110010100010001 \\ 0000000000010000&111010101011111 \\ 0000000000001000&111110101111000 \\ 0000000000000100&011111010111100 \\ 0000000000000010&001111101011110 \\ 0000000000000001&000111110101111 \end{array} \right ] \end{equation*}

since \(G \perp H\), \(GH^t = 0\). The parity check matrix obtained this way can be easily implemented in hardware using the shift registers for error detection.

for i=1:n [a,r(i,:)]= deconv(I(i,:),gx);end
r=r(:,17:31);r=mod(r,2);
p=r(1:16,:); %partity bits
% generator matrix
G=[eye(16) p];
mod(G*h,2) %  zeros

Decoder and errors locator

From the row of \(H\), there are \(2^{15}\) syndromes and \(1+\binom{n}{1} + \binom{n}{2} + \binom{n}{3} = 4992\) correctable error patterns for this implementation.

If \(\psi_i:i=1,3,5\) are the syndromes each having 5 bits and representing the columns of the transpose parity check matrix, \(H^t\),

\begin{equation*} H^t = \left[ \begin{array}{cc} 1 & 1 & 1 \\ \alpha & \alpha^3 & \alpha^5 \\ \cdots & \cdots & \cdots \\ \alpha^{30} & (\alpha^3)^{30} & (\alpha^5)^{30} \end{array} \right] \end{equation*}

and \(w\) is the received coded word, then \(wH^t=[w(\alpha), w(\alpha^3), w(\alpha^5)] = [\psi_1, \psi_3, \psi_5]\) is the syndrome of this code word. For a single bit error, \(e(x)=x^i\), the syndrome is \(wH^t=[(\alpha)^i,(\alpha^3)^i,(\alpha^5)^i]\). If there are two errors in the code word, \(e(x)=x^i+x^j, i\neq j\), the syndrome becomes \([\psi_1,\psi_3,\psi_5]=[(\alpha)^i+\alpha^j,(\alpha^3)^i+(\alpha^3)^j,(\alpha^5)^i+(\alpha^5)^j]\). Eventually it will lead to system of equations to be solved for a polynomial \(x(\psi_i)\). It is called the error-locator polynomial. This polynomial is dependent on error bit positions.

To test the error correction capability of this exercise,

v=dec2bin(0:2^16-1)-'0'; % input code word
u=mod(v*G,2); % BCH coded word

>> mod(u(1000,:)*h,2)

ans =

 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Suppose that a received coded word, \(w\) has one bit error, say bit 14,

w=u(1000,:); % a coded word
w(14)=0; %was 1, set to 0 to simulate error

>> mod(w*h,2)
ans =
   1 0 0 1 1 0 1 1 0 0 0 1 1 1 1

The output from \(wH^t\) produces the syndrome identical to row 14 of \(H^t\). The corrected code word is then \(w+I(14)\), where \(I(14)\) is the 14th row of the identity matrix. Now what happens if two bit errors, say another bit at bit 0,

w(1)=1; % was 0, set to 1 as error. Now we have bit0,14 as error bits
>> mod(w*h,2)
ans =
   0 0 0 0 1 1 1 0 1 0 1 1 0 0 0
>> mod(h(1,:)+h(14,:),2)
ans =
   0 0 0 0 1 1 1 0 1 0 1 1 0 0 0

Evidently the syndrome is the same as \(H^t(14)+H^t(1)\), sum of first and 14th row. The corrected bits are then \(I(14)+I(1)\), 1st and 14th row of \(I\) matrix. This can go on up to 3-bits error, but how do I know which bit or bits are in error ? The possibility is binomial sum as stated earlier because error can be any number of bits and at any positions. Locating the error positions is the hardest part of the implementation.

While there are several algorithms for error locating, they are not always efficient for hardware implementation. I tried out some algorithms on paper and pencil that work well, but I have no idea how to translate it into hardware. I will leave those to the experts. One possible algorithm that I like is this, let \(w(x)\) be the received code word where \(w(x)=u(x)+e(x)\). \(u(x)\) and \(e(x)\) are the transmitted code word and error respectively.

. Calculate syndrome \(s(x) = w(x) mod g(x)\)

. For \(i \ge 0\), calculate \(s_i(x)=x^i s(x) mod g(x)\) until \(s_j(x)\) is found where weight of \(s_j(x) \le t\).

. Once \(s_j(x)\) is located, \(e(x)=x^{n-j}s_j(x) mod (x^n + 1)\) are the most likely error bits.

Assume the transmitted code word \(u(12345)= 0011_0000_0011_1000_10001_10001 _00111\), which obtained from \(u=vG\) above. Representin in polynomial form,

\begin{equation*} u(x)=1+x+x^2+x^5+x^9+x^{10}+x^{14}+x^{18}+x^{19}+x^{20}+x^{27}+x^{28} \end{equation*}

having 3 bits error at bit 0, bit 29, bit 26, such that \(0111_1000_0011_1000_10001_10001 _00110\)

\begin{equation*} w(x)=x+x^2+x^5+x^9+x^{10}+x^{14}+x^{18}+x^{19}+x^{20}+x^{26}+x^{27}+x^{28}+x^{29} \end{equation*}

The compute syndrome is \(01011_11011_01101\)

\begin{equation*} s(x)= w(x) mod g(x) =1+x^2+x^3+x^5+x^6+x^8+x^9+x^{10}+x^{11}+x^{13} s_1(x) = xs(x) mod g(x) = \end{equation*}