Xilinx-Verilog-学习笔记(20):汉明码编解码与CRC冗余校验

Xilinx-Verilog-学习笔记(20):汉明码编解码与CRC冗余校验

一、汉明码编解码

1、原理解析

汉明码(Hamming Code),是在电信领域的一种线性调试码,以发明者理查德·卫斯里·汉明的名字命名。汉明码在传输的消息流中插入验证码,当计算机存储或移动数据时,可能会产生数据位错误,以侦测并更正单一比特错误。由于汉明编码简单,它们被广泛应用于内存(RAM)。

约定N为编码后的数据比特长度,K为待编码数据的比特长度,R为校验位(R=N-K),D为最小汉明距离(相邻两行之间不同比特数据的最小值)。

生成矩阵G
在这里插入图片描述
(1)编码过程
A[7:0]为原始矩阵,编码后的矩阵为CODE[11:0]=G x A
即有:
CODE[11]=A[7]
CODE[10]=A[6]
………………………
CODE[4]=A[0]
CODE[3]=A[7] ^ A[5] ^ A[3] ^ A[2]
CODE[2]=A[7] ^ A[6] ^ A[4] ^ A[2] ^ A[1]
CODE[1]=A[7] ^ A[6] ^ A[5] ^ A[3] ^ A[1] ^ A[0]
CODE[0]=A[6] ^ A[4] ^ A[3] ^ A[0]
其中 ^表示异或

举例:

待编码数据为8’b0011_0101

则矩阵A为一维的[0 0 1 1 0 1 0 1];
编码过程为:
CODE[11]=A[7]=0
CODE[10]=A[6]=0
CODE[9]=A[5]=1
CODE[8]=A[4]=1
CODE[7]=A[3]=0
CODE[6]=A[2]=1
CODE[5]=A[1]=0
CODE[4]=A[0]=1
CODE[3]=A[7] ^ A[5] ^ A[3] ^ A[2]=0 ^ 1 ^ 0 ^ 1=0
CODE[2]=A[7] ^ A[6] ^ A[4] ^ A[2] ^ A[1]=0 ^ 0 ^ 1 ^ 1 ^ 0=0
CODE[1]=A[7] ^ A[6] ^ A[5] ^ A[3] ^ A[1] ^ A[0]=0 ^ 0 ^ 1 ^ 0 ^ 0 ^ 1=0
CODE[0]=A[6] ^ A[4] ^ A[3] ^ A[0]=0 ^ 1 ^ 0 ^ 1=0

编码后数据U为12’b0011_0101_0000=12’h350

(2)解码过程
解码分为四步:第一步是求校验矩阵,第二步是求校正子,第三步是定位错误比特,第四步是优化数据修正方法。

第一步:求校验矩阵

校验矩阵用字母H表示,H={PT,I(N-K)},其中I(N-K)代表4 x 4的单位矩阵。
校验矩阵H为:
在这里插入图片描述
第二步:求校正子

假设经过信道后出来的数据U’变为12’b0011_0101_0001=12’h351
校正子用字母S表示,待解码数据为CODE用U表示。S=HT * U
即有:
S[3]=U[11] ^ U[9] ^ U[7] ^ U[6] ^ U[3]=0 ^ 1 ^ 0 ^ 1 ^ 0=0
S[2]=U[11] ^ U[10] ^ U[8] ^ U[6] ^ U[5] ^ U[2]=0 ^ 0 ^ 1 ^ 1 ^ 0 ^ 0=0
S[1]=U[11] ^ U[10] ^ U[9] ^ U[7] ^ U[5] ^ U[4] ^ U[1]=0 ^ 0 ^ 1 ^ 0 ^ 0 ^ 1 ^ 0=0
S[0]=U[10] ^ U[8] ^ U[7] ^ U[4] ^ U[0]=0 ^ 1 ^ 0 ^ 1 ^ 1=1

得到的矫正因子S为0001

第三步:定位错误比特

通过错误模式推得校正子Si, i是index指的的是错误模式的种类,因为我们汉明码解码数据有12bit 所以错误模式有12种,还包括一种全部正确的模式。
Si=HT*Ei
在这里插入图片描述
已知错误的比特位为最低位的0变成了1,且计算得到的S为0001,查找错误表可知是编号0.对应可以看出是第0比特位出现了错误。

第四步:优化数据修正方法
修正后的矩阵C为:
C[11]=U[11]^( ~S[3]&S[2]&S[1]&S[0])
C[10]=U[10]^(S[3]& ~S[2]&S[1]& ~S[0])
C[9]=U[9]^( ~S[3]&S[2]& ~S[1]&S[0])
C[8]=U[8]^(S[3]&S[2]&S[1]&S[0])
C[7]=U[7]^(S[3]& ~S[2]&S[1]&S[0])
C[6]=U[6]^(S[3]&S[2]& ~S[1]& ~S[0])
C[5]=U[5]^( ~S[3]&S[2]&S[1]& ~S[0])
C[4]=U[4]^( ~S[3]& ~S[2]&S[1]&S[0])
C[3]=U[3]^(S[3]& ~S[2]& ~S[1]& ~S[0])
C[2]=U[2]^( ~S[3]&S[2]& ~S[1]& ~S[0])
C[1]=U[1]^( ~S[3]& ~S[2]&S[1]& ~S[0])
C[0]=U[0]^( ~S[3]& ~S[2]& ~S[1]&S[0])

待解码U12’b0011_0101_0001=12’h351,S为0001
则修正后的C为:
C[11]=U[11]^( ~S[3]&S[2]&S[1]&S[0])=0 ^ 0=0
C[10]=U[10]^(S[3]& ~S[2]&S[1]& ~S[0])=0 ^ 0=0
C[9]=U[9]^( ~S[3]&S[2]& ~S[1]&S[0])=1 ^ 0=1
C[8]=U[8]^(S[3]&S[2]&S[1]&S[0])=1 ^ 0=1
C[7]=U[7]^(S[3]& ~S[2]&S[1]&S[0])=0 ^ 0=0
C[6]=U[6]^(S[3]&S[2]& ~S[1]& ~S[0])=1 ^ 0=1
C[5]=U[5]^( ~S[3]&S[2]&S[1]& ~S[0])=0 ^ 0=0
C[4]=U[4]^( ~S[3]& ~S[2]&S[1]&S[0])=1 ^ 0=1
C[3]=U[3]^(S[3]& ~S[2]& ~S[1]& ~S[0])=0 ^ 0=0
C[2]=U[2]^( ~S[3]&S[2]& ~S[1]& ~S[0])=0 ^ 0=0
C[1]=U[1]^( ~S[3]& ~S[2]&S[1]& ~S[0])=0 ^ 0=0
C[0]=U[0]^( ~S[3]& ~S[2]& ~S[1]&S[0]) =1 ^ 1=0

则经过修正后的C为12’b0011_0101_0000
可以发现最后被错写为1的已经被重新修正为0。

2、design文件

(1)汉明码编码:hamm_code.v

module	hamm_code(
	input	wire			sclk,
	input	wire			rst_n,
	input	wire			data_v,	//接收到标志进行一次转码
	input	wire	[7:0]	data_i,	//待编码数据
	output	reg				code_v, //编码标志位
	output	reg		[11:0]	code_o	//编码后数据
);

always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		code_v <= 1'b0;
	else code_v <= data_v;
	
always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		code_o<='d0;
	else if(data_v == 1'b1)begin
		code_o[11:4] <= data_i;
		code_o[3] <= data_i[7]^data_i[5]^data_i[3]^data_i[2];
		code_o[2] <= data_i[7]^data_i[6]^data_i[4]^data_i[2]^data_i[1];
		code_o[1] <= data_i[7]^data_i[6]^data_i[5]^data_i[3]^data_i[1]^data_i[0];
		code_o[0] <= data_i[6]^data_i[4]^data_i[3]^data_i[0];
	end
	else
		code_o <= 'd0;
endmodule

(2)汉明码解码:hamm_dec.v

module	hamm_dec(

	input	wire			sclk,
	input	wire			rst_n,
	input	wire	[11:0]	data_i,
	input	wire			data_v,
	output	reg		[7:0]	data_o,
	output	reg				data_ov
);

wire	[3:0]	S;
wire	[11:0]	C;

always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		data_ov <= 1'd0;
	else data_ov <= data_v;

assign S[3]=data_i[11]^data_i[9]^data_i[7]^data_i[6]^data_i[3];
assign S[2]=data_i[11]^data_i[10]^data_i[8]^data_i[6]^data_i[5]^data_i[2];
assign S[1]=data_i[11]^data_i[10]^data_i[9]^data_i[7]^data_i[5]^data_i[4]^data_i[1];
assign S[0]=data_i[10]^data_i[8]^data_i[7]^data_i[4]^data_i[0];

assign	C[11]=data_i[11]^(S[3]&S[2]&S[1]&~S[0]); 
assign	C[10]=data_i[10]^(~S[3]&S[2]&S[1]&S[0]);
assign	C[9]=data_i[9]^(S[3]&~S[2]&S[1]&~S[0]);  
assign	C[8]=data_i[8]^(~S[3]&S[2]&~S[1]&S[0]) ;   
assign	C[7]=data_i[7]^(S[3]&~S[2]&S[1]&S[0]);   
assign	C[6]=data_i[6]^(S[3]&S[2]&~S[1]&~S[0]);  
assign	C[5]=data_i[5]^(~S[3]&S[2]&S[1]&~S[0]) ; 
assign	C[4]=data_i[4]^(~S[3]&~S[2]&S[1]&S[0]);  
assign	C[3]=data_i[3]^(S[3]&~S[2]&~S[1]&~S[0]); 
assign	C[2]=data_i[2]^(~S[3]&S[2]&~S[1]&~S[0]); 
assign	C[1]=data_i[1]^(~S[3]&~S[2]&S[1]&~S[0]);
assign	C[0]=data_i[0]^(~S[3]&~S[2]&~S[1]&S[0]) ;

always @(posedge sclk or negedge rst_n)
	if(rst_n == 1'b0)
		data_o<= 'd0;
	else if(data_v == 1'b1)
		data_o <= C[11:4];
	else
		data_o <='d0;

endmodule
3、testbench文件
`timescale	1ns/1ns
module	tb_hamming;

reg				sclk ,rst_n;
reg		[7:0]	data;
reg				data_v;
wire	[11:0]	code;
wire			code_v;
wire	[7:0]	c_data;
wire			c_v;
initial	begin    
	rst_n =0;
	sclk =0;
	
	#100
	rst_n=1;
end

always # 10 sclk = ~sclk;

initial begin
	data =0;
	data_v =0;
	#300
	@(posedge sclk)
	data_v =1;  
	data =8'h35;
	#22
	data_v =0;   
 	data =8'h0;
end    


hamm_code	hamm_code_inst(

	.sclk		(sclk),
	.rst_n		(rst_n),
	.data_v		(data_v),
	.data_i		(data),//待编码数据
	.code_v		(code_v),
	.code_o		(code)//编码后数据
	
);


hamm_dec	hamm_dec_inst(

	.sclk		(sclk),
	.rst_n		(rst_n),
	.data_i		({code[11:1],~code[0]}),
	//.data_i		({~code[11],code[10:0]}),
	.data_v		(code_v),
	.data_o		(c_data),
	.data_ov	(c_v)
);

endmodule
4、仿真波形

在这里插入图片描述
原始数据data_i为8’h35,通过汉明码编码为code_o=12’h350。此时该数据经过信道,我们模拟最低位翻转了,即从信道输出data_i为12’h351,汉明码自动校验发现错误,并对其进行修正变为C=12‘h350,最终解码后的数据重新恢复为8’h35。

二、CRC冗余校验

1、原理解析

CRC8基本原理
计算方法

举例:
生成多项式G(x)=x4+x1+x0
则G(x)=10011
编码后的矩阵CODE:1010111011

(1)将码字CODE左移4位(最高次幂):10101110110000
(2)将左移4位的与G(x)相除:
在这里插入图片描述
(3)从结果可得:CRC=0010,将这部分加到编码矩阵后面,则为1010111011_0010
(4)在接收端同样需要进行验证,如果余数为0则表示正确。
在这里插入图片描述

2、硬件电路实现

画出多项式的硬件结构电路图:
在这里插入图片描述

画的方法是:CRC=10011,只要是有1的位,前面就要放一个异或,那么第0位和第1位前面有异或,最高位和最低位共用1个异或,所以在图中没有体现。最高位域输入的异或后的结果,要反馈到每个异或的地方去。

最后推出各个比特位下的多项式公式即可。

  • 8
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DDS(Direct Digital Synthesis)直接数字合成技术是一种数字信号处理技术,用于产生高精度、高稳定度、高分辨率的周期性信号。DDS技术的主要思路是:将一个固定的参考频率信号和一个可变的相位调制信号相乘,从而产生所需频率的输出信号。 在MATLAB中,我们可以通过使用内置函数sin()来生成正弦波信号。例如,我们可以生成一个频率为10 Hz,振幅为1的正弦波信号,并将其绘制成图形: ``` t = 0:0.001:1; x = sin(2*pi*10*t); plot(t,x); ``` 在Verilog中,我们可以使用DDS模块来生成正弦波信号。以下是一个简单的DDS模块: ``` module dds( input clk, //时钟信号 input reset, //复位信号 output reg [7:0] sin_out //正弦波输出信号 ); reg [31:0] phase_acc; //相位累加器 reg [7:0] sin_lut [0:255]; //正弦波查找表 //初始化正弦波查找表 initial begin for (i = 0; i < 256; i = i + 1) begin sin_lut[i] = $signed(127*sin(2*3.14159*i/256)); end end always @(posedge clk) begin if (reset) begin phase_acc <= 0; sin_out <= 0; end else begin phase_acc <= phase_acc + 100; //相位累加器步进为100 sin_out <= sin_lut[phase_acc[31:24]]; //从查找表中读取正弦波值 end end endmodule ``` 在这个DDS模块中,我们使用相位累加器来控制正弦波的频率,使用查找表来存储正弦波的值。在时钟上升沿时,相位累加器步进100,从查找表中读取正弦波值,并将其输出。 需要注意的是,在这个DDS模块中,我们使用了固定的步进值100。如果我们想要生成不同频率的正弦波信号,我们需要改变步进值。例如,如果我们想要生成频率为1 kHz的正弦波信号,我们需要将步进值改为1000*256/时钟频率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值