Вы находитесь на странице: 1из 6

Неидеальные каналы

Ранее мы говорили о кодах, устраняющих избыточность данных – избыточность


в кодировании отдельных символов (Хаффмана, Шеннона-Фано) и в кодировании
групп символов (LZ- семейство). Однако, избыточность может быть и полезной – в
разговоре по телефону мы можем не услышать значительную часть букв,
произносимых собеседником, но разобрать сказанное – благодаря избыточности
нашей речи. Здесь используется избыточность естественного языка, сложившаяся
сама собой, но мы можем добавлять избыточность в код специально, по
определённым алгоритмам, обеспечивающим исправление как можно большего
числа ошибок при как можно меньшем количестве дополнительных символов.
Простейшим используемым кодом, обнаруживающим ошибки, является
добавление бита чётности (здесь мы будем употреблять слово «бит» в смысле
«двоичная единица», а не только в смысле единицы измерения количества
информации, т.к. такова сложившаяся терминология) – на каждые несколько бит
данных передаётся дополнительный бит, такой, чтобы сумма единиц в пакете
данных была чётной или, что то же самое, XOR всех битов пакета был равен нулю.
Проверка правильности пакета происходит очень просто и быстро. Однако, такой код
позволяет определить только единичные ошибки, если ошибок было две, бит
чётности окажется «правильным». И только определить наличие единичной ошибки
в пакете – не указать конкретное место, и тем самым исправить ошибку (указать
ошибочный бит и значит его исправить), верно определить исходные данные – как в
примере с разговором по телефону выше.
Идея насчёт «указать конкретное место ошибки – значит исправить её»
довольно интересна. Уже бит чётности отчасти локализует ошибку – если бит
чётности приходится на каждые бит (включая сам бит чётности!), то он, по крайней
мере, позволяет указать, в каких блоках длиной в сообщении, содержащем много
таких блоков, есть ошибка. Но хотелось бы локализовать ошибку вплоть до одного
конкретного бита. Может быть, добавлять бит чётности к каждому биту сообщения?
Увы, это не поможет – как сказано выше, локализация происходит с точностью до
группы битов включая бит чётности. Допустим, мы получили 10 (один, допустим,
первый, бит данных, другой – чётности) – да, мы видим, что ошибка есть. Но где – в
бите данных или чётности? Было 00 или 11?
Если добавить ещё один бит, т.е. кодировать каждый бит данных – тремя, то мы
получим нужный результат - будем 0 кодировать тремя нулями 000, а 1 – 111, тогда
любая одна (!) ошибка может быть исправлена (попробуйте поменять любой один
бит в данных кодах, вы увидите, что результат всё ещё будет «ближе» к
правильному коду, чем к неправильному – у 000 с ошибкой останется два нуля, у 111
с ошибкой две единицы), Заметьте, кстати, мы говорим и будем говорить здесь об
«ошибках замены», когда один бит заменяется другим, но не об ошибках вставки или
выпадения, когда само количество бит меняется.
Но делать код длиннее втрое очень уж неэкономно. Можно ли «локализовать»
неправильный бит как-то иначе?
А сколько вообще нужно бит, чтобы локализовать (указать номер) конкретного
бита в цепочке? Ну, это мы знаем, для того, чтобы указать конкретный объект из
нужно бит (8 объектов можно пронумеровать числом из 3 бит, 16 объектов – 4
бита и т.д.).
А как именно 3 бита, например, локализуют один из восьми объектов?
Расположим мысленно объекты справа налево (как мы нумеруем биты в байте) от
нулевого до седьмого, т.е. 76543210. Тогда, если старший бит из 3-битового номера
равен 0, то искомый объект имеет номер 0, 1, 2 или 3, т.е. находится в правой
четвёрке. Если старший бит равен 1 – в левой. Аналогично, если средний бит
номера равен 0 (при любых значениях двух других), то искомый объект имеет номер
0, 1 либо 4, 5, т.е. находится в правой паре одной из четвёрок (четвёрку выбирает
старший бит), и аналогично, младший бит выбирает правый (если 0) или левый
(если 1) объект в одной из пар: 76, 54, 32 или 10. Иными словами, каждый бит
номера «выбирает» 4 объекта из 8, а номер в целом – тот, который лежит на
пересечении всех выбранных отдельными битами групп.
Один бит чётности на бит, включая сам бит чётности, может показать, есть ли
ошибка в данной группе длиной бит.
Можем ли мы разбить блок длиной бит (включая и биты данных, и биты
чётности) на пересекающиеся группы, как четвёрки объектов из примера выше,
каждая из которых будет контролироваться одним битом чётности, так, чтобы
бит с ошибкой лежал на пересечении групп, помеченных как ошибочные своим
битом чётности?
Иными словами, сможем ли мы всё-таки использовать биты чётности для
точной локализации (а значит, исправления) ошибочного бита?
И если да, сколько проверочных битов должно быть в таком блоке длины и
как именно разбить блок на группы, чтобы число проверочных бит было
минимально?
И нам ещё нужна одна комбинация битов чётности, показывающая, что
ошибок нет,

Ответ: да, в этом состоит идея кодов Хэмминга.

Для начала ответим на вопрос о количестве проверочных битов. Как сказано


выше, для точной локализации одного из объектов нужно бит, так что если у
нас есть «локализующих» битов, они смогут локализовать (максимум) один из
битов в блоке кода. Однако, нам нужна ещё одна комбинация из этих битов,
указывающая, что ошибок нет, так что проверочных битов чётности могут
локализовать (и исправить) один из битов (включающих как информационные
биты, так и сами биты чётности!), либо указать, что ни в одном из этих битов
ошибок нет. Поэтому блоки кода Хэмминга составляют битов, где -
натуральное число, большее (при мы бы получили по формуле выше блоки
нулевой длины, что не имеет особого смысла, а при мы получаем блоки длины
из которых бит данных – тот самый 3-битный код для 1-битных данных, о
котором мы писали выше).
Теперь второй вопрос – а как лучше группировать биты блока по проверочным
битам чётности – т.е. какие именно биты данных будут контролироваться первым
битом чётности, какие вторым, какие третьим и т.д.? Давайте вспомним, как мы
проверяем правильность блока с помощью бита чётности. Мы делаем XOR всех
битов блока и бита чётности блока и смотрим, равен ли результат нулю (всё
верно) или единице. Выполняя данную операцию в нашем коде с несколькими
битами чётности, каждый – для одной из пересекающихся групп битов блока – мы
получим несколько битов результата XOR. Удобнее всего – построить код так, чтобы
эти биты результата складывались просто в номер ошибочного бита! Т.е. сделать
так, чтобы, если мы получили при проверке 0,1,1, это означало, что ошибка в 3-м
бите. Так и устроены коды Хэмминга (можно распределять биты и по-другому, но это
достаточно удобный вариант).
Биты результата XOR называются синдромом полученной
последовательности.
Для примера, для -битного блока кода Хэмминга ( проверочных бита,
бита данных, ), чтобы синдром складывался в номер ошибочного бита,
нужно чтобы биты синдрома вычислялись как

биты, как обычно нумеруем от нулевого, здесь - биты данных, - биты


чётности, тогда биты составляют номер ошибочного бита. Для этого биты
чётности строят как

Подчеркнём, что такое построение кода – чтобы (например, 3) проверочных


битов локализовали ошибочный бит из (например, 7) – возможно. Это важно
потому что количество информации в информации об одном из 8 вариантов (7
вариантов ошибочного бита либо нет ошибок) равно 3 битам, и это максимум,
который могут нести 3 двоичные цифры. Так что в коде Хэмминга добавочные
двоичные единицы данных добавляют в код ровно столько информации, сколько
добавлено двоичных единиц.

Итак, для получения блока кода нам надо из битов данных получить
битов готового блока. Преобразование строки чисел (в данном случае -
однобитовых) в другую строку обычно описывается матрицами – умножением
вектора-строки на матрицу, или матрицы на вектор-столбец – если преобразование
линейно. Преобразования в кодах Хэмминга линейны – и получение проверочных
битов, и вычисление синдрома. Поэтому описание кода Хэмминга и множества
других кодов, которые так и называются – линейные, часто опирается на матричную
алгебру.
Кстати, при использовании матриц проверочные биты ещё и окажутся на
определённых местах в блоке кода.
Например, если биты данных в примере выше записать в виде вектора-строки
, а биты чётности в виде вектора-строки , то матрица,
генерирующая код по данным, согласно равенствам выше будет следующей
,

здесь операция суммирования при вычислении результата умножения понимается


как XOR – суммирование по модулю 2. Так, например, умножение строки слева на
пятый (считая от первого слева направо) столбец матрицы даст элемент строки-
результата , согласно равенствам
выше.
Обратите внимание, поскольку длина кода и длина исходных данных разные, в
теории кодирования широко используются не квадратные матрицы.
Суммирование, и вообще арифметические операции по модулю – то что мы все
делаем, когда говорим про время. Если встреча назначена на 2 часа после 11, то во
сколько встреча? В 1 час. по модулю 12. Вычисление по модулю играет
важную роль во всех случаях, когда число используемых нами символов или чисел
не бесконечно. В теории кодирования мы обычно имеем дело с конечным
алфавитом символов, так что операции над ними совершаются по модулю – по
модулю, равному их количеству. Напомню, что результат операции по модулю
можно найти, если выполнить обычную арифметическую операцию, а потом найти
остаток от деления результата на модуль.
Для двух символов – 0 и 1 сложение по модулю два совпадает с операцией xor.

Коды Хэмминга позволяют исправить ошибку в блоке полученных данных. Одну


ошибку. Что насчёт большего числа ошибок?
Как код вообще исправляет или обнаруживает ошибки?
Допустим, мы передаём пары бит – 00, 01, 10 или 11, может быть передан
любой вариант. Пока будем считать, что при передаче возможны только одиночные
ошибки. Допустим, мы получили 01. Можем ли мы сказать, правильные мы получили
данные или ошибочные? Нет! Потому что могла быть передана любая комбинация –
и полученные нами 01, и 00 (с ошибкой во втором бите) и 11 с ошибкой в первом.
А вот если бы комбинации 00 и 11, т.е. отличающиеся в одном бите от 01 были
«запрещены» - отсутствовали в правильных комбинациях, которые могли быть
переданы, мы могли бы точно сказать, что произошла ошибка.

Для того, чтобы код мог обнаружить ошибку, комбинации битов, образуемые из
правильных данных при ошибке, должны быть «запрещены» - отсутствовать в
исходных вариантах данных.
В случае одиночных ошибок это значит – должны быть запрещены все
комбинации бит, отличающиеся в одном бите от правильных.
Количество бит, в которых две последовательности бит отличаются друг
от друга, называется расстоянием по Хэммингу между последовательностями.
Т.е. для того, чтобы код мог обнаружить единичную ошибку, должны быть
запрещены все комбинации, находящиеся на расстоянии 1 по Хэммингу от
правильных комбинаций.
Или, то же самое другими словами – правильные комбинации кода должны
находиться друг от друга на расстоянии не меньше 2 по Хэммингу.
Простейший код с битом чётности работал потому что любые комбинации,
отличающиеся в одном бите, т.е. находящиеся на расстоянии 1 от правильных,
имели нечётное число единиц и были «запрещены».

Чтобы код мог обнаружить две ошибки, правильные комбинации кода должны
находиться друг от друга на расстоянии, большем двух по Хэммингу и т.д.
Т.е. для того, чтобы код обнаруживал не менее ошибок на блок при передаче
минимальное расстояние между любыми двумя правильными комбинациями кода
должно быть

Чем больше мы хотим обнаруживать ошибок, тем больше комбинаций нужно


выкинуть из правильных в коде, тем меньше комбинаций у нас останется, а значит,
тем больше блоков придётся передать для передачи того же количества
информации.
В обычной геометрии точки, находящиеся на расстоянии меньше и равном
данного от выбранной точки называются шаром вокруг данной точки (кругом в
плоскости). Также и для комбинаций битов все комбинации, находящиеся на
расстоянии по Хэммингу и меньшем называются точками шара радиуса вокруг
данной комбинации.
Так что все ошибочные комбинации, получающиеся из данной правильной при
ошибках и менее лежат в шаре радиуса вокруг данной правильной комбинации.
Что происходит, если другая комбинация находится на расстоянии от
данной? Их ошибочные комбинации оказываются на пересечении их шаров радиуса
(но сами они в шары друг друга не попадают). Так что если мы получаем
ошибочную комбинацию из этого пересечения, мы знаем, что она ошибочна, но не
знаем от какой правильной комбинации она образовалась – она принадлежит обоим
шарам. А значит, не можем однозначно заменить её на правильную – исправить.
Что нужно, чтобы код мог исправлять не менее ошибок в блоке? Не просто
обнаруживать, но исправлять?
Нужно, чтобы их шары радиуса , содержащие ошибочные точки, не
пересекались. Два шара не пересекаются, если расстояние между центрами больше
двух радиусов. У нас расстояния дискретны, так что «больше» означает «как
минимум на единицу».
Для того, чтобы код мог исправить до ошибок в блоке, нужно, чтобы
минимальное расстояние по Хэммингу между правильными кодовыми комбинациями
было равно

Задачи

1. Для некоторого канала среднее число бит на одну ошибку передачи равно 8
(т.е. на каждые 8 бит приходится, в среднем одна ошибка). Если вы хотите
разместить 1 бит чётности на блок, содержащий в среднем 1 ошибку, сколько битов
данных будет в одном блоке?

2. Найти число бит на блок в коде Хэмминга для числа контрольных бит ,
. Сколько битов данных будет в блоке?
3. Найти выражения для через из матричного произведения в
тексте.

4. Чему равно
а) 3 + 3 по модулю 5; б) 3 + 5 по модулю 8; в) 1 – 2 по модулю 12;
г) 1 – 0, 0 – 1, 0 – 0 и 1 – 1 по модулю 2. Сравнить со сложением тех же
значений.

5. Каким должно быть минимальное расстояние по Хэммингу между


допустимыми кодовыми комбинациями из 10 бит, чтобы код мог обнаружить до 3
ошибок? Исправить до 2 ошибок? Сколько ошибок сможет обнаружить второй код?

Вам также может понравиться