/*---------------------------------------------------------------------------*
* IT++ *
*---------------------------------------------------------------------------*
* Copyright (c) 1995-2004 by Tony Ottosson, Thomas Eriksson, Pål Frenger, *
* Tobias Ringström, and Jonas Samuelsson. *
* *
* Permission to use, copy, modify, and distribute this software and its *
* documentation under the terms of the GNU General Public License is hereby *
* granted. No representations are made about the suitability of this *
* software for any purpose. It is provided "as is" without expressed or *
* implied warranty. See the GNU General Public License for more details. *
*---------------------------------------------------------------------------*/
/*!
\file
\brief Implementation of a Reed-Solomon codec class.
\author Pål Frenger
1.6
2004/01/30 11:29:24
*/
#include "base/binary.h"
#include "comm/reedsolomon.h"
namespace itpp {
//-------------------- Help Function ----------------------------
//! Local help function
GFX formal_derivate(const GFX &f) {
int degree = f.get_true_degree();
int q = f.get_size();
int i;
GFX fprim(q,degree);
fprim.clear();
for (i=0; i<=degree-1; i+=2) {
fprim[i] = f[i+1];
}
return fprim;
}
//-------------------- Reed-Solomon ----------------------------
//A Reed-Solomon code is a q^m-ary BCH code of length n = pow(q,m)-1.
//k = pow(q,m)-1-t. This class works for q==2.
Reed_Solomon::Reed_Solomon(int in_m, int in_t) {
m = in_m;
t = in_t;
n = round_i(pow(2,m)-1);
k = round_i(pow(2,m))-1-2*t;
q = round_i(pow(2,m));
int i;
GFX x(q,(char *)"-1 0");
ivec alphapow(1);
g.set(q,(char *)"0");
for(i=1; i<=2*t; i++) {
alphapow(0) = i;
g *= (x-GFX(q,alphapow));
}
}
bvec Reed_Solomon::encode(const bvec &uncodedbits) {
int i, j, itterations = (int)floor( (double)uncodedbits.length() / (k*m) );
GFX mx(q,k), cx(q,n);
GF mpow;
bvec out(itterations*n*m), mbit(k*m), cbit(m);
for (i=0; i<itterations; i++) {
//Fix the message polynom m(x).
for (j=0; j<k; j++) {
mpow.set(q,uncodedbits.mid((i*m*k)+(j*m),m));
mx[j] = mpow;
}
//Fix the outputbits cbit.
cx = g*mx;
for (j=0; j<n; j++) {
cbit = cx[j].get_vectorspace();
out.replace_mid((i*n*m)+(j*m),cbit);
}
}
return out;
}
bvec Reed_Solomon::decode(const bvec &codedbits) {
int j, i, kk, l, L, foundzeros, itterations = (int)floor( (double)codedbits.length() / (n*m) ), decoderfailure;
bvec out(itterations*k*m), mbit(m*k);
GFX rx(q,n-1), cx(q,n-1), mx(q,k-1), ex(q,n-1), S(q,2*t), Lambda(q), Lambdaprim(q), OldLambda(q), T(q), Ohmega(q);
GFX dummy(q), One(q,(char*)"0"), Ohmegatemp(q);
GF delta(q), tempsum(q), rtemp(q), temp(q), Xk(q), Xkinv(q);
ivec errorpos;
for (i=0; i<itterations; i++) {
decoderfailure = false;
//Fix the received polynomial r(x)
for (j=0; j<n; j++) { rtemp.set(q,codedbits.mid(i*n*m + j*m, m)); rx[j] = rtemp; }
//Fix the syndrome polynomial S(x).
S.clear();
for (j=1; j<=2*t; j++) { S[j] = rx(GF(q,j)); }
if (S.get_true_degree() == 0) {cx = rx; decoderfailure = false; }
else {//Errors in the received word
//Itterate to find Lambda(x).
kk = 0; Lambda = GFX(q,(char*)"0"); L = 0; T = GFX(q,(char*)"-1 0");
while (kk<2*t) {
kk = kk + 1;
tempsum = GF(q,-1);
for (l=1; l<=L; l++) { tempsum += Lambda[l] * S[kk-l]; }
delta = S[kk] - tempsum;
if (delta != GF(q,-1)) {
OldLambda = Lambda;
Lambda -= delta*T;
if (2*L<kk) { L = kk - L; T = OldLambda/delta;}
}
T = GFX(q,(char*)"-1 0") * T;
}
//Find the zeros to Lambda(x).
errorpos.set_size(Lambda.get_true_degree(), false);
errorpos.clear();
foundzeros = 0;
for (j=q-2; j>=0; j--) {
temp = Lambda( GF(q,j) );
if (Lambda( GF(q,j) ) == GF(q,-1) ) {
errorpos( foundzeros ) = (n-j) % n;
foundzeros +=1;
if (foundzeros >= Lambda.get_true_degree()) { break; }
}
}
if (foundzeros != Lambda.get_true_degree()) { decoderfailure = false; }
else {
//Compute Ohmega(x) using the key equation for RS-decoding
Ohmega.set_degree(2*t);
Ohmegatemp = Lambda * (One +S);
for (j=0; j<=2*t; j++) { Ohmega[j] = Ohmegatemp[j]; }
Lambdaprim = formal_derivate(Lambda);
//Find the error polynomial
ex.clear();
for (j=0; j<foundzeros; j++) {
Xk = GF(q,errorpos(j)); Xkinv = GF(q,0) / Xk;
ex[errorpos(j)] = (Xk * Ohmega(Xkinv)) / Lambdaprim(Xkinv);
}
//Reconstruct the corrected codeword.
cx = rx + ex;
//Code word validation
S.clear(); for (j=1; j<=2*t; j++) { S[j] = rx(GF(q,j)); }
if (S.get_true_degree() >= 1) { decoderfailure=false; }
}
}
//Find the message polynomial
mbit.clear();
if (decoderfailure == false) {
if (cx.get_true_degree() >= 1) {// A nonzero codeword was transmitted
mx = divgfx(cx,g);
for (j=0; j<=mx.get_true_degree(); j++) { mbit.replace_mid(j*m,mx[j].get_vectorspace()); }
}
}
out.replace_mid(i*m*k,mbit);
}
return out;
}
} //namespace itpp
syntax highlighted by Code2HTML, v. 0.9.1