В данной публикации будет рассматриваться линейно групповой код, как один из представителей систематических корректирующих кодов и предложена его реализация на C++.
Что из себя представляет из себя корректирующий код. Корректирующий код – это код направленный на обнаружение и исправление ошибок. А систематические коды — Это коды, в которых контрольные и информационные разряды размещаются по определенной системе. Одним из таких примеров может служить Код Хэмминга или собственно линейно групповые коды.
Линейно групповой код состоит из информационных бит и контрольных. Например, для исходной комбинации в 4 символа, линейно групповой код будет выглядеть вот так:
|1100|110|
Где первые 4 символа это наша исходная комбинация, а последние 3 символа это контрольные биты.
Общая длина линейно группового кода составляет 7 символов. Если число бит исходной комбинации нам известно, то чтобы вычислить число проверочных бит, необходимо воспользоваться формулой:
$$display$$d=log(n+1+log(n+1))$$display$$
Где n — это число информационных бит, то есть длина исходной комбинации, и log по основанию 2. И общая длина N кода будет вычисляться по формуле:
$$display$$N=n+d$$display$$
Допустим исходная комбинация будет составлять 10 бит.
$$display$$d=log(10+1+log(10+1))$$display$$
$$display$$d=3,867$$display$$
d всегда округляется в большую сторону, и d=4.
И полная длина кода будет составлять 14 бит.
Разобравшись с длиной кода, нам необходимо составить производящую и проверочную матрицу.
Производящая матрица, размерностью N на n, где N — это длина линейно группового кода, а n — это длина информационной части линейно группового кода. По факту производящая матрица представляет из себя две матрицы: единичную размерностью m на m, и матрицу контрольных бит размерностью d на n. Если единичная матрица составляется путём расставления единиц по главной диагонали, то составление «контрольной» части матрицы имеет некоторые правила. Проще объяснить на примере. Мы возьмем уже известную нам комбинацию из 10 информационных битов, но добавим коду избыточность, и добавим ему 5-ый контрольный бит. Матрица будет иметь размерность 15 на 10.
1 0 0 0 0 0 0 0 0 0 1 1 1 1 1
0 1 0 0 0 0 0 0 0 0 1 1 1 1 0
0 0 1 0 0 0 0 0 0 0 1 1 1 0 1
0 0 0 1 0 0 0 0 0 0 1 1 0 1 1
0 0 0 0 1 0 0 0 0 0 1 0 1 1 1
0 0 0 0 0 1 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 1 0 0 1 1 0 0 1
0 0 0 0 0 0 0 0 1 0 1 0 0 1 1
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1
«Контрольная» часть составляется по схеме уменьшения двоичного числа и соблюдения минимального кодового расстояния между строками: в нашем случае это 11111, 11110, 11101…
Минимальное кодовое расстояние для комбинации будет вычисляться по формуле:
Wp=r+s
Где r – это ранг обнаруживаемой ошибки, а s – ранг исправляемой ошибки.
В нашем случае ранг исправляемой и обнаруживаемой ошибки 1.
Также необходимо составить проверочную матрицу. Она составляется путём транспонирования «контрольной» части и после неё добавляется единичная матрица размерности d на d.
1 1 1 1 1 0 1 1 1 0 1 0 0 0 0
1 1 1 1 0 1 1 1 0 1 0 1 0 0 0
1 1 1 0 1 1 1 0 0 0 0 0 1 0 0
1 1 0 1 1 1 0 0 1 1 0 0 0 1 0
1 0 1 1 1 1 0 1 1 1 0 0 0 0 1
Составив матрицы, мы уже можем написать линейно групповой код, путём суммирования строк производящей матрицы под номерами ненулевых бит исходного сообщения.
Рассмотрим этот этап на примере исходного сообщения 1001101010.
Линейно групповой код: 100110101011100
Сразу обозначим, что контрольные разряды в ЛГК определяются по правилам чётности суммы соответствующих индексов, в нашем случае, эти суммы составляют: 5,3,3,4,4. Следовательно, контрольная часть кода выглядит: 11100.
В результате мы составили линейно групповой код. Однако, как уже говорилось ранее, линейно групповой код имеет исправляющую способность, в нашем случае, он способен обнаружить и исправить одиночную ошибку.
Допустим, наш код был отправлен с ошибкой в 6-ом разряде. Для определения ошибок в коде служит, уже ранее составленная проверочная матрица
Для того, чтобы определить, в каком конкретно разряде произошла ошибка, нам необходимо узнать «синдром ошибки». Синдром ошибки вычисляется методом проверок по ненулевым позициям проверочной матрицы на чётность. В нашем случае этих проверок пять, и мы проводим наше полученное сообщение через все эти проверки.
$$display$$S1=n1+n2+n3+n4+n5+n7+n8+n9+n11$$display$$
$$display$$S2=n1+n2+n3+n4+n6+n7+n8+n10+n12$$display$$
$$display$$S3=n1+n2+n3+n5+n6+n7+n13$$display$$
$$display$$S4=n1+n2+n4+n5+n6+n9+n10+n14$$display$$
$$display$$S5=n1+n3+n4+n5+n6+n8+n9+n10+n15$$display$$
Получив двоичное число, мы сверяем его со столбцами проверочной матрицы. Как только находим соответствующий «синдром», определяем его индекс, и выполняем инверсию бита по полученному индексу.
В нашем случае синдром равен: 01111, что соответствует 6-му разряду в ЛГК. Мы инвертируем бит и получаем корректный линейно групповой код.
Декодирование скорректированного ЛГК происходит путём простого удаления контрольных бит. После удаления контрольных разрядов ЛГК мы получаем исходную комбинацию, которая была отправлена на кодировку.
В заключение можно сказать, что такие корректирующие коды как линейно групповые коды, Код Хэмминга уже достаточно устарели, и в своей эффективности однозначно уступят своим современным альтернативам. Однако они вполне справляются с задачей познакомится с процессом кодирования двоичных кодов и методом исправления ошибок в результате воздействия помех на канал связи.
Реализация работы с ЛГК на C++:
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <cctype>
#include <cmath>
using namespace std;
int main()
{
setlocale(LC_ALL, "Russian");
cout<<"Производящая матрица:"<<endl;
int matr [10][15]={{1,0,0,0,0,0,0,0,0,0,1,1,1,1,1},{0,1,0,0,0,0,0,0,0,0,1,1,1,1,0},{0,0,1,0,0,0,0,0,0,0,1,1,1,0,1},{0,0,0,1,0,0,0,0,0,0,1,1,0,1,1},{0,0,0,0,1,0,0,0,0,0,1,0,1,1,1},
{0,0,0,0,0,1,0,0,0,0,0,1,1,1,1},{0,0,0,0,0,0,1,0,0,0,1,1,1,0,0},{0,0,0,0,0,0,0,1,0,0,1,1,0,0,1},{0,0,0,0,0,0,0,0,1,0,1,0,0,1,1},{0,0,0,0,0,0,0,0,0,1,0,1,0,1,1}};
for(int i=0;i<10;i++)
{
for(int j=0;j<15;j++)
{
cout<<matr[i][j]<<' ';
}
cout<<endl;
}
cout<<"Проверочная матрица:"<<endl;
int matr_2 [5][15]={{1,1,1,1,1,0,1,1,1,0,1,0,0,0,0},{1,1,1,1,0,1,1,1,0,1,0,1,0,0,0},{1,1,1,0,1,1,1,0,0,0,0,0,1,0,0},{1,1,0,1,1,1,0,0,1,1,0,0,0,1,0},{1,0,1,1,1,1,0,1,1,1,0,0,0,0,1}};
for(int i=0;i<5;i++)
{
for(int j=0;j<15;j++)
{
cout<<matr_2[i][j]<<' ';
}
cout<<endl;
}
cout<<"Введите комбинацию: "<<endl;
string str;
bool flag=false;
while(flag!=true)
{
cin>>str;
if(str.size()!=10)
{
cout<<"Недопустимая размерность строки!"<<endl;
flag=false;
}
else
flag=true;
}
vector <int> arr;
for(int i=0;i<str.size();i++)
{
if(str[i]=='1')
arr.push_back(1);
else if(str[i]=='0')
arr.push_back(0);
}
cout<<"Ваша комбинация: ";
for(int i=0;i<arr.size();i++)
cout<<arr[i];
cout<<endl;
vector <int> S;
vector <vector<int>> R;
for(int i=0;i<10;i++)
{
if(arr[i]==1)
{
vector <int> T;
for(int j=0;j<15;j++)
{
T.push_back(matr[i][j]);
}
R.push_back(T);
}
}
cout<<endl;
cout<<"Суммиирвоание строк для построения группового кода: "<<endl;
for(vector <vector<int>>::iterator it=R.begin();it!=R.end();it++)
{
copy((*it).begin(),(*it).end(),ostream_iterator<int>(cout,"t"));
cout<<"n";
}
cout<<endl;
vector <int> P;
for(int i=0; i<15;i++)
{
int PT=0;
for(int j=0; j<R.size();j++)
{
PT+=R[j][i];
}
P.push_back(PT);
}
for(int i=10; i<15;i++)
{
if(P[i]%2==0)
P[i]=0;
else if(P[i]%2!=0)
P[i]=1;
}
cout<<endl<<"Групповой линейный код: "<<endl;
for(int i=0; i<P.size();i++)
{
cout<<P[i]<<' ';
}
int rand_i;
rand_i=5;
cout<<endl<<"В сообщении сгенерирована ошибка: ";
if(P[rand_i]==0)
P[rand_i]=1;
else if(P[rand_i]==1)
P[rand_i]=0;
for(int i=0; i<P.size();i++)
{
cout<<P[i]<<' ';
}
int S1, S2, S3, S4, S5;
//Проверки на чётность
S1=P[0]+P[1]+P[2]+P[3]+P[4]+P[6]+P[7]+P[8]+P[10];
S2=P[0]+P[1]+P[2]+P[3]+P[5]+P[6]+P[7]+P[9]+P[11];
S3=P[0]+P[1]+P[2]+P[4]+P[5]+P[6]+P[12];
S4=P[0]+P[1]+P[3]+P[4]+P[5]+P[8]+P[9]+P[13];
S5=P[0]+P[2]+P[3]+P[4]+P[5]+P[7]+P[8]+P[9]+P[14];
//Составление синдрома
if(S1%2==0)
{
S1=0;
}
else if(S1%2!=0)
{
S1=1;
}
if(S2%2==0)
{
S2=0;
}
else if(S2%2!=0)
{
S2=1;
}
if(S3%2==0)
{
S3=0;
}
else if(S3%2!=0)
{
S3=1;
}
if(S4%2==0)
{
S4=0;
}
else if(S4%2!=0)
{
S4=1;
}
if(S5%2==0)
{
S5=0;
}
else if(S5%2!=0)
{
S5=1;
}
cout<<endl<<"Синдром ошибки: "<<S1<<S2<<S3<<S4<<S5<<endl;
int mas_s[5]={S1,S2,S3,S4,S5};
int index_j=0;
bool flag_s=false;
for(int i=0;i<15;i++)
{
if((matr_2[0][i]==mas_s[0])&&(matr_2[1][i]==mas_s[1])&&(matr_2[2][i]==mas_s[2])&&(matr_2[3][i]==mas_s[3])&&(matr_2[4][i]==mas_s[4]))
{
index_j=i;
}
}
cout<<endl<<"Разряд ошибки: "<<index_j+1<<endl;
if(P[index_j]==0)
P[index_j]=1;
else if(P[index_j]==1)
P[index_j]=0;
cout<<"Исправленный код: ";
for(int i=0; i<P.size();i++)
{
cout<<P[i]<<' ';
}
cout<<endl;
P.erase(P.begin()+14);
P.erase(P.begin()+13);
P.erase(P.begin()+12);
P.erase(P.begin()+11);
P.erase(P.begin()+10);
cout<<"Исходный код: ";
for(int i=0; i<P.size();i++)
{
cout<<P[i]<<' ';
}
cout<<endl;
return 0;
}
Источники:
1. StudFiles – файловый архив студентов [Электронный ресурс] studfiles.net/preview/4514583/page:2/.
2. Задачник по теории информации и кодированию [Текст] / В.П. Цымбал. – Изд. объед. «Вища школа», 1976. – 276 с.
3. Тенников, Ф.Е. Теоретические основы информационной техники / Ф.Е. Тенников. – М.: Энергия, 1971. – 424 с.
Автор: lFeater