什么是CRC的更快替代方案?


27

我正在从dsPIC到PC进行一些数据传输,并且正在对512字节的每个块进行8位CRC校验,以确保没有错误。启用CRC代码后,我的速度约为33KB / s,没有它,则为67KB / s。

有什么替代的错误检测算法可以检查出更快的速度?


5
CRC本身如何实施?按位?然后切换到基于表的方法。按字节?考虑将表大小增加到例如16位所涉及的空间,复杂性和时间折衷(这将一次对两个字节进行操作,但将占用64KB的表存储空间)。
艾丹·库利(Aidan Cully)

我在RAM上只有16KB,在ROM上只有128KB,因此不能选择64KB的表。
FigBug

1
因此,您使用的是256字节表?或按位CRC?如果您按位进行操作,则按字节(使用256字节表)将快8倍。
艾丹·库利(Aidan Cully)

目前按位,我将尝试使用256表
FigBug

1
67kb / s至33kb / s?我不确定您的其他处理过程涉及什么,但是即使对于PIC来说,这听起来也相当大的开销。也许还有其他一些问题影响您的表现?
宫坂丽

Answers:


41

尽管可能有比CRC更快的选项,但是如果使用它们,则可能最终会牺牲一定程度的错误检测功能。根据您的错误检测要求,一种替代方法可能是使用针对您的应用程序优化的CRC代码。

有关CRC与其他选项的比较,请参阅Martin Thompson出色回答 。

pycrc是帮助解决此问题的一个选项,它是一种工具(用python 1编写),可以为crc模型算法的数十种组合生成C源代码。这样,您可以通过选择不同的组合并进行基准测试来优化自己的应用程序的速度和大小。1:需要Python 2.6或更高版本。

它支持的crc-8 模式,而且还支持crc-5crc-16并且crc-32在其他之中。至于算法,支持bit-by-bitbit-by-bit-fasttable-driven

例如(下载档案):

$ wget --quiet http://sourceforge.net/projects/pycrc/files/pycrc/pycrc-0.8/pycrc-0.8.tar.gz/download
$ tar -xf pycrc-0.8.tar.gz
$ cd pycrc-0.8
$ ./pycrc.py --model=crc-8 --algorithm=bit-by-bit      --generate c -o crc8-byb.c
$ ./pycrc.py --model=crc-8 --algorithm=bit-by-bit-fast --generate c -o crc8-bybf.c
$ ./pycrc.py --model=crc-8 --algorithm=table-driven    --generate c -o crc8-table.c
$ ./pycrc.py --model=crc-16 --algorithm=table-driven   --generate c -o crc16-table.c
$ wc *.c
   72   256  1790 crc8-byb.c
   54   190  1392 crc8-bybf.c
   66   433  2966 crc8-table.c
  101   515  4094 crc16-table.c
  293  1394 10242 total

您甚至可以做一些时髦的事情,例如使用双半字节查找(带有16字节查找表)进行指定,而不是使用256字节查找表进行单字节查找。

例如(克隆git存储库):

$ git clone http://github.com/tpircher/pycrc.git
$ cd pycrc
$ git branch
* master
$ git describe
v0.8-3-g7a041cd
$ ./pycrc.py --model=crc-8 --algorithm=table-driven --table-idx-width=4 --generate c -o crc8-table4.c
$ wc crc8-table4.c
  53  211 1562 crc8-table4.c

考虑到您的内存和速度限制,此选项很可能是速度和代码大小之间的最佳折衷方案。唯一可以确定的方法是对其进行基准测试。


pycrc Git仓库,在github上,这是它的问题跟踪,但它也可以从下载SourceForge上


我不相信大多数为PIC编写东西的人都在使用C,但是如果这样做的话,这可能会奏效。
Billy ONeal

4
@Billy-真的吗?我认为我没有遇到任何不使用C的商业化PIC开发人员。这些天,当然对汇编程序没有耐心,而且结构良好的C最终会变得紧凑。
Mark Booth,

我正在使用dsPIC,并且正在使用
C。– FigBug

@FigBug-谢谢,很高兴您喜欢我的回答。如果您运行一些基准测试,请随时用您的结果编辑我的答案。我很想知道每种算法对您的应用程序吞吐量和内存占用量有何不同。
Mark Booth,

1
这里是pyCrc的另一票。在具有不同约束的各种项目中使用它,效果很好。
Vicky

11

简单的一位奇偶校验(基本上是一遍又一遍地对数据进行异或运算)的速度就差不多。但是,您确实会丢失很多CRC的错误检查。

用伪代码:

char checksum = 0;
for each (char c in buffer)
{
    checksum ^= c;
    SendToPC(c);
}
SendToPc(checksum);

1
我前一段时间对此进行了调查。我相信求和而不是xor实际上会更好。(通常,将所有内容相加,然后将总和的2的补码作为校验和发送。在接收器上,将包括接收到的校验和在内的所有内容相加。如果一切正常,结果为0,否则返回非0。)
quick_now

1
@quickly:我认为这两者之间没有显着差异-两种方法都不能很好地保证事情没有被破坏。如果在目标体系结构上添加速度更快,请改用它。
比利·奥尼尔

7
我记得:ADD和XOR之间的主要区别是多位错误的可检测性较低。如果是字节流,则使用XOR消除相同位位置中的错误。当使用ADD时,通过校验和字节向上传播位意味着这种情况更容易检测到。(但是,根据当时的情况,通过字节流传播的不同位中的多个位错误很可能难以检测到)。像这样的任何校验和排列对于多位错误都是很麻烦的,因此它是一个相当小的参数。
quick_now

XOR比CRC有用得多。

3
@Thorbjørn:我相信我在回答中承认了这一点。:)
Billy ONeal

10

一篇非常好的论文,比较了嵌入式上下文中各种校验和和CRC的性能:

嵌入式网络校验和的有效性

结论中的一些引述(基于他们对未发现的错误概率的研究):

当突发错误占主导地位

XOR,二进制补码和CRC校验和提供的错误检测性能比二进制补码,Fletcher和Adler校验和更好。

在其他应用中

一个“好的” CRC多项式应尽可能用于错误检测

如果计算成本非常有限

(根据您的情况),使用(按有效性顺序):

其他语录:

Fletcher校验和比Adler校验和具有更低的计算成本,并且与流行的看法相反,在大多数情况下也更有效。

通常没有理由在新设计中继续使用XOR校验和的通用做法,因为它具有与基于加法的校验和相同的软件计算成本,但是在检测错误方面的效率只有大约一半。


1
另外,Fletcher校验和非常易于实现。
RubberDuck

6

阿德勒校验应足以用于检查传输的失真。它由Zlib压缩库使用,并由Java 3D移动图形标准采用,以提供快速但有效的数据完整性检查。

维基百科页面

通过计算两个16位校验和A和B并将它们的位连接为一个32位整数来获得Adler-32校验和。A是字符串中所有字节的总和加1,而B是每个步骤中A的各个值的总和。

在Adler-32运行的开始,A初始化为1,B初始化为0。总和取模65521(最大素数小于2 ^ 16或65536)。字节以网络顺序(大字节序)存储,B占据两个最高有效字节。

该函数可以表示为

 A = 1 + D1 + D2 + ... + Dn (mod 65521)
 B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
   = n×D1 + (n-1)×D2 + (n-2)×D3 + ... + Dn + n (mod 65521)

 Adler-32(D) = B × 65536 + A

其中D是要为其计算校验和的字节字符串,n是D的长度。


请注意,Adler32对于短期数据几乎没有用。最多约180个字节,会产生大量冲突。
greyfade11年

+1-CRC和简单位奇偶校验之间的合理中间立场。
Billy ONeal

@greyfade-FigBug提到使用512字节块,因此这对OP来说不是问题。值得庆幸的是,它对于有其他要求的人也很重要。
Mark Booth,

5

我不知道有什么方法可以像CRC一样更快地进行错误检测,如果有的话,人们会改用CRC。

您可以尝试一个简单的校验和,但是检测错误的可能性要小得多。


2
我愿意放弃提高速度的效率。
FigBug

3

校验和逻辑本身很好,人们可以提供更快的算法帮助。

如果要提高组件的速度,则可能需要考虑更改整体技术,以将传输组件与验证组件分开。

如果将它们作为两个独立的项目(在不同的线程上),则可以实现全速传输,并且仅重新发送失败的数据包。

算法看起来像:

  • 服务器分解为已知的数据包大小(例如1K块)。将它们放入“待发送”队列中。
  • 每个数据包都以16​​位或32位ID及其校验和发送。
  • 客户端接收每个数据包,并将其放入要处理的队列中。
  • 客户端在单独的线程上一次接收一个数据包,进行验证。
    • 成功后,将其添加到最终的数据包集合中(按ID顺序)
    • 失败时,它将失败的ID报告回服务器,服务器将要重新发送的数据包排队。
  • 一旦收到并验证了数据包,并且ID的顺序正确(从1开始),就可以开始将其写入磁盘(或执行所需的操作)。

这将使您以最快的速度进行传输,如果您使用数据包大小,则可以计算出最佳失败率与验证/重新发送率。


2

校验和是传统的

(减少#'+流)

上面给出的XOR也可以工作

(减少#'XOR流)

较为复杂(较慢)的方案是串行连接的标准奇偶校验。

在此级别上,您正在为速度而牺牲正确性。这些有时会失败。

在下一个最复杂的级别,您可以使用一些crc / hash类型的东西。

另一种设计是增加用于流的块的大小。

您应该估计实际错误率,以调整算法选择和块大小参数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.