BCH编码器

1. 实验内容

通过本实验了解BCH编译码原理,能够用Verilog HDL或者VHDL编写BCH编译码程序。本实验要求实现BCH(15,7,2)编译码功能,加入信道噪声进行,比较译码结果。



2. 实验原理

(1)BCH编码原理 BCH是一种线性分组码,它是循环码的一种。一个(15,7,2)的BCH码的含义是,一组码的码长为15,信息位为7位,效验位为8位,纠错能力为2。它的本原多项式为 ; 本实验采用系统BCH码,即码的前7位为信息位不变,而后8位校验位多项式为码的信息位多项式与生成多项式相除的余数得到。具体公式如下: ; 其中R(x)为效验位多项式,M(x)为信息位的多项式 例如信息位为1100000,则,

 校验位多项式  {{ :图16-164.png |}}        
 编码多项式  {{ :图16-165.png |}}           

因此,编码输出为110000010011100。 BCH码各个码位的系数,也可以通过生成矩阵G求得: 生成多项式的生成矩阵为:

生成矩阵的构造原理可以参看数字通信相关书籍。 (2)BCH码译码原理 BCH译码分为三步: 1) 由接收到的码的多项式R(x)计算出伴随多项式S(x) 同样地,伴随多项式系数也可以由矩阵运算得到。公式如下:
其中H被称为校验矩阵。 2)根据伴随多项式计算找到对应的错误图样E(x)。

  本实验使用查表法计算错误图样。

3)计算出译码输出C(x)=R(x)-E(x)



3. 实验设计

3.1 总体架构

程序由5个模块组成(图 16 1):
1. BCH为顶层模块,完成各模块之间的连接;
2. clock模块实现50M时钟clk50的4分频clk,clk50作为signaltap的采样时钟。clk作为其它四个模块的主时钟;
3. m
serial产生一个M序列作为数据作为编码模块的输入。
4. encoder是BCH的编码模块。
5. channel模块模拟信道,加入误码。
6. decoder是BCH的译码模块。 图16-1 程序总体模块图

图16-1 程序总体模块图

3.2 m_serial模块(m_serial.v)

mserial模块产生一个的M序列作为数据用作BCH的数据输入,M序列的产生电路如所图 16 2示。每四个时钟周期产生一个输出,用计数器counter来控制。当counter等于3时,输出一个比特,一个使能dataen信号,dataen给encoder模块用于信号采样,在dataen为高电平时,时钟上升延采样。 图16-2 M序列生成电路

图16-2 M序列生成电路

 
input	clk;        		//时钟输入。
input    reset;       		//复位输入。
input    load;       		//load信号用于初始化M序列多项式系数。
output   data_en;    		//M序列输出使能信号,高电平有效。
output   data_out;    		//M序列输出。
 
always @(posedge clk) begin
if (!reset) begin
	    	a7 <= 0;
			a6 <= 0;
			a5 <= 0; 
			a4 <= 0; 
			a3 <= 0; 
			a2 <= 0;
			a1 <= 0;
			a0 <= 0;
			data_en <= 0;
		end
			else begin
			    if (!load) begin //当load为低时,重新初始化M序列多项式系数。
					a7 <= 1;
					a6 <= 0;
					a5 <= 0; 
					a4 <= 0; 
					a3 <= 0; 
					a2 <= 0;
					a1 <= 0;
					a0 <= 0; 
					data_en <= 0;
				end
				else begin
					//counter是一个0~3的计数器。当counter==3时,输出一个比特。
if (counter==3) begin
data_en <= 1;
a0 <= a1;
a1 <= a2;
a2 <= a3;
a3 <= a4;
a4 <= a5;
a5 <= a6;
a6 <= a7;
a7 <= a4^a3^a2^a0;
end
else 
data_en <= 0;
			end
		end
	end

3.3 encoder模块(encoder.v)

encoder模块完成BCH编码,在采得7位信息位后对它进行编码,然后将15位BCH码串行输出,同时输出data valid信号用于指示encodeout有效。

 
input	clk;        		//时钟信号。
input   reset;      		//同步复位信号。
input   data_en;     		//M序列数据使能信号。
input   data_in;     		//M序列输入。
output  encode_out;  		//BCH码输出。
output 	encode_valid; 		//BCH码输出有效,高电平有效。
 
//将输入的数据保存到temp中,temp可以存储一组7比特数据。
always @(posedge clk) begin
if(!reset) begin
		temp <= 7'b000_0000;
	 	counter <= 3'b000;
	end
	else begin
		if(data_en) 
	   		if(counter == 3'b110) begin
	    		temp[6-counter] <= data_in;
	    		counter <= 3'b000;
	    	end
			else begin
	    		temp[6-counter] <= data_in;
	    		counter <= counter+1;
	    	end
		end
	end
 
//当temp接受完7比特数据后,将其送给info并对其进行编码。
always @(posedge clk) begin
if(!reset) 
		info[6:0] = 7'b000_0000;
	else
		if(counter == 3'b110 &&data_en == 1 )
			info = temp; 
	end
 
//信息码与生成矩阵相乘,实现编码功能。
//data为15为编码结果,低7比特为原始数据,高8比特为校验位。
assign data[14:8] = info[6:0]; //BCH前7位为信息。
assign data[7] = info[6]^info[2]^info[0];  //后8位效验位生成。
assign data[6] = info[6]^info[5]^info[2]^info[1]^info[0];
assign data[5] = info[6]^info[5]^info[4]^info[2]^info[1];
assign data[4] = info[5]^info[4]^info[3]^info[1]^info[0];
assign data[3] = info[6]^info[4]^info[3];
assign data[2] = info[5]^info[3]^info[2];
assign data[1] = info[4]^info[2]^info[1];
assign data[0] = info[3]^info[1]^info[0];
 
//将编码后的15比特数据输出。
always @(posedge clk) begin
if(!reset) begin
		encode_out <= 15'b000_0000_0000_0000;
		encode_valid <= 0;
	end
	else
		//当counter等于0时,表示完成数据输入和编码,下一个周期可以
		//输出数据。
		if(counter == 3'b000 && data_en == 1) begin
	   	 	encode_valid <= 1; //编码有效信号,长度为15个时钟周期。
	        cnt<=14;		  //cnt实现对输出数据个数的控制,为15比特。
	    	encode_out <= data[14];
		end
		else
		    if(cnt <= 0)
			   	 encode_valid <= 0; //当15位编码输出结束后,编码有效位置为0。
			else begin
				encode_out <= data[cnt-1];//每个时钟周期输出一位BCH码。
				encode_valid <= 1;
				cnt <= cnt-1;
			end
	end
end

3.4 channel模块(channel.v)

channel模块用于模拟简单的信道,在编码后的数据中加入误码,在此将第12位和第10位加入误码。Channel模块的接口如下:

 
input   clk;       			//时钟信号
input   data_in;      		//数据输入
input   data_in_valid; 		//数据输入有效
output  data_noise;        	//信道噪音数据
程序如下:
always @(posedge clk) begin
		 if (!data_in_valid)
			counter <= 0;
		 else
		  	if (counter == 14) begin
				counter <= 0;
				noise <= 0;
			end
			else
				if (counter == 1 || counter==3) begin
					counter <= counter+1;    
					noise <= 1;          当counter等于13时,noise置为1
				end
				else begin
					counter <= counter+1; 
					noise <= 0; 		当counter等于其他数时,noise置为0
				end
		end

assign datanoise = noise^datain; 信道输出为noise信号与data_in信号异或。

3.5 decoder模块(decoder.v)

decoder模块用于解码,在datavalid为高电平时将数据缓存起来,然后根据输入的编码算出伴随多项式。然后用查表法找到错误图样。最后将纠错的码字串行输出,同时输出decodevalid信号,此时只输出7位信息位,校验位被丢弃。

Decoder的输入输出接口如下:

 
input	clk;        		//时钟信号
input   reset;       		//同步复位信号
input   data_in_valid;		//数据输入有效
input   data_in;            //数据输入
output  decode_out;         //BCH解码输出
output  decode_valid;       //BCH解码有效
实现程序如下:
always @(posedge clk )
	if (!reset) begin
		temp <= 15'b000_0000_0000_0000; //temp保存了15比特的数据输入。
		counter <= 0;
	end
	else begin
		if(!data_in_valid)
			counter <= 0;
		else begin
		    counter <= counter+1;
		    temp[14-counter] <= data_in; //当有效为1时,将输入的15位编
码按顺序送给Temp。
	    end
	end
end
 
always @(posedge clk) begin
if (!reset) 
		info <= 0;  		//info中保存要译码的数据。
	else
		if (counter == 5'b01111)
      		info <= temp; 	//当temp最后一位赋值结束后,将 temp赋值给info。
 end
  	//根据输入的码组计算出伴随多项式S。
	wire [7:0] s;
assign s[7] = info[14]^info[13]^info[12]^info[10]^
info[8]^info[7]^info[4]^info[0];
assign s[6] = info[12]^info[11]^info[10]^info[9]^
info[7]^info[5]^info[4]^info[1];
assign	s[5] = info[13]^info[12]^info[11]^info[10]^
info[8]^info[6]^info[5]^info[2];
     assign	s[4] = info[14]^info[13]^info[12]^info[11]^
info[9]^info[7]^info[6]^info[3];
	 assign	s[3] = info[14]^info[10]^info[9]^info[5]^info[4]^info[0];
	 assign	s[2] = info[14]^info[13]^info[9]^info[8]^info[4]^info[3];
	 assign	s[1] = info[14]^info[12]^info[9]^info[7]^info[4]^info[2];
	 assign	s[0] = info[14]^info[13]^info[12]^info[11]^info[9]^
info[8]^info[7]^info[6]^info[4]^info[3]^info[2]^info[1];
 
   	//利用查找表找出此输入码组的错误图样,error为错误图样。
reg [6:0] error;
always @(s)
		    case(s)
		    	8'b10011111 : error = 7'b1000000;
			      ……………………………………… //此处略去了查找表
		        default     : error = 7'b0000000;
		      endcase
 
//info与error求异或,得到译码后的结果。
assign data = error^info[14:8];
 
	always @(posedge clk) begin
		if (!reset) begin
			decode_out <=7'b000_0000;
			cnt <= 7;		//输出数据为7比特,由计数器cnt来控制。
		end
		else begin
			if(counter == 5'b01111)
				cnt <= 7;
			else begin
				if (cnt == 0)
					decode_valid <= 0;
				else begin
					decode_out <= data[cnt-1];  //将译码后的信号依次输出。
					decode_valid <= 1;         //输出信号有效。
					cnt <= cnt-1;
				end
			end	
		end
	end



4. 仿真结果

图 16 3为ModelSim仿真的结果。图中对7位的M序列1100000进行编译码。经过BCH编码后的输出为110000010011100。再经过信道后加入噪声后,第12位和第10位发生了变化,变为111010010011100。在经过译码后输出为1100000,证明译码是正确的。 图16-3  程序仿真结果

图16-3 程序仿真结果



5. 运行结果

图 16 4是程序运行的结果。在signaltap中可以看到编解码的正确性。编码输入为0001001,经过信道后变为000100111001100,在经过解码后输出为0001001,译码正确。 图16-4  程序运行结果

图16-4 程序运行结果



6. 演示程序文件说明

文件名功能
BCH.v主程序
clock.v时钟分频
m_serial.vM序列产生
encoder.vBCH编码
channel.v信道噪声仿真
decoder.vBCH解码
Test.v测试程序,用于Modelsim仿真的测试程序,对BCH.v进行仿真



7. 演示程序使用

演示设备要求:核心板

演示步骤:把程序下载到开发板上,reset为复位键。KEY1为load信号输入。通过SignalTap观察运行结果。