三类奇偶校验码及循环冗余码

本文中的py代码采用了numpy库 方便进行计算。
文章背景:学了通信原理的差错控制编码后,想要尝试以下利用py进行仿真
这也是我第一次使用py的numpy库 不合理的地方欢迎指出

1.普通奇偶校验

1.1 基础理论

是一种通过检查消息序列中1的奇偶数的校验方法

例如1011中,1的个数是奇数。如果我们进行的是偶校验 那么就要在结尾补上1,使数列变为 10111,如果是1001这种1的个数是偶数的,进行偶校验就是直接添0,变成10010。

发送方和接收方约定好奇校验还是偶校验,对应的编码解码就可以了。

缺点在于 无法检测偶数个错误,因为偶数个错误会让取余都不满足

本质原因是因为校验位只有一位,消息序列也只有一个维度(后面会解释为什么要用一个维度这个词),下两个奇偶校验方法会通过增加维度来解决。

1.2 代码实现

编码端

# 生成基础奇偶校验码
def base_parity_code(is_sigular,size):
    row_code =  np.random.randint(0,2,size-1)
    result = np.sum(row_code)
    if result%2 == is_sigular: #传0就为偶校验,因为偶数对2取余为0 矩阵添0
        row_code = np.append(row_code,[0])
    else:
        row_code = np.append(row_code,[1])
    return row_code
row_code = base_parity_code(0,8) #随机生成八位的信息序列 含一位校验
print(row_code) #[0 1 0 0 0 0 1 0]

解码端

#接收端校验
def base_parity_check(r_code,is_sigular):
    result = np.sum(row_code)
    if result%2 == is_sigular:#奇数
        print('校验成功')
    else:
        print('校验失败')

模仿传输中出现的错误直接改变消息序列的位就行了。

2.纵向奇偶校验

2.1 基础理论

看了前面最普通的奇偶校验的缺点,该如何在基于奇偶基础上进行改进呢?这里用到了线性代数的思想。

普通奇偶校验因为只对有一行进行校验,那么显然校验码所能做到的就只有 监视该行的奇数个错误了,试想以下,如果我们增加校验位,校验多个行(或者多个列)不就可以校验出部分的偶数个错误了?

举个例子

[1,0,0,1,0]  就只能校验奇数个错误比如如果前两个码元错误 变成了[0,1,0,1,0]是监视不出来的
那如果我们将其变为这种形式
a = [1,0,0,1,1,1] 那么a[1]和a[0]由a[4]监视,a[2]和a[3]由a[5]监视。
此时我们相当于多了一个监视行()数 我们写成矩阵的形式较为方便理解
a = [[1,0],   #前面的a[0]a[1]
	 [0,1]	  #前面的a[2]a[3]
	 [1,1]]   #前面的a[4]a[5]
这里我是以列的形式构造,每列的最后一个就是监督位。
此时如果 又发生了偶数个,例如a[1]a[0]的错误,那么很容易就可以发现了
很明显每列不再是偶数个1了,这样就不是之前那种只能检测奇数个错误的情况了
当然,如果偶数个错误发生在同个列上,还是无法检错
a = [[0,1],   #假设这第一行横起来的两位错误就可以检错
	 [0,1]	  #如果是竖起来的两位错了就不行了
	 [1,1]]  

2.2 代码实现

is_signal = 0
err_flag = 0

#编码
raw_code = np.random.randint(0,2,[4,8]) #随机生成4行8列的矩阵 传输32位码元
print('生成序列\n',raw_code)
temp_arr = np.zeros(raw_code.shape[1],dtype=np.int32)#生成一个监督码组,长度为码元矩阵的列数
for i in range(raw_code.shape[1]):#对每列进行奇偶校验编码,并将码值放在数组里
    result = np.sum(raw_code[:,i])
    if result%2 == is_signal:
        temp_arr[i] = 0;
    else:
        temp_arr[i] = 1;
raw_code = np.r_[raw_code,[temp_arr]]#将监督码组追加到最后一行中
print('编码后序列\n',raw_code)
#生成序列
# [[1 0 0 1 0 1 0 0]
# [0 0 1 0 1 0 0 0]
# [1 1 0 0 0 0 1 0]]
#编码后序列
# [[1 0 0 1 0 1 0 0]
# [0 0 1 0 1 0 0 0]
# [1 1 0 0 0 0 1 0]
# [0 1 1 1 1 1 1 0]]
#解码
err_flag = 0
for i in range(raw_code.shape[1]): #对每一列 进行奇偶校验
    result = np.sum(raw_code[:,i])
    if result%2 != is_signal:
        err_flag = 1
if err_flag:
    print('检测到错误')
    print('错误序列为')
    print(raw_code)
else:
    print('检测不到错误')

3.水平奇偶校验

3.1 基础理论

利用上述的编码其实已经能实现效果不错的检错了,但是这种编码,很多多位的,偶数个的错误也能被成功检测出来,但是有一类错误还是无法被检查出来, 那就是只有每一列的错误都是刚好偶数个时无法检错了因为本质上 可以理解为,我们只是做了个多列的奇偶校验

解决思路很简单, 将行也加入我们的监督码组中,对每一列,每一行 都进行奇偶校验 将监视的维度升维(线性代数的思想真的牛啊)

从只对一列的单点进行检测
改为对多列连成的线进行检测
最后变为多行多列形成的面进行检测

3.2 代码实现

is_signal = 0
err_flag = 0

#编码
raw_code = np.random.randint(0,2,[4,8])
print('生成序列\n',raw_code)
temp_arr = np.zeros(raw_code.shape[1],dtype=np.int32)
for i in range(raw_code.shape[1]): #生成每一列的监督码
    result = np.sum(raw_code[:,i])
    if result%2 == is_signal:
        temp_arr[i] = 0;
    else:
        temp_arr[i] = 1;
raw_code = np.r_[raw_code,[temp_arr]]
print('垂直编码后序列\n',raw_code)

temp_arr.resize(raw_code.shape[0]);#将矩阵大小重新指定
for i in range(raw_code.shape[0]): #生成每一行的监督码
    result = np.sum(raw_code[i,:])
    if result%2 == is_signal:
        temp_arr[i] = 0;
    else:
        temp_arr[i] = 1;
raw_code = np.c_[raw_code,temp_arr.T]#因为是行监督组 是竖起来的 所以放了矩阵的转置
print('水平编码后序列\n',raw_code)
#生成序列
# [[0 1 1 0 1 1 1 0]
# [1 0 1 1 1 0 0 0]
# [1 0 0 1 1 1 1 1]
# [1 1 0 0 0 0 1 0]]
#垂直编码后序列
# [[0 1 1 0 1 1 1 0]
# [1 0 1 1 1 0 0 0]
# [1 0 0 1 1 1 1 1]
# [1 1 0 0 0 0 1 0]
# [1 0 0 0 1 0 1 1]]
#水平编码后序列
# [[0 1 1 0 1 1 1 0 1]
# [1 0 1 1 1 0 0 0 0]
# [1 0 0 1 1 1 1 1 0]
# [1 1 0 0 0 0 1 0 1]
# [1 0 0 0 1 0 1 1 0]]
#解码
err_flag = 0
for i in range(raw_code.shape[1]):#对列进行校验
    result = np.sum(raw_code[:,i])
    if result%2 != is_signal:
        err_flag = 1

for i in range(raw_code.shape[0]):#对行进行校验
    result = np.sum(raw_code[i,:])
    if result%2 != is_signal:
        err_flag = 1

if err_flag:
    print('检测到错误')
else:
    print('检测不到错误')

这样的话,如果是之前那种竖起来的偶数个错误,也会被检测到了,因为竖起来的在列上看不出来,可是在行上确是错误的了.

但是还是有一种极端情况,那就是列中的偶数个错误的两个位置,在另外一个列的相同两个位置也错误了 那这个时候就相当于当该列上错误x个的时候,列监督位检查不出来,同时除了此列,还存在奇数个不同列但同行的位置也错了x个.就无法查错了 (x为偶数)

举例子这样子就无法检错了

raw_code[0,0] = not raw_code[0,0]
raw_code[1,0] = not raw_code[1,0]
raw_code[0,1] = not raw_code[0,1] 
raw_code[1,1] = not raw_code[1,1]

不得不说 突然发现线性代数的一些思想真的好奇特

4.循环冗余码

4.1 基础理论

这方面其实csdn有特别多的优秀教程了。

总的来说就是双方约定一个多项式 发送方利用自己和该多项式相除得到一个余数,把余数添加到自己的末尾。

接收方就是拿着这个信息再去和多项式相除,此时信息末尾已经添加上余数了。所以除法的结果如果为0,那么就是正确接收

4.2 代码实现

raw_code = np.random.randint(0,2,16)#产生16位随机序列
print('原始数据是       :',raw_code)
#多项式X8+X5+X4+X0 这是专家们研究的CRC8的 其他的也不是不行
gx = np.array([1,0,0,1,1,0,0,0,1]) #产生一个最高次方为len(gx)的矩阵 后面转化为多项式
print(np.poly1d(gx))
print('除数(生成多项式) :',gx)
raw_code = np.r_[raw_code,np.zeros(len(gx)-1)].astype(np.int32) #在原序列后添加len(gx) - 1个0
print('被除数           :',raw_code)
temp_result = (np.poly1d(raw_code)/np.poly1d(gx))[1]#将生成多项式和原序列进行多项式除法取余数
temp_result = np.mod(temp_result,2).astype(np.int32)#对余数进行模2得到校验位
print('校验位           :',temp_result)
for i in range (len(temp_result)):#用余数替换掉刚刚补0的位置
    index = len(raw_code) - len(temp_result)
    raw_code[index+i] = temp_result[i]
print('编码序列         :',raw_code)
#原始数据是        : [0 0 0 0 0 0 1 0 1 1 1 0 0 0 1 1]
#除数(生成多项式)   : [1 0 0 1 1 0 0 0 1]
#被除数            : [0 0 0 0 0 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0]
#校验位            : [1 0 0 1 0 1 1]
#编码序列          : [0 0 0 0 0 0 1 0 1 1 1 0 0 0 1 1 0 1 0 0 1 0 1 1]
#再次对多项式进行除法 此时余数为0就是校验成功否则校验失败
result = (np.poly1d(raw_code)/np.poly1d(gx))[1];  
result = np.mod(result,2).astype(np.int32)
print(result)
print(np.all(result==0))
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这里煤球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值