1. 程式人生 > >縮短迴圈碼BCH(26,16)編解碼原理與二進位制演算法

縮短迴圈碼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;
}