Кодирование сигнала

advertisement
Кодирование сигнала
Кодирование сигнала – это его представление в определенной форме,
удобной или пригодной для последующего использования сигнала. Говоря
строже, это правило, описывающее отображение одного набора знаков в
другой набор знаков. Тогда отображаемый набор знаков называется
исходным алфавитом, а набор знаков, который используется для
отображения, - кодовым алфавитом, или алфавитом для кодирования. При
этом кодированию подлежат как отдельные символы исходного алфавита,
так и их комбинации. Аналогично для построения кода используются как
отдельные символы кодового алфавита, так и их комбинации. Например,
дана таблица соответствия между натуральными числами трех систем
счисления, аналогичная рассмотренной ранее. Эту таблицу можно
рассматривать как некоторое правило, описывающее отображение набора
знаков десятичной системы счисления в двоичную и шестнадцатеричную.
Тогда исходный алфавит - десятичные цифры от 0 до 9, а кодовые алфавиты это 0 и 1 для двоичной системы; цифры от 0 до 9 и символы {A, B, C, D, E, F}
- для шестнадцатеричной.
Кодовой комбинацией, или, короче, кодом называется совокупность
символов кодового алфавита, применяемых для кодирования одного символа
(или одной комбинации символов) исходного алфавита. При этом кодовая
комбинация может содержать один символ кодового алфавита. Исходным
символом называется символ (или комбинация символов) исходного
алфавита, которому соответствует кодовая комбинация. Например,
поскольку 8 = 10002 и 8 является исходным символом, 1000 - это кодовая
комбинация, или код, для числа 8. В то же время 8 - это исходный символ.
Совокупность кодовых комбинаций называется кодом. Взаимосвязь
символов (или комбинаций символов, если кодируются не отдельные
символы) исходного алфавита с их кодовыми комбинациями составляет
таблицу соответствия (или таблицу кодов).
Следует отметить, что понятие “код” омонимично: оно может
употребляться и в смысле кодовой комбинации, и в приведенном выше
смысле. Аналогично, понятие “кодовая комбинация” синонимично понятию
“код”.
Обратная процедура получения исходных символов по кодам
символов называется декодированием. Очевидно, для выполнения
правильного декодирования код должен быть однозначным, т.е. одному
исходному символу должен соответствовать точно один код и наоборот.
В зависимости от целей кодирования, различают следующие его
виды:
1.
кодирование по образцу - используется всякий раз при вводе
информации в компьютер для ее внутреннего представления;
криптографическое кодирование, или шифрование, – используется,
когда нужно защитить информацию от несанкционированного доступа;
3.
эффективное, или оптимальное, кодирование – используется для
устранения избыточности информации, т.е. снижения ее объема,
например, в архиваторах;
2.
4.
помехозащитное, или помехоустойчивое, кодирование – используется
для обеспечения заданной достоверности в случае, когда на сигнал
накладывается помеха, например, при передаче информации по каналам
связи.
Коды по образцу
Данный вид кодирования применяется для представления
дискретного сигнала на том или ином машинном носителе.
Большинство кодов, используемых в информатике для кодирования
по образцу, имеют одинаковую длину и используют двоичную систему для
представления кода (и, возможно, шестнадцатеричную как средство
промежуточного представления).
Рассмотрим виды таких кодов: прямые; ASCII-коды; коды Грея;
коды, учитывающие частоту символов; код Штибица
Прямые коды
Применяются для представления в ЭВМ числовых данных и
используют двоичную систему счисления.
Примером прямого кода для семнадцати натуральных десятичных
чисел является соответствующий фрагмент таблицы. Эти коды имеют
переменную длину, что неудобно для их обработки. Для получения кодов
постоянной длины кодовые комбинации дополняются незначащими нулями.
Тогда получим прямые коды постоянной длины для семнадцати первых
натуральных десятичных чисел. Они показаны в таблице:
Числа Прямые
коды
0
00000
1
00001
2
00010
3
00011
4
00100
5
00101
6
00110
7
00111
8
9
10
11
12
13
14
15
16
01000
01001
01010
01011
01100
01101
01110
01111
10000
Прямые коды могут использоваться для кодирования и нечисловых
данных.
Пример 1. Построить двоичные коды для символов a, b, c, d.
Пронумеруем исходные символы, начиная с нуля, и по таблице
сформируем двоичные коды для номеров символов. Тогда двоичные коды
исходных символов примут вид:
Исходные
символы
a
b
c
d
Номер Двоичные
коды
0
0
1
1
2
10
3
11
Для получения двоичного кода постоянной длины добавим
незначащие нули к кодовым комбинациям для a и b. Получим:
Исходные
символы
a
b
c
d
Двоичные
коды
00
01
10
11
Пример 2. С помощью полученной таблицы закодировать
сообщение (дискретный сигнал) "abba".
Результат: abba = 00010100.
ASCII-коды
Наиболее распространенным является код ASCII (American Standard
Code for Information Interchange), который используется для внутреннего
представления символьной информации в операционной системе MS DOS, в
Блокноте операционной системы Windows’xx, а также для кодирования
текстовых файлов в Интернет. Структура кода представлена в таблице
(обозначения столбцов и строк выделены полужирно).
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
2
!
"
#
$
%
&
'
(
)
*
+
,
.
/
3
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
4
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
5
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
6
'
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
7
р
q
r
s
t
u
v
w
x
y
z
{
|
}
~
¤
8
А
Б
В
Г
Д
Е
Ж
З
И
Й
К
Л
М
Н
О
П
9
Р
С
Т
У
Ф
Х
Ц
Ч
Ш
Щ
Ъ
Ы
Ь
Э
Ю
Я
A
а
б
в
г
д
е
ж
з
и
й
к
л
м
н
о
п
B
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
C
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
D
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
E
р
с
т
у
ф
х
ц
ч
ш
щ
ъ
ы
ь
э
ю
я
F
Ё
ё
Є
є
Ї
ї
Ў
ў
°
∙
·
√
№
¤
■
Таблица кодов содержит 16 столбцов и 16 строк; каждая строка и
столбец пронумерованы в шестнадцатеричной системе счисления цифрами
от 0 до F. Шестнадцатеричное представление ASCII-кода складывается из
номера столбца и номера строки, в которых располагается символ. Так,
например, ASCII-код символа 1 есть число 3116, что по правилам перевода
означает 1100012. В двоичной системе код представляется восемью
разрядами, т.е. двоичный ASCII-код символа 1 есть 001100012.
Данная таблица делится на две части: столбцы с номерами от 0 до 7
составляют стандарт кода – неизменяемую часть; столбцы с номерами от 8
до F являются расширением кода и используются, в частности, для
кодирования символов национальных алфавитов. В столбцах с номерами 0 и
1 находятся управляющие символы, которые используются, в частности, для
управления принтером. Столбцы с номерами от 2 до 7 содержат знаки
препинания, арифметических действий, некоторые служебные символы, а
также заглавные и строчные буквы латинского алфавита. Расширение кода
включает символы псевдографики, буквы национальных алфавитов и другие
символы.
В приведенной таблице в качестве национального выбран русский
алфавит. Пустые ячейки означают, что они не используются, а ячейки с
многоточием содержат символы, которые умышленно не показаны.
Пример 1. С помощью таблицы ASCII-кодов закодировать
сообщение "группа", используя шестнадцатеричное представление кода.
Результат: A3 E0 E3 AF AF A0 (для простоты коды символов
разделены пробелами)
Коды Грея
Часто бывает необходимым, чтобы лексикографически (т.е. по
алфавиту или по возрастанию) упорядоченные символы при двоичном
кодировании различались минимальным количеством разрядов. Коды,
удовлетворяющие этому условию, называются кодами Грея или
одношаговыми кодами. В таблице приведены значения кода Грея для
десятичных цифр (для сравнения также указан их прямой код, значения
которого тоже упорядочены).
Цифра Прямой Код
код
Грея
0
0000
0000
1
0001
0001
2
0010
0011
3
0011
0010
4
0100
0110
5
0101
0111
6
0110
0101
7
0111
0100
8
1000
1100
9
1001
1101
Как видно, коды лексикографически (в данном случае, по
значению) упорядоченных цифр 1 и 2 в случае кода Грея различаются одним
двоичным разрядом, а прямые коды этих же цифр – двумя разрядами.
Аналогичную картину можно наблюдать в случае пар цифр 3 и 4; 5 и 6; 7 и 8.
Для формирования кода Грея можно использовать следующую
последовательность действий:
Шаг 1) код Грея для 0 и 1 равен 02 и 12, соответственно;
Шаг 2) для построения кодов Грея для десятичных чисел 2 и 3
построим таблицу, в которой для нумерации строк и столбцов использованы
коды Грея для чисел 0 и 1 (обозначение строк и столбцов выделены серым
фоном):
номера столбцов
0
1
номера 0 0
1
строк 1 3
2
В ячейках таблицы размещены кодируемые десятичные числа,
включая и уже закодированные 0 и 1. Стрелки показывают направление
перемещения по ячейкам для формирования кода одного из чисел (само
число указано в ячейке). Тогда код Грея для произвольного числа,
размещенного в некоторой ячейке, формируется как номер строки и номер
столбца для этой ячейки. Так, код Грея для числа 3 – это 102, а для числа 2 –
112. Поскольку код Грея имеет постоянную длину, сформированные ранее
коды для чисел 0 и 1 пополняются незначащими нулями, т.е. код Грея для 0 –
это 002, а для 1 – это 012;
Шаг 3) получив коды Грея для четырех десятичных чисел,
используем их в качестве номеров строк и столбцов, чтобы сформировать
кодовые комбинации для первых шестнадцати десятичных цифр:
00
01
11
10
00
0
7
8
15
01
1
6
9
14
11
2
5
10
13
10
3
4
11
12
Так, например, для получения кода числа 9 выписывают
обозначения строки и столбца: соответственно, 11 и 01. Тогда получаем код:
для числа 15 кодом будет комбинация 1000, для числа 11 – 1110 и т.д.
Поскольку переход от числа 15 к 0 также является одношаговым
(эти числа имеют коды, соответственно, 1000 и 0000), построенный код
называют также циклически одношаговым;
Шаг 4) для формирования кода Грея для множества
последовательных натуральных чисел, начинающихся с нуля, в количестве
2m строят таблицу размером mxm и нумеруют строки и столбцы в
соответствии с кодами Грея, построенными на предыдущих этапах для m
чисел. Получают коды Грея в соответствии с рассмотренными схемами.
Следует отметить, что таблицы для кода Грея не обязательно
квадратные: число строк и столбцов могут не совпадать.
Пример 1. Построить код Грея для алфавита, который используется
при записи фамилии "Шеннон". При этом не различать строчные и
прописные буквы.
Сформирует исходный алфавит, для которого будем строить код.
Это множество символов {е, н, о, ш}. Отметим, что символы в множестве
упорядочены по алфавиту. Тогда построим таблицу размером 2х2, введем
обозначения строк и столбцов и разместим в ячейках символы алфавита.
Получим:
0 1
0е н
1шо
Тогда коды Грея: е - 00, н - 01, о - 11, ш - 10.
Пример 2. Закодировать фамилию "Шеннон" построенным в
примере 1 кодом Грея (строчные и прописные буквы не различаются).
Получаем: 10 00 01 01 11 01 (коды символов для простоты
разделены пробелами).
Назад
Коды, учитывающие частоту символов
В некоторых системах кодирования значение кода определяется
частотой кодируемого символа. Как правило, такие частоты известны для
букв алфавитов естественных языков, например, английского или русского, и
используются уже давно при размещении клавиш клавиатуры: наиболее
часто используемые буквы располагаются на клавишах в середине
клавиатуры, наиболее редко используемые – на периферии, что создает
удобство работы для человека.
Учет частоты символов позволяет строить “экономные” для
техники коды постоянной длины. Например, условимся, что двоичная
единица технически реализуется включенной лампочкой накаливания (как
это и было в первых ламповых компьютерах), а двоичный ноль –
выключенной лампочкой. Пусть также известны частоты букв русского
алфавита, и в соответствии с этой частотой буквам назначены коды (мы
умышленно задались неполным алфавитом русского языка), показанные в
таблице.
Буква Частота Коды
о
0,090 0001
е
0,072 0010
а
0,062 0100
и
0,062 1000
я
0,018 0011
ы
0,016 0101
Первые четыре кода содержат по одной единице, следующие два – по
две. Коды строятся с таким условием, чтобы они различались для
последующего декодирования: коды, содержащие одинаковое количество
единиц, различаются их позицией.
Очевидно, чем больше частота исходного символа, тем меньше в
соответствующем коде единиц, т.е. тем меньше включенных лампочек
применяется для представления символа в компьютере, а значит меньше
тратится электроэнергии.
Код Штибица
Для внутреннего представления отрицательного числа -х в
информатике традиционно используется дополнительный код, который
облегчает выполнение арифметических операций над отрицательными
числами (это будет рассмотрено далее).
Код Штибица (или код плюс-3) используется для кодирования
десятичных чисел для простого перехода от двоичного значения числа к его
дополнению.
Для построения кода Штибица используется понятие прямого
целочисленного эквивалента двоичного кода – это десятичное число,
соответствующее двоичному коду. Тогда код Штибица – это сдвинутый на 3
прямой код: чтобы получить представляемое данным двоичным кодом число,
надо из прямого целочисленного эквивалента вычесть 3.
В таблице приведены значения кода Штибица для десятичных цифр
(для сравнения также указан их прямой код).
Исходная Прямой
Код
цифра
код Штибица
0
0000
0011
1
0001
0100
2
0010
0101
3
0011
0110
4
0100
0111
5
0101
1000
6
0110
1001
7
0111
1010
8
1000
1011
9
1001
1100
В этом коде используется понятие взаимно дополнительных пар
чисел: это такие числа, при сложении двоичных значений которых
получается двоичное число, состоящее только из единиц. Примером таких
пар чисел могут служить 0 и 9, 1 и 8 и т.д.
Криптографические коды
Криптографические коды используются для защиты сообщений от
несанкционированного доступа, потому называются также шифрованными.
В качестве символов кодирования могут использоваться как символы
произвольного алфавита, так и двоичные коды.
Существуют различные методы, рассмотрим два из них: метод простой
подстановки и метод Вижинера.
Метод простой подстановки
Простейшим случаем криптографического кодирования является
простая подстановка: каждому исходному символу ставится в соответствие
произвольный символ кодирования из какого-либо другого алфавита или из
того же исходного – получается таблица соответствия. Тогда в кодируемом
сообщении выполняется замена символов в соответствии с полученной
таблицей.
Пример 1. Пусть исходным является русский алфавит. Составим
таблицу соответствия, используя служебные символы, знаки препинания и
знаки арифметических действий из таблицы ASCII- кодов в качестве
кодового алфавита:
А Б В Г Д Е Ё Ж З И Й К Л М Н О П РС Т УФ Х Ц Ч Ш Щ Э
Ю Я Ь Ъ Ы
! №$ % & * ( ) { } [ ] - | = ” ’ ~ ` : ; _ < > ^ • ↑ →
↓ ← ± ? ¤
Тогда сообщение ИНФОРМАТИКА будет закодировано как
}=_”~|!:}]!
.
Данный метод кодирования является ненадежным, так как при
достаточно большой выборке закодированных сообщений при известных
частотах символов исходного алфавита можно с определенной долей
погрешности выполнить декодирование. В самом деле, пусть есть
представительная выборка закодированных русскоязычных сообщений,
общее число букв в которых равно M, и известны частоты букв русского
алфавита:
Буква
О
Е(Ё)
А
И
Т
Н
С
Р
В
Частота
0,090
0,072
0,062
0,062
0,053
0,053
0,045
0,040
0,038
Буква
М
Д
П
У
Я
Ы
З
Ъ,Ь
Б
Частота
0,026
0,025
0,023
0,021
0,018
0,016
0,016
0,014
0,014
Буква
Й
Х
Ж
Ю
Ш
Ц
Щ
Э
Ф
Частота
0,010
0,009
0,007
0,006
0,006
0,004
0,003
0,003
0,001
Л
0,035
Г
0,013
К
0,028
Ч
0,012
пробелы и 0,175
знаки
препинания
Можно рассчитать частоту каждого символа s – fS :
fS = mS /M,
где mS – количество символов S в сообщениях.
Тогда получив частоты и сопоставив их с приведенной таблицей,
можно определить исходный текст.
Пример 2. Пусть есть закодированное сообщение из примера 1:
}=_”~|!:}]!. Известно, что до кодирования оно было составлено из букв
русского алфавита. Требуется декодировать его, используя в качестве
представительной выборки закодированных русскоязычных текстов
настоящее учебное пособие, предварительно выполнив все замены русских
букв символами из таблицы соответствия примера 1.
Воспользуемся встроенными средствами текстового процессора
WINWORD для определения требуемых статистических данных.
Так определим, что общее число символов М в учебном пособии на
момент подготовки данного примера составляет 275979.
Определяем, сколько раз встречаются интересующие нас символы
из закодированного сообщения - ms:
символ
}
=
_
"
~
|
!
:
]
s
ms
18716 14396 1436 22027 12058 8503 16835 13426 6592
Это позволяет рассчитать частоты символов fs по приведенной
выше формуле:
символ }
=
_
"
~
|
!
:
]
s
fs
0,068 0,052 0,005 0,078 0,044 0,031 0,061 0,049 0,024
Сопоставим полученные данные с приведенной выше таблицей
частот символов. Наиболее близкие по значению символы для полученных
частот показаны ниже:
символ s
}
=
_
" ~ |
!
:
]
подходящий Е,А.И Т,Н Ю,Ш,Ц Е,О С,Р Л,К А,И Т,Н,С Д,П
символ
Таким образом, кодовые символы из закодированного сообщения
могут быть заменены символами из соответствующего множества
подходящих символов.
Если построить все возможные сочетания символов из указанных
множеств, там будет, в частности и сочетание вида И Н * О Р * А Т И * А,
где знак * означает любой символ из соответствующего, определенного
выше, множества исходных символов (в случае * декодирование, очевидно,
выполнено неверно). Если предъявить полученную строку человеку или
автомату, способному распознать русское слово, зашифрованное сообщение
можно считать декодированным.
Очевидно, декодирование также возможно при известной таблице
соответствия
Метод Вижинера
Разрушить статистические зависимости в закодированных
сообщениях и тем самым повысить надежность кодирования можно с
помощью метода Вижинера. Алгоритм применения этого метода приведен
ниже:
1) символы исходного алфавита нумеруются, начиная с нуля,
например:
АБВГДЕЖЗИКЛ М Н О П Р С Т У Ф Х Ц Ч Ш ЩЭ ЮЯ Ь
Ъ Ы
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
29 30
Получают таблицу соответствия;
2) задаются ключом кодирования – словом в исходном алфавите,
например, АСУ;
3) выписывают сообщение, подлежащее кодированию, например,
пусть это будет сообщение ИНФОРМАТИКА, и выполняют следующие
шаги:
а) под каждым его символом записывают порядковый номер из
таблицы соответствия:
И Н Ф О Р М А Т И КА
8 12 19 13 15 11 0 17 8 9 0
б) под сообщением выписывают ключевое слово, а под символами
ключа выписывают их порядковые номера из таблицы соответствия:
А С У А С У А С У АС
0 16 18 0 16 18 0 16 18 0 16
в) порядковые номера символов складываются по модулю, равному
числу символов исходного алфавита (в нашем случае – 31):
8 28 6 13 0 29 0 2 26 9 16
Напомним, что сложение по модулю (обозначается ⊕) выполняется
без переноса единицы переноса в старший разряд. Так мы получили при
сложении по модулю 31, например, чисел 17 и 16 (сумма равна 33, что на 2
превышает модуль 31) значение 2;
4) полученный числовой ряд преобразуется в символы исходного
алфавита по таблице соответствия. Так имеем:
И Ь Ж О А Ъ А В Ю К С.
Очевидно, что статистика не поможет декодировать это сообщение,
поскольку повторяются совсем не те символы, что в исходном сообщении.
Для декодирования подобных сообщений требуется таблица
соответствия и ключ. Тогда выполняют описанные выше процедуры
кодирования в обратном порядке. Сложность может представлять только
операция вычитания с учетом модуля. При этом следует помнить, что не
должны получаться отрицательные значения. Если такое происходит, нужно
занять число, соответствующее модулю.
Пример 1. Декодировать сообщение И Ь Ж О А Ъ А В Ю К С,
задавшись ключом АСУ и зная таблицу соответствия.
Решение:
а) выписываем под закодированным сообщением порядковые
номера символов из таблицы соответствия (см. выше):
И Ь Ж О А Ъ А ВЮКС
8 28 6 13 0 29 0 2 26 9 16
б) выписываем под сообщением ключ с порядковыми номерами
символов:
А С У А С У АС УА С
0 16 18 0 16 18 0 16 18 0 16
в) вычитаем с учетом модуля 31 из чисел в закодированном
сообщении числа для ключа:
8 12 19 13 15 11 0 17 8 9 0
г) преобразуем числа в символы по таблице соответствия:
ИН Ф О Р М АТ И К А
При декодировании возникла сложность в получении кодов
символов Т, Ф, Р. В самом деле, при вычитании из 2 числа 16 получалось –
14. Тогда к 2 прибавили модуль 31, получили 33 и уже из 33 вычли 16.
Получили 17 – порядковый номер символа Т. Аналогично поступили и с
символами Ф и Р.
Эффективное кодирование
Этот вид кодирования используется для уменьшения объемов
информации на носителе - сигнале.
Для кодирования символов исходного алфавита используют
двоичные коды переменной длины: чем больше частота символа, тем короче
его код. Эффективность кода определяется средним числом двоичных
разрядов для кодирования одного символа – lср по формуле
где k – число символов исходного алфавита;
ns – число двоичных разрядов для кодирования символа s;
fs – частота символа s; причем
При эффективном кодировании существует предел сжатия, ниже
которого не «спускается» ни один метод эффективного кодирования - иначе
будет потеряна информация. Этот параметр определяется предельным
значением двоичных разрядов возможного эффективного кода – lпр:
где n – мощность кодируемого алфавита,
fi – частота i-го символа кодируемого алфавита.
Существуют два классических метода эффективного кодирования:
метод Шеннона-Фано и метод Хаффмена. Входными данными для обоих
методов является заданное множество исходных символов для кодирования с
их частотами; результат - эффективные коды
Метод Шеннона-Фано
Этот метод требует упорядочения исходного множества символов по не
возрастанию их частот. Затем выполняются следующие шаги:
а) список символов делится на две части (назовем их первой и второй
частями) так, чтобы суммы частот обеих частей (назовем их Σ1 и Σ2) были
точно или примерно равны. В случае, когда точного равенства достичь не
удается, разница между суммами должна быть минимальна;
б) кодовым комбинациям первой части дописывается 1, кодовым
комбинациям второй части дописывается 0;
в) анализируют первую часть: если она содержит только один символ,
работа с ней заканчивается, – считается, что код для ее символов построен, и
выполняется переход к шагу г) для построения кода второй части. Если
символов больше одного, переходят к шагу а) и процедура повторяется с
первой частью как с самостоятельным упорядоченным списком;
г) анализируют вторую часть: если она содержит только один символ,
работа с ней заканчивается и выполняется обращение к оставшемуся списку
(шаг д). Если символов больше одного, переходят к шагу а) и процедура
повторяется со второй частью как с самостоятельным списком;
д) анализируется оставшийся список: если он пуст – код построен,
работа заканчивается. Если нет, – выполняется шаг а).
Пример 1. Даны символы a, b, c, d с частотами fa = 0,5; fb = 0,25; fc =
0,125; fd = 0,125. Построить эффективный код методом Шеннона-Фано.
Сведем исходные данные в таблицу, упорядочив их по невозрастанию
частот:
Исходные
символы
a
b
c
d
Частоты
символов
0,5
0,25
0,125
0,125
Первая линия деления проходит под символом a: соответствующие
суммы Σ1 и Σ2 равны между собой и равны 0,5. Тогда формируемым кодовым
комбинациям дописывается 1 для верхней (первой) части и 0 для нижней
(второй) части. Поскольку это первый шаг формирования кода, двоичные
цифры не дописываются, а только начинают формировать код:
Исходные
символы
a
b
c
d
Частоты
символов
0,5
0,25
0,125
0,125
Формируемый
код
1
0
0
0
В силу того, что верхняя часть списка содержит только один элемент
(символ а), работа с ней заканчивается, а эффективный код для этого символа
считается сформированным (в таблице, приведенной выше, эта часть списка
частот символов выделена заливкой).
Второе деление выполняется под символом b: суммы частот Σ1 и Σ2
вновь равны между собой и равны 0,25. Тогда кодовой комбинации символов
верхней части дописывается 1, а нижней части – 0. Таким образом, к
полученным на первом шаге фрагментам кода, равным 0, добавляются новые
символы:
Исходные
символы
a
b
c
d
Частоты
символов
0,5
0,25
0,125
0,125
Формируемый
код
1
01
00
00
Поскольку верхняя часть нового списка содержит только один символ
(b), формирование кода для него закончено (соответствующая строка
таблицы вновь выделена заливкой).
Третье деление проходит между символами c и d: к кодовой
комбинации символа c приписывается 1, коду символа d приписывается 0:
Исходные
символы
a
b
c
d
Частоты
символов
0,5
0,25
0,125
0,125
Формируемый
код
1
01
001
000
Поскольку обе оставшиеся половины исходного списка содержат по
одному элементу, работа со списком в целом заканчивается.
Таким образом, получили коды:
a
-
1,
b
-
01,
c
-
001,
d
-
000.
Определим эффективность построенного кода по формуле:
lср = 0,5*1 + 0,25*01 + 0,125*3 + 0,125*3 = 1,75.
Поскольку при кодировании четырех символов кодом постоянной
длины требуется два двоичных разряда, сэкономлено 0,25 двоичного разряда
в среднем на один символ.
Метод Хаффмена
Этот метод имеет два преимущества по сравнению с методом
Шеннона-Фано: он устраняет неоднозначность кодирования, возникающую
из-за примерного равенства сумм частот при разделении списка на две части
(линия деления проводится неоднозначно), и имеет, в общем случае,
большую эффективность кода.
Исходное множество символов упорядочивается по не возрастанию
частоты и выполняются следующие шаги:




1) объединение частот:
две последние частоты списка складываются, а соответствующие
символы исключаются из списка;
оставшийся после исключения символов список пополняется суммой
частот и вновь упорядочивается;
предыдущие шаги повторяются до тех пор, пока ни получится единица
в результате суммирования и список ни уменьшится до одного символа;
2) построение кодового дерева:
строится двоичное кодовое дерево: корнем его является вершина,
полученная в результате объединения частот, равная 1; листьями –
исходные вершины; остальные вершины соответствуют либо
суммарным, либо исходным частотам, причем для каждой вершины
левая подчиненная вершина соответствует большему слагаемому, а

правая – меньшему; ребра дерева связывают вершины-суммы с
вершинами-слагаемыми. Структура дерева показывает, как происходило
объединение частот;
ребра дерева кодируются: каждое левое кодируется единицей, каждое
правое – нулем;
3) формирование кода: для получения кодов листьев (исходных
кодируемых символов) продвигаются от корня к нужной вершине и
«собирают» веса проходимых ребер.
Пример 1. Даны символы a, b, c, d с частотами fa = 0,5; fb = 0,25; fc
= 0,125; fd= 0,125. Построить эффективный код методом Хаффмена.
1) объединение частот (результат объединения двух последних
частот в списке выделен в правом соседнем столбце заливкой):
Исходные Частоты fs Этапы объединения
символы
первый второй третий
a
0,5
0,5
0,5
1
b
0,25
0,25
0,5
c
0,125
0,25
d
0,125
2) построение кодового дерева:
3) формирование кода:
a
1;
b
01;
c
001;
d
000.
Как видно, полученные коды совпадают с теми, что были
сформированы методом Шеннона-Фано, следовательно, они имеют
одинаковую эффективность
Повышение эффективности кодирования
Повысить эффективность кодирования можно, строя код не для
символа, а для блоков из n символов, причем частота блока рассчитывается
как произведение частот символов, входящих в блок. Рассмотрим этот тезис
на примере.
Пример 1. Даны символы a и b с частотами, соответственно, 0,9 и
0,1. Построить эффективный код методом Шеннона-Фано для блоков из двух
символов (n = 2).
Сформируем список возможных блоков и их частот. При этом
частоту блока будем рассчитывать как произведение частот символов,
входящих в блок. Тогда имеем:
Блоки исходных
Частоты блоков
символов
aa
0,81
ab
0,09
ba
0,09
bb
0,01
Построение кода сведем в таблицу:
Блоки
исходных
символов
aa
ab
Частоты Этапы построения кода
блоков первый второй третий
0,81
0,09
1
0
ba
bb
0,09
0,01
0
0
код построен
1
код
построен
0
1
0
0
Таким образом, получены коды:
aa
1;
ab
01;
ba
001;
bb
000.
Определим эффективность построенного кода. Для этого
рассчитаем сначала показатель эффективности для блока символов:
lср блока = 0,81*1 + 0,09*2 + 0,09*3 + 0,01*3 = 1,28.
Поскольку в блоке 2 символа (n=2), для одного символа lср = lср блока/2
= 1,28/2 = 0,64.
При посимвольном кодировании для эффективного кода
потребуется по одному двоичному разряду. В самом деле, применение
метода Шеннона-Фано дает результат, представленный в таблице:
Исходные Частоты Построение
символы символов
кода
a
0,9
1
b
0,1
0
Таким образом, при блочном кодировании выигрыш составил 1 0,64 = 0,36 двоичных разрядов на один кодируемый символ в среднем.
Эффективность блочного кодирования тем выше, чем больше
символов включается в блок.
Адаптивные алгоритмы сжатия. Кодирование Хаффмена
Является практичным, однопроходным, не требующим передачи таблицы
кодов. Его суть в использовании адаптивного алгоритма, т.е. алгоритма,
который при каждом сопоставлении символу кода, кроме того, изменяет
внутренний ход вычислений так, что в следующий раз этому же символу
может быть сопоставлен другой код, т.е. происходит адаптация алгоритма к
поступающим для кодирования символам. При декодировании происходит
аналогичный процесс.
В начале работы алгоритма дерево кодирования содержит только один
специальный символ, всегда имеющий частоту 0. Он необходим для
занесения в дерево новых символов: после него код символа передается
непосредственно. Обычно такой символ называют escape-символом, <ESC>.
Расширенный ASCII кодируют каждый символ 8-битным числом, т.е. числом
от 0 до 255. При построении дерева кодирования необходимо для
возможности правильного декодирования как-то упорядочивать структуру
дерева. Расположим листья дерева в порядке возрастания частот и затем в
порядке возрастания стандартных кодов символов. Узлы собираются слева
направо без пропусков. Левые ветви помечаются 0, а правые - 1.
Рассмотрим процесс построения кодов по адаптивному алгоритму Хаффмена
для сообщения ACCBCAAABC, которое соответствует выборке 10-и
значений д.с.в. из 2-го примера на построение неадаптивного кода
Хаффмена:
Здесь L1(ACCBCAAABC)=4.1 бит/сим. Если не использовать сжатия, то
L1(ACCBCAAABC)=8 бит/сим. Для рассматриваемой д.с.в. ранее были
получены значения
бит/сим и
бит/сим. С ростом
длины сообщения среднее количество бит на символ сообщения при
адаптивном алгоритме кодирования будет мало отличаться от значения,
полученного при использовании неадаптивного метода Хаффмена или
Шеннона-Фэно, т.к. алфавит символов ограничен и полный код каждого
символа нужно передавать только один раз.
Теперь рассмотрим процесс декодирования сообщения
'A'0'C'100'B'1001010100101. Здесь и далее символ в апостофах означает
восемь бит, представляющих собой запись двоичного числа, номера символа,
в таблице ASCII+. В начале декодирования дерево Хаффмена содержит
только escape-символ с частотой 0. С раскодированием каждого нового
символа дерево заново перестраивается.
Выбранный способ адаптации алгоритма очень неэффективный, т.к. после
обработки каждого символа нужно перестраивать все дерево кодирования.
Существуют гораздо менее трудоемкие способы, при которых не нужно
перестраивать все дерево, а нужно лишь незначительно изменять.
Бинарное дерево называется упорядоченным, если его узлы могут быть
перечислены в порядке неубывания веса и в этом перечне узлы, имеющие
общего родителя, должны находиться рядом, на одном ярусе. Причем
перечисление должно идти по ярусам снизу-вверх и слева-направо в каждом
ярусе.
На рис. 5.1 приведен пример упорядоченного дерева Хаффмена.
Рис. 5.1.
Если дерево кодирования упорядоченно, то при изменении веса
существующего узла дерево не нужно целиком перестраивать - в нем
достаточно лишь поменять местами два узла: узел, вес которого нарушил
упорядоченность, и последний из следующих за ним узлов меньшего веса.
После перемены мест узлов необходимо пересчитать веса всех их узловпредков.
Например, если в дереве на рис. 5.1 добавить еще две буквы A, то узлы A и D
должны поменяться местами (См. рис. 5.2).
Рис. 5.2.
Если добавить еще две буквы A, то необходимо будет поменять местами
сначала узел A и узел, родительский для узлов D и B, а затем узел E и узелбрат E (рис.6).
Рис. 5.3.
Дерево нужно перестраивать только при появлении в нем нового узла-листа.
Вместо полной перестройки можно добавлять новый лист справа к листу
<ESC> и упорядочивать, если необходимо, полученное таким образом
дерево.
Процесс работы адаптивного алгоритма Хаффмена с упорядоченным
деревом можно изобразить следующей схемой:
Адаптивное арифметическое кодирование
Для арифметического кодирования, как и для кодирования методом
Хаффмена, существуют адаптивные алгоритмы. Реализация одного из них
запатентована фирмой IBM.
Построение арифметического кода для последовательности символов из
заданного множества можно реализовать следующим алгоритмом. Каждому
символу сопоставляется его вес: вначале он для всех равен 1. Все символы
располагаются в естественном порядке, например, по возрастанию.
Вероятность каждого символа устанавливается равной его весу, деленному
на суммарный вес всех символов. После получения очередного символа и
постройки интервала для него, вес этого символа увеличивается на 1 (можно
увеличивать вес любым регулярным способом).
Рис. 5.4.
Заданное множество символов - это, как правило, ASCII+. Для того, чтобы
обеспечить остановку алгоритма распаковки вначале сжимаемого сообщения
надо поставить его длину или ввести дополнительный символ-маркер конца
сообщения. Если знать формат файла для сжатия, то вместо начального
равномерного распределения весов можно выбрать распределение с учетом
этих знаний. Например, в текстовом файле недопустимы ряд управляющих
символов и их вес можно занулить.
Пример. Пусть заданное множество - это символы A, B, C. Сжимаемое
сообщение - ACCBCAAABC. Введем маркер конца сообщения - E.
Кодирование согласно приведенному алгоритму можно провести согласно
схеме, приведенной на рис. 5.4.
Вследствие того, что
Поэтому L1(ACCBCAAABC)=2.2 бит/сим. Результат, полученный
адаптивным алгоритмом Хаффмена - 4.1 бит/сим, но если кодировать буквы
не 8 битами, а 2, то результат будет 2.3 бит/сим. В первой строчке схемы
выписаны суммарные веса символов, а во второй - длины текущих отрезков.
Способ распаковки адаптивного арифметического кода почти аналогичен
приведенному для неадаптивного. Отличие только в том, что на втором шаге
после получения нового кода нужно перестроить разбиение единичного
отрезка согласно новому распределению весов символов. Получение маркера
конца или заданного началом сообщения числа символов означает окончание
работы.
Пример. Распакуем код 0010111001010011101101, зная, что множество
символов сообщения состоит из A, B, C и E, причем последний - это маркер
конца сообщения.
Download