
- •Корректирующие коды Хэмминга
- •Коды Хэмминга. Алгоритм кодирования
- •Коды Хэмминга. Алгоритм декодирования
- •Разработанный проект
- •Проект, разработанный на wpf
- •Режим работы с одним символом
- •Пример кодирования с исправлениями ошибок
- •Пример кодирования сообщения
- •Пример кодирования
- •Параметры кода
- •Исходный код программы
- •Класс, реализующий хранение и вывод информации на форму
- •Главный класс логики
Исходный код программы
Классы, представляющие алфавит
public class Symbol
{
public char Char { get; set; }
public int Code { get; set; }
}
public class Alphabet
{
private List<Symbol> list = new List<Symbol>();
public List<Symbol> Content { get { return list; } set { list = value; } }
public string Header { get; set; }
public void AddSymbol(Symbol sym)
{
list.Add(sym);
}
}
Класс, реализующий хранение и вывод информации на форму
public class Result : INotifyPropertyChanged
{
private Symbol _symb;
private string _hammingCode;
private string _hammingCodeEditable;
private string _controlNumber;
private string _correctedHammingCode;
private char _decodedSymbol;
private int _correctedBit;
private string _decodedCode;
public Symbol Symb
{
get { return _symb; }
set { _symb = value; NotifyPropertyChanged("Symb"); }
}
public string HammingCode
{
get { return _hammingCode; }
set { _hammingCode = value; NotifyPropertyChanged("HammingCode"); }
}
public string HammingCodeEditable
{
get { return _hammingCodeEditable; }
set { _hammingCodeEditable = value; NotifyPropertyChanged("HammingCodeEditable"); }
}
public string ControlNumber
{
get { return _controlNumber; }
set { _controlNumber = value; NotifyPropertyChanged("ControlNumber"); }
}
public string CorrectedHammingCode
{
get { return _correctedHammingCode; }
set { _correctedHammingCode = value; NotifyPropertyChanged("CorrectedHammingCode"); }
}
public string DecodedCode
{
get { return _decodedCode; }
set { _decodedCode = value; NotifyPropertyChanged("DecodedCode"); }
}
public char DecodedSymbol
{
get { return _decodedSymbol; }
set { _decodedSymbol = value; NotifyPropertyChanged("DecodedSymbol"); }
}
public int CorrectedBit
{
get { return _correctedBit; }
set { _correctedBit = value; NotifyPropertyChanged("CorrectedBit"); }
}
// for auto updating
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Главный класс логики
public class BusinessLayer
{
private List<Alphabet> alphabethList = new List<Alphabet>();
private List<List<int>> hammingMatrix;
private bool allowHamming = false;
private List<Result> results;
public List<Result> Results
{
get { return results; }
}
public bool AllowHamming
{
get { return allowHamming; }
}
public List<Alphabet> AlphabethList
{
get { return alphabethList; }
}
public Alphabet SelectedAlphabet
{
get { return selectedAlphabet; }
set { selectedAlphabet = value; }
}
public BusinessLayer()
{
InsertAlphabets();
allowHamming = false;
selectedAlphabet = alphabethList[0];
}
private void InsertAlphabets()
{
var alphabet = new Alphabet {Header = "Roman (a-n)"};
for (var i = 'a'; i <= 'n'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'a') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet { Header = "Roman (a-z)" };
for (var i = 'a'; i <= 'z'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'a') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet { Header = "Roman (o-z)" };
for (var i = 'o'; i <= 'z'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'o') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet {Header = "Cyrillic (а-м)"};
for (var i = 'а'; i <= 'м'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'а') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet { Header = "Cyrillic (о-я)" };
for (var i = 'о'; i <= 'я'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'о') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet { Header = "Cyrillic (а-я)" };
for (var i = 'а'; i <= 'я'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - 'а') });
}
alphabethList.Add(alphabet);
alphabet = new Alphabet { Header = "Numbers (0-9)" };
for (var i = '0'; i <= '9'; i++)
{
alphabet.AddSymbol(new Symbol() { Char = i, Code = (i - '0') });
}
alphabethList.Add(alphabet);
}
private Alphabet selectedAlphabet = null;
public void StartAlgo(bool wholeAlphabet, int selectedAlph, char symbol = ' ')
{
if (wholeAlphabet)
{
selectedAlphabet = alphabethList[selectedAlph];
}
else
{
// find Symbol
var symb = new Symbol();
foreach (var cur in alphabethList[selectedAlph].Content)
{
if (cur.Char == symbol)
{
symb = new Symbol { Char = cur.Char, Code = cur.Code };
}
}
// save symbol
selectedAlphabet = new Alphabet
{
Content = new List<Symbol> { symb },
Header = "Standalone symbol"
};
}
allowHamming = true;
results = new List<Result>();
foreach (var cur in selectedAlphabet.Content)
{
results.Add(new Result {Symb = cur});
}
CodeParameters.SymbolCodeLength = Convert.ToInt32(Math.Ceiling(Math.Log(alphabethList[selectedAlph].Content.Count, 2)));
var codeLength = CodeParameters.SymbolCodeLength;
var tmpStr = "";
for (var i = 0; i < codeLength; i++)
{
tmpStr += "1";
}
CodeParameters.HammingCodeLength = ToHammingCode(tmpStr).Length;
}
private string ToHammingCode(string code)
{
var res = code;
for (var i = 0; i < res.Length; i++)
{
var power = Math.Log(i + 1, 2);
if (Math.Abs(Math.Floor(power) - power) < 0.0000001)
{
res = res.Substring(0, i) + "0" + res.Substring(i);
}
}
return res;
}
private List<int> GetHammingCorrectingIndexes(int length)
{
var res = new List<int>();
for (var i = 0; i < length; i++)
{
var power = Math.Log(i + 1, 2);
if (Math.Abs(Math.Floor(power) - power) < 0.0000001)
{
res.Add(i);
}
}
return res;
}
public void RunHamming()
{
var correctingBits = CodeParameters.HammingCodeLength - CodeParameters.SymbolCodeLength;
// fill hamming matrix
hammingMatrix = new List<List<int>>();
for (var i = 0; i < correctingBits; i++)
{
var row = new List<int>();
for (var j = 1; j <= CodeParameters.HammingCodeLength; j++)
{
row.Add((j & (1<<i)) == 0 ? 0 : 1);
}
hammingMatrix.Add(row);
}
var conv = new IntegerToBinaryConverter();
var curIndex = 0;
foreach (var symbol in selectedAlphabet.Content)
{
var symbolCode = conv.Convert(symbol.Code, null, "Symbol", null).ToString();
var hammingCode = ToHammingCode(symbolCode);
var hammingBits = "";
for (var k = 0; k < correctingBits; k++)
{
var sum = 0;
for (var m = 0; m < CodeParameters.HammingCodeLength; m++)
{
if (hammingMatrix[k][m].ToString() == hammingCode[m].ToString() && hammingCode[m].ToString() == "1") sum++;
}
hammingBits += (sum%2 == 0) ? "0" : "1";
}
var bitIndex = 0;
foreach (var hammingCorrectingIndex in GetHammingCorrectingIndexes(hammingCode.Length))
{
hammingCode = hammingCode.Substring(0, hammingCorrectingIndex) + hammingBits[bitIndex] + ((hammingCorrectingIndex + 1 < hammingCode.Length) ? hammingCode.Substring(hammingCorrectingIndex + 1) : "");
bitIndex++;
}
Results[curIndex].HammingCode = hammingCode;
Results[curIndex].HammingCodeEditable = hammingCode;
curIndex++;
}
}
public void RunDecode()
{
var correctingBits = CodeParameters.HammingCodeLength - CodeParameters.SymbolCodeLength;
var conv = new IntegerToBinaryConverter();
var curIndex = 0;
foreach (var result in Results)
{
if (result.HammingCodeEditable.Length != CodeParameters.HammingCodeLength)
{
MessageBox.Show("Hey! The length of hamming code is wrong!");
return;
}
var hammingBits = "";
var hammingCode = result.HammingCodeEditable;
for (var k = 0; k < correctingBits; k++)
{
var sum = 0;
for (var m = 0; m < CodeParameters.HammingCodeLength; m++)
{
if (hammingMatrix[k][m].ToString() == hammingCode[m].ToString() && hammingCode[m].ToString() == "1") sum++;
}
hammingBits += (sum % 2 == 0) ? "0" : "1";
}
var arr = hammingBits.ToCharArray();
Array.Reverse(arr);
results[curIndex].ControlNumber = new string(arr);
var bitToCorrect = 0;
for (var i = 0; i < hammingBits.Length; i++)
{
bitToCorrect += (hammingBits[i] == '0' ? 0 : 1<<i) ;
}
results[curIndex].CorrectedBit = bitToCorrect;
var correctedHammingCode = hammingCode;
if (bitToCorrect != 0)
{
var bit = correctedHammingCode[bitToCorrect - 1];
correctedHammingCode = correctedHammingCode.Remove(bitToCorrect - 1, 1);
correctedHammingCode = correctedHammingCode.Insert(bitToCorrect - 1, bit == '0' ? "1" : "0");
}
results[curIndex].CorrectedHammingCode = correctedHammingCode;
var receivedSymbolCode = "";
for (var i = 0; i < correctedHammingCode.Length; i++)
{
if (!IsPowOfTwo(i + 1))
{
receivedSymbolCode += correctedHammingCode[i];
}
}
results[curIndex].DecodedCode = receivedSymbolCode;
var receivedChar = '-';
var recievedCharCode = 0;
for (var i = 0; i < receivedSymbolCode.Length; i++)
{
if (receivedSymbolCode[i] == '1')
{
recievedCharCode += 1 << (receivedSymbolCode.Length - i - 1);
}
}
foreach (var symbol in selectedAlphabet.Content)
{
if (symbol.Code == recievedCharCode) receivedChar = symbol.Char;
}
results[curIndex].DecodedSymbol = receivedChar;
curIndex++;
}
}
private bool IsPowOfTwo(int a)
{
var cnt = 0;
while (a > 0)
{
if ((a & 1) == 1) cnt++;
a >>= 1;
}
return (cnt == 1);
}
}
Выводы
В результате выполнения лабораторной работы была разработана программа для кодирования и декодирования посредством кодов Хэмминга.
Данный код позволяет исправлять одну ошибку в передаваемых блоках. Также он может обнаружить двойную ошибку, но проблема состоит в том, что двойная ошибка интерпретируется как одинарная, а после ее "исправления" мы почти всегда попадаем на другую разрешенную комбинацию.
Три и более ошибки код Хэмминга фиксировать не способен, т.к. минимальное кодовое расстояние равно 3, т.е. после изменения 3-х или более битов мы почти всегда попадаем на другую разрешенную комбинацию.
Здесь правильнее сказать, что мы можем с определенной вероятностью диагностировать множественную ошибку, если вдруг попадем на запрещенную комбинацию. К сожалению, только диагностировать. Т.е. приемнику снова придется запрашивать пересылку куска данных, где была обнаружена ошибка.