Скалярное квантование является процессом, который преобразует все входы в заданную область в общее значение. Этот процесс преобразует входы в другой области значений значений в другое общее значение. В эффект скалярное квантование оцифровывает аналоговый сигнал. Квантование определяют два параметра: раздел и кодовая книга.
Разбиение квантования задает несколько смежных, непересекающиеся области значений значений в наборе вещественных чисел. Чтобы задать раздел в MATLAB® окружение, перечислите различные конечные точки различных областей значений в векторе.
Например, если раздел разделяет действительную числовую линию на четыре набора
{x: x ≤ 0}
{x: 0 < x ≤ 1}
{x: 1 < x ≤ 3}
{x: 3 < x}
тогда можно представлять разбиение как трехэлементный вектор
partition = [0,1,3];
Длина вектора разбиения на один меньше, чем количество интервалов разбиения.
Кодовая книга сообщает квантователю, какое общее значение следует присвоить входам, которые попадают в каждую область значений раздела. Представьте кодовую книгу как вектор, чья длина совпадает с количеством интервалов разбиения. Для примера, вектор
codebook = [-1, 0.5, 2, 3];
является одной возможной кодовой книгой для раздела [0,1,3]
.
quantiz
функция также возвращает вектор, который сообщает, в каком интервале находится каждый вход. Для примера в выход ниже сказано, что значения входа находятся в пределах интервалов, обозначенных 0, 6 и 5, соответственно. Здесь 0-й интервал состоит из вещественных чисел, меньших или равных 3; 6-й интервал состоит из вещественных чисел больше 8, но меньше или равен 9; и 5-й интервал состоит из вещественных чисел, больше 7, но меньше или равно 8.
partition = [3,4,5,6,7,8,9]; index = quantiz([2 9 8],partition)
Это выход
index = 0 6 5
Если вы продолжаете этот пример, определяя вектор кодовой книги, такой как
codebook = [3,3,4,5,6,7,8,9];
затем приведенное ниже уравнение связывает вектор index
к квантованному сигналу quants
.
quants = codebook(index+1);
Эта формула для quants
именно то, что quantiz
function использует, если вместо этого описать пример более кратко, как показано ниже.
partition = [3,4,5,6,7,8,9]; codebook = [3,3,4,5,6,7,8,9]; [index,quants] = quantiz([2 9 8],partition,codebook);
Квантование искажает сигнал. Можно уменьшить искажения, выбрав соответствующие параметры разбиения и кодовой книги. Однако тестирование и выбор параметров для больших наборов сигналов с тонкой схемой квантования может быть утомительным. Одним из способов легкого создания параметров разделов и кодовых книг является их оптимизация в соответствии с набором так называемых обучающих данных.
Примечание
Обучающие данные, которые вы используете, должны быть типичными для видов сигналов, которые вы фактически будете квантовать.
lloyds
функция оптимизирует раздел и кодовую книгу согласно алгоритму Ллойда. Приведенный ниже код оптимизирует разбиение и кодовую книгу для одного периода синусоидального сигнала, начиная с грубого начального предположения. Затем он использует эти параметры, чтобы квантовать исходный сигнал, используя начальные параметры догадки, а также оптимизированные параметры. Этот выход показывает, что среднее квадратное искажение после квантования намного меньше для оптимизированных параметров. quantiz
функция автоматически вычисляет среднее квадратное искажение и возвращает его как третий выходной параметр.
% Start with the setup from 2nd example in "Quantizing a Signal." t = [0:.1:2*pi]; sig = sin(t); partition = [-1:.2:1]; codebook = [-1.2:.2:1]; % Now optimize, using codebook as an initial guess. [partition2,codebook2] = lloyds(sig,codebook); [index,quants,distor] = quantiz(sig,partition,codebook); [index2,quant2,distor2] = quantiz(sig,partition2,codebook2); % Compare mean square distortions from initial and optimized [distor, distor2] % parameters.
Это выход
ans = 0.0148 0.0024
Квантование в разделе Квантование Сигнала не требует априорного знания о переданном сигнале. На практике можно часто делать образованные догадки о настоящем сигнале на основе прошлых передач сигнала. Использование таких образованных догадок, чтобы помочь квантовать сигнал, известно как прогнозирующее квантование. Наиболее распространенным методом прогнозирующего квантования является дифференциальная импульсно код модуляция (DPCM).
Функции dpcmenco
, dpcmdeco
, и dpcmopt
может помочь вам реализовать прогнозирующий квантователь DPCM с линейным предиктором.
Чтобы определить энкодер для такого квантователя, вы должны предоставить не только раздел и кодовую книгу, как описано в Represent Partitions и Represent Codooks, но и предиктор. Предиктор является функцией, которую DPCM энкодера использует, чтобы произвести образованное предположение на каждом шаге. Линейный предиктор имеет вид
y(k) = p(1)x(k-1) + p(2)x(k-2) + ... + p(m-1)x(k-m+1) + p(m)x(k-m)
где x - исходный сигнал, y(k)
пытается предсказать значение x(k)
, и p
является m
-кортеж реальных чисел. Вместо квантования x
сам DPCM энкодера квантует прогнозирующую ошибку x-y. Целое число m
выше называется прогнозирующим порядком. Особый случай, когда m = 1
называется дельта-модуляцией.
Если догадка о k
th значение сигнала x
, на основе более ранних значений x
является
y(k) = p(1)x(k-1) + p(2)x(k-2) +...+ p(m-1)x(k-m+1) + p(m)x(k-m)
тогда соответствующий вектор предиктора для функций тулбокса
predictor = [0, p(1), p(2), p(3),..., p(m-1), p(m)]
Примечание
Начальный нуль в векторе-предикторе имеет смысл, если вы рассматриваете вектор как полиномиальную передаточную функцию фильтра с конечной импульсной характеристикой (КИХ).
Простой специальный случай DPCM квантует различие между текущим значением сигнала и его значением на предыдущем шаге. Таким образом, предиктор просто y(k) = x (k - 1)
. Приведенный ниже код реализует эту схему. Он кодирует пилообразный сигнал, декодирует его и строит графики как исходных, так и декодированных сигналов. Сплошная линия является исходным сигналом, в то время как штриховая линия является восстановленными сигналами. Пример также вычисляет среднюю квадратную ошибку между исходным и декодированным сигналами.
predictor = [0 1]; % y(k)=x(k-1) partition = [-1:.1:.9]; codebook = [-1:.1:1]; t = [0:pi/50:2*pi]; x = sawtooth(3*t); % Original signal % Quantize x using DPCM. encodedx = dpcmenco(x,codebook,partition,predictor); % Try to recover x from the modulated signal. decodedx = dpcmdeco(encodedx,codebook,predictor); plot(t,x,t,decodedx,'--') legend('Original signal','Decoded signal','Location','NorthOutside'); distor = sum((x-decodedx).^2)/length(x) % Mean square error
Это выход
distor = 0.0327
В разделе Оптимизация параметров квантования описывается, как использовать обучающие данные с lloyds
функция, чтобы помочь найти параметры квантования, которые минимизируют искажение сигнала.
В этом разделе описываются аналогичные процедуры для использования dpcmopt
функция в сочетании с двумя функциями dpcmenco
и dpcmdeco
, которые впервые появляются в предыдущем разделе.
Примечание
Обучающие данные, которые вы используете с dpcmopt
должно быть типичным для видов сигналов, которые вы фактически будете квантовать с dpcmenco
.
Этот пример аналогичен примеру в последнем разделе. Однако, где был создан последний пример predictor
, partition
, и codebook
прямолинейным, но бессистемным способом этот пример использует ту же кодовую книгу (теперь называется initcodebook
) как начальное предположение для нового оптимизированного параметра кодовой книги. Этот пример также использует предсказательный порядок, 1, как желаемый порядок нового оптимизированного предиктора. dpcmopt
функция создает эти оптимизированные параметры, используя пилообразный сигнал x
как обучающие данные. Далее в этом примере квантуются сами обучающие данные; в теории оптимизированные параметры подходят для квантования других данных, которые аналогичны x
. Заметьте, что среднее квадратное искажение здесь намного меньше, чем искажение в предыдущем примере.
t = [0:pi/50:2*pi]; x = sawtooth(3*t); % Original signal initcodebook = [-1:.1:1]; % Initial guess at codebook % Optimize parameters, using initial codebook and order 1. [predictor,codebook,partition] = dpcmopt(x,1,initcodebook); % Quantize x using DPCM. encodedx = dpcmenco(x,codebook,partition,predictor); % Try to recover x from the modulated signal. decodedx = dpcmdeco(encodedx,codebook,predictor); distor = sum((x-decodedx).^2)/length(x) % Mean square error
Это выход
distor = 0.0063
Сжатие и расширение последовательности данных с помощью Mu-закон
Сжатие и расширение последовательности данных с помощью A-закона
В некоторых приложениях, таких как обработка речи, обычно используют расчет логарифма, называемое компрессором, перед квантованием. Обратная операция компрессора называется расширителем. Комбинация компрессора и расширителя называется компандером.
Для получения дополнительной информации см. quantiz
и compand
.
Сгенерируйте последовательность данных.
data = 2:2:12
data = 1×6
2 4 6 8 10 12
Сжатие последовательности данных с помощью компрессора mu-закон. Установите значение для mu равным 255. Теперь последовательность сжатых данных находится в диапазоне от 8,1 до 12.
compressed = compand(data,255,max(data),'mu/compressor')
compressed = 1×6
8.1644 9.6394 10.5084 11.1268 11.6071 12.0000
Разверните последовательность сжатых данных с помощью расширителя mu-закон. Расширенная последовательность данных почти идентична исходной последовательности данных.
expanded = compand(compressed,255,max(data),'mu/expander')
expanded = 1×6
2.0000 4.0000 6.0000 8.0000 10.0000 12.0000
Вычислите различие между исходной последовательностью данных и расширенной последовательностью.
diffvalue = expanded - data
diffvalue = 1×6
10-14 ×
-0.0444 0.1776 0.0888 0.1776 0.1776 -0.3553
Сгенерируйте последовательность данных.
data = 1:5;
Сжатие последовательности данных с помощью компрессора A-закона. Установите значение A равным 87,6. Теперь последовательность сжатых данных находится в диапазоне от 3,5 до 5.
compressed = compand(data,87.6,max(data),'A/compressor')
compressed = 1×5
3.5296 4.1629 4.5333 4.7961 5.0000
Разверните последовательность сжатых данных с помощью расширителя A-закона. Расширенная последовательность данных почти идентична исходной последовательности данных.
expanded = compand(compressed,87.6,max(data),'A/expander')
expanded = 1×5
1.0000 2.0000 3.0000 4.0000 5.0000
Вычислите различие между исходной последовательностью данных и расширенной последовательностью.
diffvalue = expanded - data
diffvalue = 1×5
10-14 ×
0 0 0.1332 0.0888 0.0888
Кодирование Хаффмана предлагает способ сжатия данных. Средняя длина кода Хаффмана зависит от статистической частоты, с которой источник производит каждый символ из своего алфавита. Словарь кода Хаффмана, который связывает каждый символ данных с кодовым словом, имеет свойство, что никакое кодовое слово в словаре не является префиксом любого другого кодового слова в словаре.
huffmandict
, huffmanenco
, и huffmandeco
функции поддерживают кодирование и декодирование Хаффмана.
Примечание
Для длинных последовательностей из источников, имеющих искаженные распределения и малые алфавиты, арифметическое кодирование сжимается лучше, чем кодирование Хаффмана. Чтобы узнать, как использовать арифметическое кодирование, см. «Арифметическое кодирование».
Кодирование Хаффмана требует статистической информации об источнике кодируемых данных. В частности, p
входной параметр в huffmandict
функция перечисляет вероятность, с которой источник создает каждый символ в своем алфавите.
Например, рассмотрим источник данных, который производит 1с с вероятностью 0,1, 2с с вероятностью 0,1 и 3с с вероятностью 0,8. Основным вычислительным шагом в кодировании данных из этого источника с помощью кода Хаффмана является создание словаря, который связывает каждый символ данных с кодовым словом. Пример здесь создает такой словарь и затем показывает вектор кодового слова, сопоставленный с конкретным значением из источника данных.
В этом примере показано, как создать словарь кода Хаффмана с помощью huffmandict
функция.
Создайте вектор символов данных и присвойте вероятность каждому.
symbols = [1 2 3]; prob = [0.1 0.1 0.8];
Создайте словарь кода Хаффмана. Наиболее вероятный символ данных 3 связан с однозначным кодовым словом, в то время как менее вероятные символы данных связаны с двухзначными кодовыми словами.
dict = huffmandict(symbols,prob)
dict=3×2 cell array
{[1]} {[1 1]}
{[2]} {[1 0]}
{[3]} {[ 0]}
Отображение второй строки словаря. Выходы также показывают, что энкодер Хаффмана, принимающий символ данных 2
заменяет последовательность 1 0
.
dict{2,:}
ans = 2
ans = 1×2
1 0
Пример выполняет кодирование и декодирование Хаффмана с использованием источника, чей алфавит имеет три символа. Заметьте, что huffmanenco
и huffmandeco
функции используют словарь, созданный huffmandict
.
Сгенерируйте последовательность данных для кодирования.
sig = repmat([3 3 1 3 3 3 3 3 2 3],1,50);
Задайте набор символов данных и вероятность, связанная с каждым элементом.
symbols = [1 2 3]; p = [0.1 0.1 0.8];
Создайте словарь кода Хаффмана.
dict = huffmandict(symbols,p);
Закодируйте и декодируйте данные. Проверьте, что исходные данные, sig
и декодированные данные, dhsig
, идентичны.
hcode = huffmanenco(sig,dict); dhsig = huffmandeco(hcode,dict); isequal(sig,dhsig)
ans = logical
1
Арифметическое кодирование предлагает способ сжатия данных и может быть полезно для источников данных, имеющих небольшой алфавит. Длина арифметического кода, вместо того чтобы быть фиксированной относительно количества кодируемых символов, зависит от статистической частоты, с которой источник производит каждый символ из своего алфавита. Для длинных последовательностей из источников, имеющих искаженные распределения и малые алфавиты, арифметическое кодирование сжимается лучше, чем кодирование Хаффмана.
arithenco
и arithdeco
функции поддерживают арифметическое кодирование и декодирование.
Арифметическое кодирование требует статистической информации об источнике кодируемых данных. В частности, counts
входной параметр в arithenco
и arithdeco
functions перечисляет частоту, с которой источник создает каждый символ в своем алфавите. Определить частоты можно путем изучения набора тестовых данных из источника. Набор тестовых данных может иметь любой размер, который вы выбираете, пока каждый символ в алфавите имеет ненулевую частоту.
Для примера, перед кодированием данных из источника, который производит 10 x, 10 y и 80 z в типичном 100-символьном наборе тестовых данных, задайте
counts = [10 10 80];
В качестве альтернативы, если больший набор тестовых данных из источника содержит 22 x, 23 y и 185 z, то задайте
counts = [22 23 185];
Кодируйте и декодируйте последовательность из источника, имеющего три символа.
Создать вектор последовательности, содержащий символы из набора {1,2,3}.
seq = [3 3 1 3 3 3 3 3 2 3];
Установите counts
вектор для определения энкодера, который формирует 10 таковые, 20 двоек и 70 третей из типового 100-символьного набора тестовых данных.
counts = [10 20 70];
Примените функции арифметического энкодера и декодера.
code = arithenco(seq,counts); dseq = arithdeco(code,counts,length(seq));
Проверьте, что выходы декодера совпадают с исходной входной последовательностью.
isequal(seq,dseq)
ans = logical
1
Код ниже показывает, как quantiz
функция использует partition
и codebook
чтобы сопоставить вектор действительных чисел, samp
, к новому вектору, quantized
, записи которого: -1, 0,5, 2 или 3.
partition = [0,1,3]; codebook = [-1, 0.5, 2, 3]; samp = [-2.4, -1, -.2, 0, .2, 1, 1.2, 1.9, 2, 2.9, 3, 3.5, 5]; [index,quantized] = quantiz(samp,partition,codebook); quantized
Ниже приведен выход.
quantized = Columns 1 through 6 -1.0000 -1.0000 -1.0000 -1.0000 0.5000 0.5000 Columns 7 through 12 2.0000 2.0000 2.0000 2.0000 2.0000 3.0000 Column 13 3.0000
Этот пример более четко иллюстрирует природу скалярного квантования. После квантования дискретизированной синусоиды она строит графики исходных и квантованных сигналов. График контрастирует с x
они составляют синусоидальную кривую с точками, которые составляют квантованный сигнал. Вертикальная координата каждой точки является значением в векторе codebook
.
t = [0:.1:2*pi]; % Times at which to sample the sine function sig = sin(t); % Original signal, a sine wave partition = [-1:.2:1]; % Length 11, to represent 12 intervals codebook = [-1.2:.2:1]; % Length 12, one entry for each interval [index,quants] = quantiz(sig,partition,codebook); % Quantize. plot(t,sig,'x',t,quants,'.') legend('Original signal','Quantized signal'); axis([-.2 7 -1.2 1.2])