缩短循环码BCH(26,16)编解码原理与二进制算法

1.BCH(26,16)的基本简介

BCH(26,16)是一种缩短循环校验码,它的数据位为16位,校验位是10位,码字的长度为26位。BCH(26,16)码取(31,21)循环码中的前5位信息位为0的码字作为码字,构成(21-5)维的线性子空间,它最多能够纠正t=2位错误(n-k\equiv mt,其中m是GF(p^m)中的m,这里的m=5,n=31,k=21)。对于铁路在800M频段上的数据业务,它采用的生成多项式为G(X)=X^10+X^8+X^7+X^5+X^4+X^3+1。

2.BCH(26,16)的编码原理

我们假设C(X)是需要发送的数字,C(X)=C_{15}X^{^{15}}+C_{14}X^{^{14}}+C_{13}X^{^{13}}+....+C_{1}X^{^{1}}+C_{0},在这里C15C14....C1C0你是我们需要发送的二进制数据。假设R(X)是校验位,R(X)=R_{9}X^{^{9}}+R_{8}X^{^{8}}+R_{7}X^{^{7}}+....+R_{1}X^{^{1}}+R_{0}。那么我们需要通过C(X)和生成多项式G(X)产生R(X),R(X)是C(X)X10除以G(X)的余数,这里的除法是模2除法。模2除法与算术除法类似,但每一位除的结果不影响其它位,即不向上一位借位,所以实际上就是异或。例如,发送的数据C(x)=1000,校验位数是3,其选择生成多项式为G(x)=x^3+x+1G(x)=x^3+x+1对应的二进制数为1011,C(X)X^3=1000<<3=1000 000B;1000 000B(被除数)对1011(除数)做模2除法,得到的余数R(X)便是101B。为了得到BCH(26,16)的校验位,一种很方便的模2除法的算法源代码如下。

	unsigned int CX = 0x5555,RX;//16位的数据位
	CX = CX<<10;//相当于C(X)X10
	unsigned int gx = 0x05B9<<(26-11);
	for(int i=0;i<16;i++){//迭代循环16次,进行16次除法操作,最后剩下10位的余数
		if((CX&0x2000000)!=0){//对CX的最高位是否为1,如果是1,做减法操作(异或)
			CX ^=gx ;//扩展gx到与CX同样是26位,为了方便除法运算
		}
		CX = CX<<1;
	}
	RX = CX>>16;
	printf("CX为校验位是 %2x",RX);

3. BCH(26,16)的解码原理

3.1用BCH的生成多项式校验数据是否正确,即使用接收到的26位码M(X)= C(X)X^10+R(X)除以生成多项式G(X)。如果余数为0,那么校验正确,否则校验错误,需要纠错。

        unsigned int code = 0;
        unsigned int gx = 0x05B9<<(26-11);
        code = 0x3fffccd;
	unsigned int res = 0;
	for(int i=0;i<16;i++){//求余数的算法中,只需要除以最高位的16位,余数一定是10位。
		if((code&0x2000000)!=0){
			code ^=gx;
		}
		code = code <<1;
	}
        Res = code>>(26-10);
        printf("余数 %2x\n",res);

3.2如果只错了1位或者2位。假设发送方发送的码为C(X)=C_{25}C_{24}C_{23}...C_{x}...C_{1}C_{0},由于只错了一位,那么假设错的这位是Cx,则接收到的码为R(X)=C_{25}C_{24}C_{23}...\bar{C_{x}}...C_{1}C_{0}。我们的问题是如何知道错误的位置x,以及所对应的Cx?上面的关系实际上表明R(X)=C(X)+E(X),其中E(X)=000..1....00。我们已经知道R(X),生成多项式G(X)和R(X)%G(X)的余数r(X),现在需要求出C(X)。r(X)=\frac{R(X)}{G(X)}=\frac{C(X)+E(X)}{G(X)}=\frac{E(X)}{G(X)},如果我们前期计算了一个表,这个表中表明唯一的一个E(X)对应唯一的一个r(X),唯一的r(x)不一定代表唯一的E(X),但是我们假设了只存在一个错误,那么通过查表我们就可以知道E(X)。当求解出E(X)后,C(X)=R(X)-E(X)=R(X)+E(X),这样R(X)和E(X)进行异或运算就可以得到C(X)。这种方式能够解决一位出错的情况,但是当2位出错的时候,可以改写表达式为r(X)=\frac{R(X)}{G(X)}=\frac{C(X)+E_{1}(X)+E_{2}(X)}{G(X)}=\frac{E_{1}(X)}{G(X)}+\frac{E_{2}(X)}{G(X)},因此只要检测到错误的这两位,然后把它修正了就可以了。具体的解码程序如下。

unsigned int CheckMatrix[26][2]; 
#define gx 0x05B9<<(26-11)
//create check metric
void CreateCheckMatrix(){
	unsigned int RX,CX;
	CX = 1<<15;
	for(int i=0;i<16;i++){
		if(i<16){
			RX = GetFEC(CX);
			CheckMatrix[i][0] = RX;
			CheckMatrix[i][1] = CX<<10;
		}
		CX = CX>>1;
	}
	CX = 1<<9;
	for(int i=0;i<10;i++){
		CheckMatrix[i+16][0] = CX;
		CheckMatrix[i+16][1] = CX;
		printf("%2x 为校验位是 %2x\n",CX,CX);
		CX = CX>>1;
	}
}
//correct data error
unsigned int CorrectError(unsigned int code,unsigned int *value){
	unsigned int encode = 0;
	unsigned int decode = 0;
	unsigned int res;
	decode  = code;
	printf("decode %2x\n",code);
	//2.1 calculate remainder
	for(int i=0;i<16;i++){//求余数的算法中,只需要除以最高位的16位,余数一定是10位。
		if((code&0x2000000)!=0){
			code ^=gx;
		}
		code = code <<1;
	}
	res  = code>>(26-10);
	printf("余数 %2x\n",res);
	if(res == 0){
		*value  = decode;
		return 0;
	}
	//2.2 correct one bit error
	for(int i=0;i<26;i++){
		if(res == CheckMatrix[i][0]){
			decode  = decode^CheckMatrix[i][1];
			*value  = decode;
			return 1;
		}
	}
	//2.3 correct two bit error
	for(int i=0;i<26;i++){
		for(int j=i+1;j<26;j++){
			if(res == (CheckMatrix[i][0]^CheckMatrix[j][0])){
				decode  = decode^CheckMatrix[i][1]^CheckMatrix[j][1];
				*value  = decode;
				return 2;
			}
		}
	}
	return 3;
}

3.3最后BCH(26,16)编码和解码源程序如下

#include <iostream>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
unsigned int CheckMatrix[26][2]; 

#define gx 0x05B9<<(26-11)
//get correct remainder 
unsigned int GetFEC(unsigned int CX){
	unsigned int RX;//16位的数据位
	unsigned int tmp;
	
	CX = CX<<10;
	tmp = CX;
	for(int i=0;i<16;i++){//迭代循环16次,进行16次除法操作,最后剩下10位的余数
		if((CX&0x2000000)!=0){//对CX的最高位是否为1,如果是1,做减法操作(异或)
			CX ^=gx ;//扩展gx到与CX同样是26位,为了方便除法运算
		}
		CX = CX<<1;
	}
	RX = CX>>16;
	
	printf("%2x 为校验位是 %2x\n",tmp,RX);
	return RX;
}
//create check metric
void CreateCheckMatrix(){
	unsigned int RX,CX;
	CX = 1<<15;
	for(int i=0;i<16;i++){
		if(i<16){
			RX = GetFEC(CX);
			CheckMatrix[i][0] = RX;
			CheckMatrix[i][1] = CX<<10;
		}
		CX = CX>>1;
	}
	CX = 1<<9;
	for(int i=0;i<10;i++){
		CheckMatrix[i+16][0] = CX;
		CheckMatrix[i+16][1] = CX;
		printf("%2x 为校验位是 %2x\n",CX,CX);
		CX = CX>>1;
	}
}
//correct data error
unsigned int CorrectError(unsigned int code,unsigned int *value){
	unsigned int encode = 0;
	unsigned int decode = 0;
	unsigned int res;
	decode  = code;
	printf("decode %2x\n",code);
	//2.1 calculate remainder
	for(int i=0;i<16;i++){//求余数的算法中,只需要除以最高位的16位,余数一定是10位。
		if((code&0x2000000)!=0){
			code ^=gx;
		}
		code = code <<1;
	}
	res  = code>>(26-10);
	printf("余数 %2x\n",res);
	if(res == 0){
		*value  = decode;
		return 0;
	}
	//2.2 correct one bit error
	for(int i=0;i<26;i++){
		if(res == CheckMatrix[i][0]){
			decode  = decode^CheckMatrix[i][1];
			*value  = decode;
			return 1;
		}
	}
	//2.3 correct two bit error
	for(int i=0;i<26;i++){
		for(int j=i+1;j<26;j++){
			if(res == (CheckMatrix[i][0]^CheckMatrix[j][0])){
				decode  = decode^CheckMatrix[i][1]^CheckMatrix[j][1];
				*value  = decode;
				return 2;
			}
		}
	}
	return 3;
}


int main(int argc, char** argv) {
	unsigned int code = 0,RX,CX;
	unsigned int encode = 0,decode;
	unsigned int res = 0;
	unsigned int pos1=0,pos2=0,pos3=0;
	//produce check metric
	CreateCheckMatrix();
	//encode
	res = 0xffff;
	encode = (res<<10)^GetFEC(res);
	printf("encode %2x\n",encode);
	//decode
//	pos1 = 0x8;
	pos2 = 0x2000000;
	pos3 = 0x800000;
	code = encode^pos1^pos2^pos3;
	res = CorrectError(code,&decode);
	printf("result %2x decode %2x\n",res,decode);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/u012750235/article/details/84622161