文章目录
-
-
- 汉明码
-
- 定义
- 校验位个数
- 编码规则
- 一个例子
-
- C++实现
-
- Verilog实现
-
汉明码
定义
- 在传输的信息流中插入验证码,侦测单一比特错误
- 只能发现和修正一位错误,对于两位或两位以上的错误无法发现与修正
校验位个数
编码规则
- 在新的编码的2(k - 1)( k >= 0)位上填入0(即校验位),把新的编码的其余位把源码按原顺序填入
- 校验位的编码方式为:
- 第k位校验码从则从新的编码的第2(k - 1)位开始,每计算2(k - 1)位的异或,跳2(k - 1)位,再计算下一组2(k - 1)位的异或,填入2(k - 1)位
- 比如:
- 第1位校验码位于新的编码的第1位(2 (1-1) == 1)(汉明码从1位开始),计算1,3,5,7,9,11,13,15,…位的异或,填入新的编码的第1位
- 第2位校验码位于新的编码的第2位(2 (2-1) == 2),计算2,3,6,7,10,11,14,15,…位的异或,填入新的编码的第2位
- 第3位校验码位于新的编码的第4位(2 (3-1) == 4),计算4,5,6,7,12,13,14,15,20,21,22,23,…位的异或,填入新的编码的第4位
- 第4位校验码位于新的编码的第8位(2 (4-1) == 8),计算8-15,24-31,40-47,…位的异或,填入新的编码的第8位
- 第5位校验码位于新的编码的第16位(2 (5-1) == 16),计算16-31,48-63,80-95,…位的异或,填入新的编码的第16位
一个例子
- 以10101编码为例,创建一个汉明码编码的空间,并且需要将原本数据位的校验位放置于对应位置中
- 计算校验位数
- 23 < 5 + 3 + 1
- 24 ≥ 5 + 4 + 1
- r = 4
- 数据位记为P1~P5 = 10101
- 校验位记为C1~C4
- 数据输出为:C1C2P1C3P2P3P4C4P5
编码
- 计算校验位
- C1 = P1 ^ P2 ^ P4 ^ P5 = 1 ^ 0 ^ 0 ^ 1 = 0
- C2 = P1 ^ P3 ^ P4 = 1 ^ 1 ^ 0 = 0
- C3 = P2 ^ P3 ^ P4 = 0 ^ 1 ^ 0 = 1
- C4 = P5 = 1
- 插入校验位
- C1C2P1C3P2P3P4C4P5 = 001101011
解码
- 假设收到的编码数据为:001101001
- 计算校验位数
- 23 < 5 + 3 + 1
- 24 ≥ 5 + 4 + 1
- r = 4
- 2(k - 1)(k = 1, 2, 3, 4)为校验位位置
- 校验
- C1 ^ P1 ^ P2 ^ P4 ^ P5 = 0 ^ 1 ^ 0 ^ 0 ^ 1 = 0
- C2 ^ P1 ^ P3 ^ P4 = 0 ^ 1 ^ 1 ^ 0 = 0
- C3 ^ P2 ^ P3 ^ P4 = 1 ^ 0 ^ 1 ^ 0 = 0
- C4 ^ P5 = 0 ^ 1 = 1
- 将各校验结果逆序排列 = 2’b1000 = 1’d8
- 则第8位出错,纠正后 = 001101001 -> 001101011
C++实现
功能编写
// calculate the number of check digits for encode
auto cal(size_t sz) -> decltype(auto)
{
decltype(sz) k = 0;
decltype(sz) cur = 1;
while (cur - 1 < sz + k)
{
cur <<= 1;
k++;
}
return k;
}
// encode
bool encode(const string &data, string &str)
{
str.clear();
auto check = cal(data.size());
str.resize(data.size() + check);
for (decltype(str.size()) i = 0, j = 0, p = 0; i != str.size(); i++)
{
if ((i + 1) == pow(2, p) && p < check)
{
str[i] = '0';
p++;
}
else if (data[j] == '0' || data[j] == '1')
{
str[i] = data[j++];
}
else
{
return false;
}
}
for (auto i = 0; i != check; i++)
{
int count = 0, index = 1 << i;
for (auto j = index - 1; j < str.size(); j += index)
{
for (auto k = 0; k != index && j < str.size(); k++, j++)
{
count ^= str[j] - '0';
}
str[index - 1] = '0' + count;
}
}
return true;
}
// calculate the number of check digits for decode
auto antical(size_t sz) -> decltype(auto)
{
decltype(sz) k = 0;
decltype(sz) cur = 1;
while (cur < sz)
{
cur <<= 1;
k++;
}
return k;
}
// decode
auto decode(string &data, string &str) -> decltype(auto)
{
data.clear();
auto check = antical(str.size());
data.resize(str.size() - check);
decltype(data.size()) sum = 0;
for (decltype(check) i = 0; i != check; i++)
{
int pAnti = 0;
decltype(check) index = 1 << i;
for (decltype(str.size()) j = index - 1; j < str.size(); j += index)
{
for (auto k = 0; k < index && j < str.size(); j++, k++)
{
pAnti ^= str[j] - '0';
}
}
sum += pAnti << i;
}
if (sum != 0)
{
str[sum - 1] = (1 - (int)(str[sum - 1] - '0')) + '0';
}
for (decltype(str.size()) i = 0, j = 0, k = 0; i != str.size(); i++)
{
if ((i + 1) == (1 << j) && j < check)
{
j++;
}
else
{
data[k++] = str[i];
}
}
return sum;
}
测试结果
int main()
{
string source, dest;
while (cin >> source)
{
if (encode(source, dest))
{
cout << "source : " << source << endl;
cout << "dest : " << dest << endl;
}
size_t index;
cout << "input error index : ";
cin >> index;
auto check = dest.size();
if (index != 0 && index <= dest.size())
{
dest[index - 1] = (1 - (int)(dest[index - 1] - '0')) + '0';
}
cout << "code : " << dest << endl;
auto ret = decode(source, dest);
if (ret == 0)
{
cout << "source : " << source << endl;
cout << "dest : " << dest << endl;
}
else
{
cout << "error index : " << ret << endl;
cout << "corret source : " << source << endl;
cout << "corret dest : " << dest << endl;
}
cout << endl;
}
return 0;
}
- 结果
Verilog实现
.v功能代码
module ham_encoder(
input wire clk,
input wire rst_n,
input wire data_v,
input wire [ 7:0] data_in,
output reg encode,
output reg [11:0] data_out
);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
encode <= 1'b0;
end else begin
encode <= 1'b1;
end
end
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_out <= 12'b0;
end else if (data_v) begin
data_out[11:4] <= data_in[7:0];
data_out[3] <= data_in[7]^data_in[5]^data_in[3]^data_in[2];
data_out[2] <= data_in[7]^data_in[6]^data_in[4]^data_in[2]^data_in[1];
data_out[1] <= data_in[7]^data_in[6]^data_in[5]^data_in[3]^data_in[1]^data_in[0];
data_out[0] <= data_in[6]^data_in[4]^data_in[3]^data_in[0];
end else begin
data_out <= 12'b0;
end
end
endmodule
module ham_decoder(
input wire clk,
input wire rst_n,
input wire data_v,
input wire [11:0] data_in,
output reg [ 7:0] data_out,
output reg decode
);
wire [ 3:0] checkout;
wire [11:0] data;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
decode <= 1'd0;
end else begin
decode <= 1'b1;
end
end
assign checkout[3] = data_in[11]^data_in[ 9]^data_in[7]^data_in[6]^data_in[3];
assign checkout[2] = data_in[11]^data_in[10]^data_in[8]^data_in[6]^data_in[5]^data_in[2];
assign checkout[1] = data_in[11]^data_in[10]^data_in[9]^data_in[7]^data_in[5]^data_in[4]^data_in[1];
assign checkout[0] = data_in[10]^data_in[ 8]^data_in[7]^data_in[4]^data_in[0];
assign data[11] = data_in[11]^( checkout[3]& checkout[2]& checkout[1]&~checkout[0]);
assign data[10] = data_in[10]^(~checkout[3]& checkout[2]& checkout[1]& checkout[0]);
assign data[ 9] = data_in[ 9]^( checkout[3]&~checkout[2]& checkout[1]&~checkout[0]);
assign data[ 8] = data_in[ 8]^(~checkout[3]& checkout[2]&~checkout[1]& checkout[0]);
assign data[ 7] = data_in[ 7]^( checkout[3]&~checkout[2]& checkout[1]& checkout[0]);
assign data[ 6] = data_in[ 6]^( checkout[3]& checkout[2]&~checkout[1]&~checkout[0]);
assign data[ 5] = data_in[ 5]^(~checkout[3]& checkout[2]& checkout[1]&~checkout[0]);
assign data[ 4] = data_in[ 4]^(~checkout[3]&~checkout[2]& checkout[1]& checkout[0]);
assign data[ 3] = data_in[ 3]^( checkout[3]&~checkout[2]&~checkout[1]&~checkout[0]);
assign data[ 2] = data_in[ 2]^(~checkout[3]& checkout[2]&~checkout[1]&~checkout[0]);
assign data[ 1] = data_in[ 1]^(~checkout[3]&~checkout[2]& checkout[1]&~checkout[0]);
assign data[ 0] = data_in[ 0]^(~checkout[3]&~checkout[2]&~checkout[1]& checkout[0]);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_out<= 12'b0;
end else if(decode) begin
data_out <= data[11:4];
end else begin
data_out <= 12'b0;
end
end
endmodule
testbench
`timescale 1ns / 1ps
`include "ham_encoder.v"
`include "ham_decoder.v"
module tb_ham;
// edge_detect Parameters
parameter PERIOD = 10;
// Inputs
reg clk = 0 ;
reg rst_n = 0 ;
reg data_v = 0 ;
reg [ 7:0] data_in ;
// Output
wire [11:0] encoder ;
wire encode ;
wire [ 7:0] decoder ;
wire decode ;
initial begin
forever begin
#(PERIOD) clk = ~clk;
end
end
initial begin
#(PERIOD*2) rst_n = ~rst_n;
end
initial begin
#(PERIOD*2)
@ (posedge clk)
data_in = 8'h35;
data_v = 1'b1;
#(PERIOD*2)
data_in = 8'h0;
data_v = 1'b0;
end
initial
begin
$dumpfile("./build/ham.vcd");
$dumpvars;
#1000
$finish;
end
ham_encoder u_ham_encoder (
.clk ( clk ),
.rst_n ( rst_n ),
.data_v ( data_v ),
.data_in ( data_in [ 7:0] ),
.encode ( encode ),
.data_out ( encoder )
);
wire [11:0] err_encoder;
assign err_encoder = {encoder[11:1], ~encoder[0]};
ham_decoder u_ham_decoder (
.clk ( clk ),
.rst_n ( rst_n ),
.data_v ( encode ),
.data_in ( err_encoder ),
.data_out ( decoder[ 7:0] ),
.decode ( decode )
);
endmodule
波形