海明纠错码工作原理

海明纠错码

海明码(Hamming Code)是一个可以有多个校验位,具有检测并纠正一位错误代码的纠错码,所以它也仅用于信道特性比较好的环境中,如以太局域网中,因为如果信道特性不好的情况下,出现的错误通常不是一位。

海明码的检错、纠错基本思想是将有效信息按某种规律分成若干组,每组安排一个校验位进行奇偶性测试,然后产生多位检测信息,并从中得出具体的出错位置,最后通过对错误位取反(也是原来是1就变成0,原来是0就变成1)来将其纠正。

要采用海明码纠错,需要按以下步骤来进行:

  1. 计算校验位数
  2. 确定校验码位置
  3. 确定校验码
  4. 实现校验和纠错

摘自 茶乡浪子

1. 计算校验位数

要使用海明码纠错,首先就要确定发送的数据所需要要的校验码(也就是“海明码”)位数(也称“校验码长度”)。它是这样的规定的:假设用N表示添加了校验码位后整个信息的二进制位数,用K代表其中有效信息位数,r表示添加的校验码位,它们之间的关系应满足:

N = K + r ≤ 2 r - 1 N=K+r \le 2^r-1 N=Kr2r1

如K=5,则要求 2 r − r ≥ 5 + 1 = 6 2^r-r≥5+1=6 2rr5+1=6,根据计算可以得知r的最小值为4,也就是要校验5位信息码,则要插入4位校验码。如果信息码是8位,则要求 2 r − r ≥ 8 + 1 = 9 2^r-r \ge 8+1=9 2rr8+1=9,根据计算可以得知r的最小值也为4。

信息码位数与校验码位数之间的关系

信息码位数12~45~1112~2627~5758~120121~247
校验码位数2345678

2.确定校验码位置

上一步我们确定了对应信息中要插入的校验码位数,但这还不够,因为这些校验码不是直接附加在信息码的前面、后面或中间的,而是分开插入到不同的位置。但不用担心,校验码的位置很容易确定的,那就是校验码必须是在 2 n 2^n 2n 次方位置,如第1、2、4、8、16、32,……位(对应20、21、22、23、24、25,……,是从最左边的位数起的),这样一来就知道了信息码的分布位置,也就是非 2 n 2^n 2n 次方位置,如第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,因现在还没有求出各位校验码值,现在这些校验码位都用“?”表示,最终的码字为:??10011101

3. 确定校验码

这些校验码的值不是随意的,每个校验位的值代表了代码字中部分数据位的奇偶性(最终要根据是采用奇校验,还是偶校验来确定),其所在位置决定了要校验的比特位序列。总的原则是:第i位校验码从当前位开始,每次连续校验 2 n − 1 2^{n-1} 2n1位后再跳过i位,然后再连续校验 2 n − 1 2^{n-1} 2n1位,再跳过 2 n − 1 2^{n-1} 2n1位,以此类推。最后根据所采用的是奇校验,还是偶校验即可得出第 n n n位校验码的值。如下表示意:原文

数据位位置1234567891011121314151617181920...
编码后数据位置p1p2d1p4d2d3d4p8d5d6d7d8d9d10d11p16d12d13d14d15
奇偶校验位
覆盖率
p1XXXXXXXXXX
p2XXXXXXXXXX
p4XXXXXXXXX
p8XXXXXXXX
p16XXXXX
3.1 计算方法1

对每组数字位通过奇偶校验的方式来依次确定校验位的值。比如使用偶校验,校验位的值使用每组中1的个数为偶数,对组内已有数字进行异或运算得到校验位的值

3.1 计算方法2

对11000010进行汉明编码,求编码后的码字。

  1. 列出表格,从左往右(或从右往左)填入数字,但2的次方的位置不填。

    位置1234567891011121314
    数据11000010
  2. 把数据行有1的列的位置写为二进制。

    位置1234567891011121314
    数据11000010
    二进制001101011011
  3. 收集所有二进制数字,求异或。 0011 ⊕ 0101 ⊕ 1011 = 1101 0011\oplus 0101 \oplus 1011=1101 001101011011=1101

  4. 把1101依次填入表格中2的次方的位置(低位在左)。

    位置1234567891011121314
    数据11000010
    二进制001101011011
    校验1011
  5. 所以编码后的码字是101110010010。

4. 校验与纠错

把以上这些校验码所校验的位分成对应的组,则在接收端的对各校验位再进行逻辑“异或运算”,如果采用的是偶校验,正常情况下均为0。

如果最终发现只是一个校验组中的校验结果不符,则直接可以知道是对应校验组中的校验码在传输过程中出现了差错,因为所有校验码所在的位是只由对应的校验码进行校验;如果发现多组校验结果不正确,则查看这些组中公共校验的数据位(只有数据位才可能被几个校验码进行校验),以最终确定是哪个数据位出了差错(海明码只能检查一位出错);最后,对所找到的出错数据位取反即可实现纠错。

如计算出的每组的校验结果为p1、p2、p3、p4,均为0则正确,有一个不为0的则出错的位置在 p 1 + 10 ∗ p 2 + 100 ∗ p 3 + 1000 ∗ p 4 p1+10*p2+100*p3+1000*p4 p1+10p2+100p3+1000p4的位置处

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 MSB
    for (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 value
    for (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 positions
  parity[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 message
  for (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 bits
  for (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 2
      result = 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 codeword
  i = 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 error
  code[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 needed
  if (syn)
    code[syn] ^= 1;

  printf("estimate = ");
  for (j=1; j<=n; j++) printf("%1d", code[j]);
  printf("\n");

}

没找到很好的算法实现源码,不知道有没有开源,如有开源的请留言

  • 14
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
海明码工作原理是通过在数据中添加冗余比特位来实现检错和纠错的功能。其中,每个比特位都有其对应的位置编号,比如第1、2、4、8、16位等。对于每一个比特位,都有多个冗余比特位与之对应,这些冗余比特位的编号是采用二进制表示的,例如第1个比特位对应的冗余比特位编号为1、3、5、7,这些编号中的每一个都可以表示为二进制形式下的1。 在发送方进行编码时,首先将数据按照一定规则进行分组,通常是按照一定的字节长度进行分组。然后,对每一个数据组都进行冗余比特位的计算,具体的计算方式是将原始数据中的某些比特位进行异或运算,并将结果作为冗余比特位添加到数据中。这样,就得到了一个完整的带有冗余比特位的数据包,可以通过网络进行传输。 在接收方进行解码时,首先进行检错,即检查是否有比特位发生错误。检错的方式是将接收到的数据中的每个比特位与相应的冗余比特位进行异或运算,如果发现某些冗余比特位和实际计算结果不一致,则说明这个比特位发生了错误。通过这种方式,可以快速地检测出哪些数据发生了错误。 如果发现错误,则海明码会利用冗余比特位进行纠错。具体的纠错方式是,根据冗余比特位的值,确定哪些比特位发生了错误,并进行修正。例如,如果冗余比特位的值为1,而实际计算结果为0,那么说明这个比特位发生了错误,需要将其修正为1。 最终,接收方将解码后的数据传送至应用程序中进行处理。通过这种方式,海明码能够有效地检测和纠正数据传输中的错误,提高了数据传输的可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

callinglove

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

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

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

打赏作者

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

抵扣说明:

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

余额充值