1)关于编码的基础知识

在信息的传输过程中,为了达到更高效、更低误码的目的,不可避免地要在发送端进行编码,在接收端进行解码。

通常,编码可以分为信源编码和信道编码,具体的区分可以见下图:

信源编码是用于压缩数据用的;信道编码是用于增加检错、纠错信息,抵抗传输误码的。

例如:奇偶校验、和校验,就是两种最简单的信道编码,在接收端,如果发现校验位/校验字节不对,就可以知道传输中出现了误码,这就是信道编码的作用。

当然,复杂一些的信道编码不只能发现传输错误,还能在一定程度上纠正传输错误。

本文中要讲的,CRC校验码和汉明码,都属于信道编码,它们实现起来简单,效果却非常好。

常见的奇偶校验、和校验只能检出部分误码,能力有限,而CRC校验码可以检出多个bit位的传输错误,有文献表明,CRC16能100%检出:单个位误码、双位误码、奇数个误码、短于16bit的误码,能以99.99%以上的概率检出其他突发性误码。

汉明码与前面几种只能查错的编码不同,它甚至还可以纠正单个bit位的传输错误。

2)CRC校验码

首先来了解一下CRC校验码的原理。

假设我们有一串原始信息bit流要传输,从高位到低位依次为:序列1=11001100;

我们再选择一个用于生成CRC校验码的序列,假设为:序列2=100000111,总长度为k=9;我们暂时称其为“生成多项式”;

然后,我们在原始信息序列1后面增加(k-1)个0,然后将其和生成多项式序列2进行“模二除“(计算时不进位也不借位,二进制除法,相当于按位异或),计算过程如下:

最后得到一个k-1位长度的余数(位数不够的把前面的0也算上),这个余数就是计算得到的CRC校验。

把这个余数替换到原始信息序列1后面,得到新的序列:1100110001101010,这个新的序列就可以“整除”生成多项式序列2。

这样,我们只要在发送端计算出CRC校验,附加到原始信息的末尾一起发送,在接收端看能否整除,就能知道传输过程中有没有误码。

计算过程中的这个“被除数”——生成多项式,可以用多项式形式表示,也可以将序列换算成16进制表示。

计算时取的生成多项式不同,其CRC校验的结果也不同,因此,收发双方应该事先约定好生成多项式。

CRC校验的长度和生成多项式是可以自己定义的,但是一般来讲,为了通用化、标准化,一般选择8位、12位、16位或32位长度,越长它的检错能力会越强;生成多项式也有一些常用的标准形式,举几个例子如下:

标准

生成多项式

16进制表示

CRC8

x^8 + x^2 + x + 1

0x07

CRC12

x^12 + x^11 + x^3 + x^2 + x + 1

0x80F

CRC16

x^16 + x^15 + x^2 + 1

0x8005

CRC16-CCITT

x^16 + x^12 + x^5 + 1

0x1021

CRC32

x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1

0x04C11DB7

注意,因为生成多项式的最高次幂决定了CRC校验的长度,多项式的最高次幂必须为1(如CRC16,多项式X^16的系数必须为1),所以在用16进制或者2进制表示时,常常省略最高位固定的1。上表中的16进制就是省略最高位1的形式。

下面给出C语言求CRC校验的实现方法。

我们以计算CRC8为例,生成多项式为x^8 + x^2 + x + 1,那么它用十六进制数表示为0x107。在前面的手算示例中,我们可以发现,生成多项式的最高位是固定为1的,在循环做模二除时,每次计算的被除数的最高位也为1,所以计算完后余数的最高位必然为0,后续计算时是要丢弃的。根据这个特点,我们可以省略最高位的运算,每次只算除去最高位之外的那些位的模二除法。

实现代码如下:

这种实现方法便于理解,和手工计算的过程相似;它的缺点在于要按bit位循环计算,每个字节要循环8次,效率很低,计算一个长串时要花费很多cpu周期。

一个加快速度的方法是查表,以空间换时间,实现过程如下所示:

查表法每个字节只用计算一次,运算速度大大提高。

可以运行上面两个函数,查看结果是否和前述手工计算的crc8值一致。

3)汉明码

汉明码的原理,是将要发送的原始信息bit位分成几组,每组算出一个校验位,再将这些校验位附加在原始信息之后传输。接收方也按同样的方法分组、计算校验,如果发现某几个校验位不对,则可以根据分组的特性找出这几个组的交集,即确定误码的bit位,然后取反就可以纠正错误了。

我们以一个简单的例子来进一步理解一下汉明码(hamming code)的原理:

a)确定汉明码长度

假设我们有一串原始信息bit流要传输,长度为n,那么我们要先确定汉明码的长度(这个过程实际上等效于确定分组的组数)。

假定附加在原始信息之后的汉明码长度为m,那么编码的总长度为n+m。这n+m个bit位在传输过程中,每一位都有可能误码,为了能够纠正1bit的误码,我们需要区分n+m种错误状态和1种正确的状态,所以附加的m位编码,必须满足2^m ≥ (n+m+1)。

假定原始信息长度n=4,那么我们可以计算出m=3时,2^3 ≥ (4+3+1)满足要求。所以我们确定汉明码长度为3(即后面我们要把原始信息的bit位分为3组计算校验值)。

(注意,当编码长度满足上述≥取到=时,编码效率最高,此时才称为汉明码)。

b)bit位分组

接下来,我们考虑如何分组。

由于我们的目的是要使得能通过各组的交集来确定误码的bit位,那么分组方式可以如下表来确定:

C3

C2

C1

D1

0

0

1

D2

0

1

0

D3

0

1

1

D4

1

0

0

D5

1

0

1

D6

1

1

0

D7

1

1

1

表中D1~D7表示编码后的各个bit,从表中可以看出,我们只要把C1列为1的Dx划为第1组、C2列为1的Dx划为第2组,C3列为1的Dx划为第3组,这样只要某几组的校验值出错,就能通过他们的交集来确定是哪个bit位出错。

更直观的解释如下,我们采用异或来计算校验,有:

C1 = D1^D3^D5^D7

C2 = D2^D3^D6^D7

C3 = D4^D5^D6^D7

假如计算出来的校验值C3 C2 C1 = 001,则可以确定是D1位出错了,同样地,假如计算出C3 C2 C1 = 101,则可以确定是D5位出错了,其他值也一样可以推测出来。

如果计算出C3 C2 C1 = 000,则没有单bit的误码。

可以看到,如上方式的分组,可以有效地识别出单bit的误码。

c)编码计算方法

最后,我们要确定一种计算方法,使得在无误码时,计算出来的C3 C2 C1等于000。

我们观察发现,三个计算式中,D1、D2、D4都只出现了一次,所以,令C1等于0,可以求得:

D1 = D3^D5^D7

同理,令C2=0、C3=0可以求出:

D2 = D3^D6^D7

D4 = D5^D6^D7

这样,我们可以得到一个bit串:D7、D6、D5、D4、D3、D2、D1

其中D7、D6、D5、D3这几位,放原始的4bit信息,D4、D2、D1位由上式计算得到,附加在原始信息中,作为纠错码,也就是我们需要的汉明码。

实际编码实现时,D1~D7的排列顺序是可以换的,我们可以把原始信息放在前4bit,汉明码放在后3bit,只要接收方也知道这个顺序即可。

这样,我们就完成了4bit原始信息的汉明码编码。

d)如何解码

接收端收到信息后,按照同样的分组和计算方法来获取C3、C2、C1的值,可以知道哪个bit产生了误码,如有误码,将其翻转就完成了纠正。

为了便于编码,我们把上述例子中的D3和D4调换一下位置,即D7、D6、D5、D4是原始信息位,D3、D2、D1是汉明码。

下面是这个例子C语言实现。

注意,这个代码中由于D3和D4的位置互换了,所以解码函数中,返回3表示的是D4出错,返回4表示D3出错,其他位的指示是一一对应的。

上述实现过程可以看出,4bit信息至少要附加3bit的纠错码,效率不高;实际中,一般会选择较长的码来作为纠错码,比如:11bit信息附加4bit的纠错码,效率就要高一些。

好了,本节介绍了两种简单实用的信道编码方式,CRC校验可以检出多个bit的误码,效率较高;汉明码可以纠正单bit的误码,在误码率较低的场合能使通信更可靠。

欢迎大家关注我的公众号“小白白学电子”,可下载文中提到的电路、源码,更多学习资源分享:

介绍两种简单实用的信道编码——CRC校验和汉明码相关推荐

  1. win10录屏怎么用_怎么用Win10电脑系统进行录音教你两种简单实用的方法

    今天小编来教大家两种录音方法,一种是电脑自带的录音功能,一种是通过软件 一.电脑自带的录音功能 1.点击左下角WIN键 2.搜索 "录音机" 3.打开录制机,提示需要进行麦克风设置 ...

  2. 一种简单实用的全屏方法

    实现程序全屏幕显示的思路有很多种,最常见的一种就是: 1)利用Windows API提供的一个结构体WINDOWPLACEMENT来存储全屏显示前视图和主框架窗口在屏幕上的位置和显示信息.非客户区窗口 ...

  3. GIT将本地项目上传到Github(两种简单、方便的方法)

    GIT将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法: 首先你需要一个github账号,所有还没有的话先去注册吧! https://github.com/ 我们使用git需要先安 ...

  4. git学习(10):Git的使用--如何将本地项目上传到Github(两种简单、方便的方法)

    将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法: 首先你需要一个github账号,所有还没有的话先去注册吧! https://github.com/ 我们使用git需要先安装gi ...

  5. 上微信怎么同时用计算机,电脑端微信双开,教你两种简单的方法,上手即用!...

    原标题:电脑端微信双开,教你两种简单的方法,上手即用! 微信现在已不单单是社交软件了,如今已成了工作必备软件,每天上班微信电脑端一登,传个文件,发个群通知,实在方便. 但是很多人都不止有一个微信号,电 ...

  6. 电脑端微信双开,教你两种简单的方法,上手即用!

    电脑端微信双开,教你两种简单的方法,上手即用! https://kuaibao.qq.com/s/20181117A0GAZF00?refer=spider 微信现在已不单单是社交软件了,如今已成了工 ...

  7. Ajax提交Form表单的两种简单方式

    在现在的项目开发中,ajax的应用是必不可免的,最为基本的就是利用ajax的异步处理方式来向后台提交数据.关于ajax提交表单我利用到了两种简单的方式. 方法一## 先获取表单里面的数据,再通过aja ...

  8. 怎么给照片降噪?分享两种简单好用的图片降噪方法

    怎么给照片降噪呢?大家在使用数码摄影的时候,相机将光线作为接收信号接收并输出的过程中,会产生图片中粗糙的部分,这本是不该出现的外来像素,导致拍出来的照片或多或少会出现噪点,让图片看起来不美观.这时候我 ...

  9. 测量模型不确定性的两种简单方法

    在本文中,我们将介绍两种方法,它们允许你获得模型的不确定性:蒙特卡罗Dropout法(MC Dropout)和深度集成法. 它们适用于各种各样的任务,但在本文中,我们将展示一个图像分类的示例.它们都相 ...

  10. 简单轻松的将本地项目上传到Github的两种简单方法

    如何将本地项目上传到Github 将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法: 二.第二种方法: Git命令 查看.添加.提交.删除.找回,重置修改文件 查看文件diff 查 ...

最新文章

  1. android高级组件,Android高级组件ImageSwitcher图像切换器使用方法详解
  2. android h5 禁止缩放,vue h5移动端禁止缩放代码
  3. Zabbix监控交换机设置方法
  4. asp.net mvc 重定向
  5. 创业冲突的五种解决方法是_当创业合伙人发生冲突时,最好的解决办法看这5招...
  6. windows分区的理解
  7. YbtOJ#853-平面标记【整体二分,凸壳】
  8. CF940D Alena And The Heater
  9. 集成学习(西瓜书学习)
  10. bzoj 1803: Spoj1487 Query on a tree III(主席树)
  11. Redis进阶实践之十三 Redis的Redis-trib.rb脚本文件使用详解
  12. 只要学会它,再多 Bug 也不怕
  13. 面试百度、阿里、腾讯,这134道Java面试题你会多少?
  14. CCNA学习指南 TCP/IP
  15. c语言 学生成绩管理系统
  16. php mp4 ckplayer,织梦dedecms整合添加ckplayer播放器支持flv,mp4等播放功能
  17. c语言编程模拟银行取钱代码,C语言 用初等函数模拟银行取款
  18. IM系统架构设计之浅见
  19. DevExpress项目升级总结
  20. Excel,根据一列的子集进行筛选

热门文章

  1. Android获取应用程序信息——PackageManager的基本使用
  2. 7.1 布朗运动定义及构造
  3. linux电源管理配置,Arch Linux 如何修改默认电源管理设置
  4. Linux-4.4-x86_64 内核配置选项简介
  5. 中国首档程序员真人秀,20位选手找bug做模型,结果一开场主办方就惨遭攻击
  6. php swfupload,ThinkPHP+swfupload多图上传实例 经典实用的php多图上传
  7. 产业数字化转型升级案例:联合利华数字化供应链管理
  8. 永久禁止ctfmon.exe和conime.exe进程启动
  9. linux patch 给文件打补丁,Linux补丁工具patch生成使用补丁用法示例
  10. codesmith 连接mysql_CodeSmith连接Mysql方法步骤