您的位置:首页 > 其它

LTE物理层之信道编码--CRC校验

2015-01-21 14:52 113 查看
CRC校验原理:

在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码也叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。 校验码的具体生成过程为:假设要发送的信息用多项式C(X)表示,将C(x)左移R位(可表示成C(x)*xR),这样C(x)的右边就会空出R位,这就是校验码的位置。用 C(x)*xR 除以生成多项式G(x)得到的余数就是校验码。

CRC生成步骤:

1、将X的最高次幂为R的生成多项式G(X)转换成对应的R+1位二进制数。

2、将信息码左移R位,相当于对应的信息多项式C(X)*2R。

3、用生成多项式(二进制数)对信息码做除,得到R位的余数(注意:这里的二进制做除法得到的余数其实是模2除法得到的余数,并不等于其对应十进制数做除法得到的余数。)。

4、将余数拼到信息码左移后空出的位置,得到完整的CRC码。

CRC生成例子:
假设使用的生成多项式是G(X)=X3+X+1。4位的原始报文为1010,求编码后的报文。

解:

1、将生成多项式G(X)=X3+X+1转换成对应的二进制除数1011。

2、此题生成多项式有4位(R+1)(注意:4位的生成多项式计算所得的校验码为3位,R为校验码位数),要把原始报文C(X)左移3(R)位变成1010 000

3、用生成多项式对应的二进制数对左移3位后的原始报文进行模2除(高位对齐),相当于按位异或:


以上只是讲述了几个CRC校验的几个重要的地方,详细的地方大家可以阅读相关书籍。

LTE中的生成多项式有CRC24A、CRC24B、CRC16、CRC8等几种,那么为什么选择这几种生成多项式呢?查阅到以下资料:

CRC在本质上是一种缩短循环码,由于编码的前k位是信息,因此属于系统码。CRC标准的应用一般遵循着某些规则,那就是如果没有实时的要求应该尽量使用生成多项式较长的,为了实现方便,应尽量选择计算机芯片支持的数据宽度,比如16位或32位,当然,对实时性处理要求非常严格的也可选用很短的生成多项式,比如蓝牙技术就采用4位,语音业务采用CRC-8。而对于同样的16位,CRC-CCITT在欧洲比较盛行,而在北美洲则是CRC-16。如果对实时性处理要求不高的情况下,应尽量选用较长的生成多项式,CRC-32或CRC-32C,因为这样更加安全可靠,注意它并没有要求待传输的数据比特数为八位字节的整数倍。所以,只关心数据传输、数据压缩的CD-ROM扇区和ARJ工具软件采用32位CRC检错码。

通过对差错检测能力和漏检错误率两个方面的仿真分析和总结,可以得出以下结论:

1) 生成多项式的比特数越大,其差错检测能力越强;漏检错误率越低。

2) 生成多项式比特数相同的情况下,差错检测能力相同;漏检错误率范围大致相同,但是对于不同的信道误码率,又有不同的漏检错误率。

通过对以上的结论的分析产生了一个思考:循环冗余校验码的性能取决于所选取的生成多项式,多项式的形式会对循环冗余校验码的性能产生各个方面不同的影响,但是对于通常所说的标准CRC码,几乎没有提供任何资料说明选择这些生成多项式的依据,也没有任何数据说明这些称之为标准的多项式就是性能最好,最优化的。

--以上是参考《CRC性能分析及生成多项式选取的研究》这篇文章,他后续还探讨了生成多项式的生成标准。

以上是对CRC原理的相关说明,但是真正实现CRC校验的方法却不是这样的。直接编程来实现上面的算法,不仅繁琐,效率也不高。实际上在工程中不会直接这样去计算和验证CRC。

标准CRC生成多项式如下表:

名称 生成多项式 简记式* 标准引用
CRC-4 x4+x+1 3 ITU G.704
CRC-8 x8+x5+x4+1 0x31
CRC-8 x8+x2+x1+1 0x07
CRC-8 x8+x6+x4+x3+x2+x1 0x5E
CRC-12 x12+x11+x3+x+1 80F
CRC-16 x16+x15+x2+1 8005 IBM SDLC
CRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
CRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS
CRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP //叶子:这里不知道问什么省略了,有些迷惑哦。要是生成多项式要是都省了,那还怎么校验?我猜想可能是中间的全为一吧。

生成多项式的最高位固定的1,故在简记式中忽略最高位1了,如0x1021实际是0x11021。
I、基本算法(人工笔算):
以CRC16-CCITT为例进行说明,CRC校验码为16位,生成多项式17位。假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];
数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。
发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];

II、计算机算法1(比特型算法):
1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;
2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;
否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);
3)重复第2步,直到数据流(6字节)全部移入寄存器;
4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。

III、计算机算法2(字节型算法):256^n表示256的n次方
把按字节排列的数据流表示成数学多项式,设数据流为BYTE
BYTE[n-1]BYTE[n-2]、、、BYTE[1]BYTE[0],表示成数学表达式为BYTE
×256^n+BYTE[n-1]×256^(n-1)

+...+BYTE[1]*256+BYTE[0],在这里+表示为异或运算。设生成多项式为G17(17bit),CRC码为CRC16。
则,CRC16=(BYTE
×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]×256+BYTE[0])×256^2/G17,即数据流左移16位,再除以生成多项式G17。
先变换BYTE[n-1]、BYTE[n-1]扩大后的形式,
CRC16=BYTE
×256^n×256^2/G17+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=(Z
+Y
/G17)×256^n+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z
×256^n+{Y
×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z
×256^n+{(YH8
×256+YHL
)×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z
×256^n+{YHL
×256/G17+(YH8
+BYTE[n-1])×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL
×256/G17+(YH8
+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y
的高8位(YH8
)与本字节BYTE[n-1]异或,

该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y
的低8位(YL8


乘以256(即左移8位)异或。然后依次逐个字节求出CRC,直到BYTE[0]。
字节型算法的一般描述为:本字节的CRC码,等于上一字节CRC码的低8位左移8位,与上一字节CRC右移8位同本字节异或后所得的CRC码异或。
字节型算法如下:
1)CRC寄存器组初始化为全"0"(0x0000)。(注意:CRC寄存器组初始化全为1时,最后CRC应取反。)
2)CRC寄存器组向左移8位,并保存到CRC寄存器组。
3)原CRC寄存器组高8位(右移8位)与数据字节进行异或运算,得出一个指向值表的索引。
4)索引所指的表值与CRC寄存器组做异或运算。
5)数据指针加1,如果数据没有全部处理完,则重复步骤2)。
6)得出CRC。

unsigned short GetCrc_16(unsigned char * pData, int nLength)
//函数功能:计算数据流* pData的16位CRC校验码,数据流长度为nLength
{
unsigned short cRc_16 = 0x0000; // 初始化

while(nLength>0)
{
cRc_16 = (cRc_16 << 8) ^ cRctable_16[((cRc_16>>8) ^ *pData) & 0xff]; //cRctable_16表由函数mK_cRctable生成
nLength--;
pData++;
}

return cRc_16;
}

void mK_cRctable(unsigned short gEnpoly)
//函数功能:生成0-255对应的16CRC校验码,其实就是计算机算法1(比特型算法)
//gEnpoly为生成多项式
//注意,低位先传送时,生成多项式应反转(低位与高位互换)。如CRC16-CCITT为0x1021,反转后为0x8408
{
unsigned short cRc_16=0;
unsigned short i,j,k;

for(i=0,k=0;i<256;i++,k++)
{
cRc_16 = i<<8;
for(j=8;j>0;j--)
{
if(cRc_16&0x8000) //反转时cRc_16&0x0001
cRc_16=(cRc_16<<=1)^gEnpoly; //反转时cRc_16=(cRc_16>>=1)^gEnpoly
else
cRc_16<<=1; //反转时cRc_16>>=1
}
cRctable_16[k] = cRc_16;
}
}

2:CRC码集选择的原则

若设码字长度为N,信息字段为K位,校验字段为R位(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得

V(x)=A(x)g(x)=xRm(x)+r(x);

其中: m(x)为K次信息多项式, r(x)为R-1次校验多项式,

g(x)称为生成多项式:

g(x)=g0+g1x+ g2x2+...+g(R-1)x(R-1)+gRxR

发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。

3、CRC校验码软件生成方法:

借助于多项式除法,其余数为校验字段。

例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1

假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001

x4m(x)=x10+x8+x7+x4 对应的代码记为:10110010000;

采用多项式除法: 得余数为: 1010 (即校验字段为:1010)

发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10

信息字段 校验字段

接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法), 如果能够除尽,则正确。

以上字节型算法(红字部分)解读:

比特型算法较易理解,这里不做解释.一般我们应用中更多的是用字节型的算法,而大部字节型算法为了提高效率是利用查表法实现的,对于查表法,表是如何产生的,有时迷惑,所以在此对字节型查表法推导过程的理解做一个备忘:

由等式一到等式二的推导:Z
和Y
分别为BYTE
/G17的商和余子式,所以可以进行转换;其它的BYTE暂不变;

由等式二到等式三的推导:由于只关心余子式,所以可以不理Z
,对Y
与后一字节进行进一步的结合处理,提取256^(n-1);

由等式三到等式四的推导:把Y
进一步分解成高低8位Y
×256/G17 = (YH8
×256+YL8
)×256/G17;

由等式四到等式五的推导:重新组合得{YHL
×256/G17+(YH8
+BYTE[n-1])×256^2/G17};

这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL
×256/G17+(YH8
+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y
的高8位(YH8
)与本字节BYTE[n-1]异或,该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y
的低8位(YL8
)乘以256(即左移8位)异或。然后依次逐个字节求出CRC,直到BYTE[0]。

表的生成则是对0~255每个数进行求CRC得到的!

字节型算法表的生成:

B(X)=Bn(X)*2^8n+Bn-1(X)*2^8(n-1)+....+B1(X)*2^8+B0(X)

CRC16时候,上式两端还要乘以2^16,即左移16位。把繁琐的计算过程省略,其实只要记住本字节的CRC码等于上一字节的余式的CRC码的低8位左移8位后,再加上上一字节CRC右移8位(也就是取高8位)和本字节之和(异或)所求的的CRC码。但是我们不可能这样每部就去计算,单片机是承受不了的,而且占据大量任务,给实时通信打折扣。所以一般我们会把8位二进制序列数从0~255的CRC全部计算出来,放在表里,扔到EEPROM或者FLASH中固存。

unsigned int crc_table[256]={

0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,

0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,

0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,

0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,

0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,

0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,

0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,

0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,

0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,

0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,

0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,

0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,

0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,

0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,

0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,

0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,

0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,

0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,

0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,

0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,

0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,

0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,

0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,

0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,

0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,

0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,

0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,

0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,

0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,

0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,

0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,

0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0

};

table[0]是0的CRC,table[1]是1的CRC 1021,table[2]是0010的CRC.(G(X)是11021)

例如:table[2] :0010(二进制)的CRC校验码是0X2042

0010 0000 0000 0000 0000
(左移16位)

^ 10 0010 0000 0100 001
(CRC16:X^16+X^12+X^5+1)

00 0010 0000 0100 0010=0X2042

CRC表的生成函数:

CRC表一般不要计算了,网络上都有,是通用的了。如果你要计算,可以按下面函数实现:

CRC表的生成函数

void init_crc_table(void)

{

int i, j;

long int k;

for (i = 0; i < 256; i++)

{

k = 0xC0C1;

for (j = 1; j < 256; j <<= 1)

{

if (i & j)

crc_table[i] ^= k;

k = (k << 1) ^ 0x4003;

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: