循环冗余校验码(CRC码)
循环冗余校验码的思想:
数据发送、接受方约定一个“除数”
K个信息位+R个校验位作为“被除数”,添加校验位后需保证除法的余数为0。收到数据后,进行除法检查余数是否为0,若余数非0说明出错,则进行重传或纠错。
例.设生成多项式为G(x)=
x
3
x^3
x3+
x
2
x^2
x2+1,信息码为101001,求对应CRC码。
1.确定K、R以及生成多项式对应的二进制码
K=信息码的长度=6,R=生成多项式最高次幂=3——>校验码位数N=K+R=9
生成多项式G(x)=1*
x
3
x^3
x3+1*
x
2
x^2
x2+0*
x
1
x^1
x1+1*
x
0
x^0
x0,对应二进制码1101
2.移位
信息码左移R位,低位补0。(101001000)
3.相除
对移位后的信息码,用生成多项式进行模2除法,产生余数
模2除法:
对应的CRC码:101001 001
4.检错和纠错
发送:101001001 记为
C
9
C_9
C9
C
8
C_8
C8
C
7
C_7
C7
C
6
C_6
C6
C
5
C_5
C5
C
4
C_4
C4
C
3
C_3
C3
C
2
C_2
C2
C
1
C_1
C1
接收:101001001 ———> 用110进行模2除——> 余数为000,代表没有出错。
K个信息位,R个校验位,若生成多项式选择得当,且 2 R 2^R 2R>=K+R+1,则CRC码课纠正1位错。(实际应用中一般只用来“检错”)
理论上可以正面循环冗余校验码的检错能力有以下特点:
1.可检测出所有奇数个错误;
2.可检测出所有双比特的错误;
3.可检测出所有小于等于校验位长度的连续错误
以下一个小例子:
/**
* 计算CRC16校验码
*
* @param bytes
* @return
* [1,3,4,1,205,1,18,235,173]
*/
public static String CRC16(byte[] bytes) {
int CRC = 0x0000ffff;
int POLYNOMIAL = 0x0000a001;
int i, j;
for (i = 0; i < bytes.length; i++) {
CRC ^= ((int) bytes[i] & 0x000000ff);
for (j = 0; j < 8; j++) {
if ((CRC & 0x00000001) != 0) {
CRC >>= 1;
CRC ^= POLYNOMIAL;
} else {
CRC >>= 1;
}
}
}
return Integer.toHexString(CRC);
}
public static void main(String[] args) {
byte[] s ={1,3,4,1,(byte) 205,1,18,(byte)235,(byte)173};
System.out.printf("1111%s\r\n",CRC16(s));
if (CRC16(s)!="00"){
System.out.printf("2222%s\n",CRC16(s));
}
}