海明纠错码
海明码(Hamming Code)是一个可以有多个校验位,具有检测并纠正一位错误代码的纠错码,所以它也仅用于信道特性比较好的环境中,如以太局域网中,因为如果信道特性不好的情况下,出现的错误通常不是一位。
海明码的检错、纠错基本思想是将有效信息按某种规律分成若干组,每组安排一个校验位进行奇偶性测试,然后产生多位检测信息,并从中得出具体的出错位置,最后通过对错误位取反(也是原来是1就变成0,原来是0就变成1)来将其纠正。
要采用海明码纠错,需要按以下步骤来进行:
- 计算校验位数
- 确定校验码位置
- 确定校验码
- 实现校验和纠错
摘自 茶乡浪子
1. 计算校验位数
要使用海明码纠错,首先就要确定发送的数据所需要要的校验码(也就是“海明码”)位数(也称“校验码长度”)。它是这样的规定的:假设用N表示添加了校验码位后整个信息的二进制位数,用K代表其中有效信息位数,r表示添加的校验码位,它们之间的关系应满足:
N=K+r≤2r-1N=K+r \le 2^r-1N=K+r≤2r-1
如K=5,则要求2r−r≥5+1=62^r-r≥5+1=62r−r≥5+1=6,根据计算可以得知r的最小值为4,也就是要校验5位信息码,则要插入4位校验码。如果信息码是8位,则要求2r−r≥8+1=92^r-r \ge 8+1=92r−r≥8+1=9,根据计算可以得知r的最小值也为4。
信息码位数与校验码位数之间的关系
信息码位数 | 1 | 2~4 | 5~11 | 12~26 | 27~57 | 58~120 | 121~247 |
---|---|---|---|---|---|---|---|
校验码位数 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
2.确定校验码位置
上一步我们确定了对应信息中要插入的校验码位数,但这还不够,因为这些校验码不是直接附加在信息码的前面、后面或中间的,而是分开插入到不同的位置。但不用担心,校验码的位置很容易确定的,那就是校验码必须是在 2n2^n2n 次方位置,如第1、2、4、8、16、32,……位(对应20、21、22、23、24、25,……,是从最左边的位数起的),这样一来就知道了信息码的分布位置,也就是非 2n2^n2n 次方位置,如第3、5、6、7、9、10、11、12、13,……位(是从最左边的位数起的)。
举一个例子,假设现有一个8位信息码,即b1、b2、b3、b4、b5、b6、b7、b8,它需要插入4位校验码,即p1、p2、p3、p4,也就是整个经过编码后的数据码(称之为“码字”)共有12位。根据以上介绍的校验码位置分布规则可以得出,这12位编码后的数据就是p1、p2、b1、p3、b2、b3、b4、p4、b5、b6、b7、b8。
现假设原来的8位信息码为10011101,因现在还没有求出各位校验码值,现在这些校验码位都用“?”表示,最终的码字为:??1?001?1101。
3. 确定校验码
这些校验码的值不是随意的,每个校验位的值代表了代码字中部分数据位的奇偶性(最终要根据是采用奇校验,还是偶校验来确定),其所在位置决定了要校验的比特位序列。总的原则是:第i位校验码从当前位开始,每次连续校验2n−12^{n-1}2n−1位后再跳过i位,然后再连续校验2n−12^{n-1}2n−1位,再跳过2n−12^{n-1}2n−1位,以此类推。最后根据所采用的是奇校验,还是偶校验即可得出第nnn位校验码的值。如下表示意:原文
数据位位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ... | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
编码后数据位置 | p1 | p2 | d1 | p4 | d2 | d3 | d4 | p8 | d5 | d6 | d7 | d8 | d9 | d10 | d11 | p16 | d12 | d13 | d14 | d15 | ||
奇偶校验位 覆盖率 | p1 | X | X | X | X | X | X | X | X | X | X | |||||||||||
p2 | X | X | X | X | X | X | X | X | X | X | ||||||||||||
p4 | X | X | X | X | X | X | X | X | X | |||||||||||||
p8 | X | X | X | X | X | X | X | X | ||||||||||||||
p16 | X | X | X | X | X |
3.1 计算方法1
对每组数字位通过奇偶校验的方式来依次确定校验位的值。比如使用偶校验,校验位的值使用每组中1的个数为偶数,对组内已有数字进行异或运算得到校验位的值
3.1 计算方法2
对11000010进行汉明编码,求编码后的码字。
-
列出表格,从左往右(或从右往左)填入数字,但2的次方的位置不填。
位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 数据 1 1 0 0 0 0 1 0 -
把数据行有1的列的位置写为二进制。
位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 数据 1 1 0 0 0 0 1 0 二进制 0011 0101 1011 -
收集所有二进制数字,求异或。0011⊕0101⊕1011=11010011\oplus 0101 \oplus 1011=11010011⊕0101⊕1011=1101
-
把1101依次填入表格中2的次方的位置(低位在左)。
位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 数据 1 1 0 0 0 0 1 0 二进制 0011 0101 1011 校验 1 0 1 1 -
所以编码后的码字是101110010010。
4. 校验与纠错
把以上这些校验码所校验的位分成对应的组,则在接收端的对各校验位再进行逻辑“异或运算”,如果采用的是偶校验,正常情况下均为0。
如果最终发现只是一个校验组中的校验结果不符,则直接可以知道是对应校验组中的校验码在传输过程中出现了差错,因为所有校验码所在的位是只由对应的校验码进行校验;如果发现多组校验结果不正确,则查看这些组中公共校验的数据位(只有数据位才可能被几个校验码进行校验),以最终确定是哪个数据位出了差错(海明码只能检查一位出错);最后,对所找到的出错数据位取反即可实现纠错。
如计算出的每组的校验结果为p1、p2、p3、p4,均为0则正确,有一个不为0的则出错的位置在p1+10∗p2+100∗p3+1000∗p4p1+10*p2+100*p3+1000*p4p1+10∗p2+100∗p3+1000∗p4的位置处
5. 简单的算法实现
#include <iostream>using namespace std;namespace Encode
{// 参考 https://zh.wikipedia.org/wiki/%E6%B1%89%E6%98%8E%E7%A0%81/*** @brief encode a [5-11]-bit int to hamming code* @param inCode IN as orginal code* @param inLen IN as the length infomation* @param outCode OUT as the encoded int* @param outLen OUT as the length * @return none*/bool Hamming26(int const inCode, int const inLen, int& outCode, int& outLen){if (inLen <= 5 || inLen >= 11){return false;}int checkNum = 4; // 校验码位outLen = checkNum + inLen;const int dataBitLoc[] = { 2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14 };const int checkBitLoc[] = { 0, 1, 3, 7 };int checkSum = 0;for (int i = 0; i < inLen; ++i){int dataBit = ((inCode >> i) & 0x1);if (dataBit){outCode |= (dataBit << dataBitLoc[i]);checkSum ^= (dataBitLoc[i] + 1);}}cout << checkSum << endl;for (int i = 0; i < checkNum; ++i){outCode |= (((checkSum >> i) & 0x1) << checkBitLoc[i]);}return true;}// 参考http://www.cnblogs.com/scrutable/p/6052127.html/*** @brief check the correctness of a hamming code* @param code received code* @param length the length of the code* @return return -1 if no error, or return the position of the error bit*/bool CheckCode(int code, int length, int& errLoc){if (length <= 9 || length >= 15){return false;}errLoc = 0;int step[4] = { 1, 2, 4, 8 };for (int i = 0; i < 4; ++i){int stepNum = 0;int checkCode = 0;for (int j = step[i] - 1; j < length;){checkCode ^= ((code >> j) & 0x1);++stepNum;if (stepNum % step[i] == 0){j += (step[i] + 1);}else {++j;}}errLoc |= ((checkCode&0x1) << i);}return true;}
}int main()
{int code = 157;int length = 8;int result, reLen;Encode::Hamming26(code, length, result, reLen);cout << "The orignal code " << code << "[" << length << "] ";// display from LSB to MSBfor (int i = 0; i < length; ++ i){cout << ((code & (1 << i)) ? 1 : 0);}cout << endl;cout << "the hamming code " << result << "[" << reLen << "] ";for (int i = 0; i < reLen; ++ i){cout << ((result & (1 << i)) ? 1 : 0);}cout << endl;cout << "now to test the result " << endl;// test and indicate which bit is wrong// notice the binary number should be reversed// when you want to know the decimal valuefor (int i = 0; i < reLen; ++ i){int test = result & ~(1 << i);// result & ( 1 << i);int errLoc;Encode::CheckCode(test,reLen, errLoc);cout << test << " " << errLoc;cout << ' ';}cout << endl;return 0;
}
一个开源的C demo
// ------------------------------------------------------------------------
// File: hamming.c
// Date: August 7, 2000
//
// Encoding and decoding of a Hamming code.
// ------------------------------------------------------------------------
// This program is complementary material for the book:
//
// R.H. Morelos-Zaragoza, The Art of Error Correcting Coding, Wiley, 2002.
//
// ISBN 0471 49581 6
//
// This and other programs are available at http://the-art-of-ecc.com
//
// You may use this program for academic and personal purposes only.
// If this program is used to perform simulations whose results are
// published in a journal or book, please refer to the book above.
//
// The use of this program in a commercial product requires explicit
// written permission from the author. The author is not responsible or
// liable for damage or loss that may be caused by the use of this program.
//
// Copyright (c) 2002. Robert H. Morelos-Zaragoza. All rights reserved.
// ------------------------------------------------------------------------#include <math.h>
#include <stdio.h>
#include <float.h>
#include <limits.h>
#include <stdlib.h>
#include <cstdlib>
#define MAX_RANDOM LONG_MAX // Maximum value of random() int i,j,l,index;
int n, k;
int code[1024];
int red[1024], info[1024];
int m;
int parity[10];
int syn;
int error;int test, result;main(int argc, char *argv[])
{if (argc != 3){printf("Usage: %s m position_error\n", argv[0]);exit(0);}sscanf(argv[1],"%d", &m);sscanf(argv[2],"%d", &error);n = pow(2,m)-1; k = n - m;// Compute parity positionsparity[1] = 1;for (i=2; i<=m; i++)parity[i] = (parity[i-1]<<1) & 0xfffffffe;printf("parity positions: ");for (i=1; i<=m; i++) printf("%2d ", parity[i]); printf("\n");// Generate random messagefor (i=1; i<=k; i++)info[i] = ( random() >> 10) & 0x01;printf("information bits = ");for (j=1; j<=k; j++) printf("%1d", info[j]);printf("\n");// Compute parity bitsfor (j=1; j<=m; j++){red[j] = 0;l = 0;for (i=1; i<=n; i++){// Check that "i" is not a parity position = not a power of 2result = 0;test = 1;for (index=1; index<=m; index++){if (i==test) result = 1;test *= 2;}if (!result){l++;if ( (i>>(j-1)) & 0x01 )red[j] ^= info[l];}}}printf("parity bits = ");for (j=1; j<=m; j++) printf("%1d", red[j]);printf("\n");// Transmit codewordi = 1;l = 1;for (j=1; j<=n; j++)if (j==parity[l] && l<=m){code[j] = red[l]; l++;}else{code[j] = info[i]; i++;}printf("codeword = ");for (j=1; j<=n; j++) printf("%1d", code[j]);printf("\n");// Add a hard errorcode[error] ^= 1;printf("received = ");for (j=1; j<=n; j++) printf("%1d", code[j]);printf("\n");// Compute syndrome syn = 0;for (i=1; i<=n; i++)if (code[i]) syn ^= i;printf("syndrome = %d\n", syn);// Correct error if neededif (syn)code[syn] ^= 1;printf("estimate = ");for (j=1; j<=n; j++) printf("%1d", code[j]);printf("\n");}
没找到很好的算法实现源码,不知道有没有开源,如有开源的请留言