Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

Source Coding

パーティションの表現

スカラー量子化は、指定した範囲内のすべての入力を共通の値に割り当てるプロセスです。このプロセスは、値の範囲が異なる入力を、別の共通の値に割り当てます。実質的に、スカラー量子化はアナログ信号をデジタル化します。量子化を決定するものは、次の 2 つのパラメーター、分割コードブックです。

量子化の分割は、実数値の集合において、オーバーラップしないで隣接する値の範囲を定義します。分割を MATLAB® 環境で指定するには、異なる範囲の明確な端点をベクトルでリストします。

たとえば、分割が実数線を次の 4 つに分割する場合を考えてみます。

  • {x: x ≤ 0}

  • {x:0< x ≤ 1}

  • {x:1 < x ≤ 3}

  • {x:3 < x}

この場合、分割を 3 要素のベクトルとして表すことができます。

partition = [0,1,3];

分割ベクトルの長さは、分割区間数よりも 1 小さくなります。

コードブックの表現

コードブックは、分割の各範囲に分けられる入力に割り当てる共通の値を量子化器に指定します。コードブックは、長さが分割の区間の数と同じベクトルとして表されます。たとえば、次のベクトルを例に説明します。

codebook = [-1, 0.5, 2, 3];

このベクトルは、分割 [0,1,3] に対して考えられるコードブックの 1 つです。

各入力の区間の決定

関数 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 が使用する式です。

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);

量子化パラメーターの最適化

この節の概要

量子化を行うと信号が変形します。適切な分割パラメーターとコードブック パラメーターを選択することによって歪みを減少させることができます。しかし、大きな信号の集合に対し、微細な量子化方式を使用してパラメーターのテストや選択を行うのは手間のかかる作業です。分割およびコードブック パラメーターを簡単に生成する方法の 1 つは、いわゆる一連の "学習データ" に従ってそれらを最適化することです。

メモ

使用する学習データは、実際に量子化する典型的な種類の信号であるべきです。

例:量子化パラメーターの最適化

関数 lloyds は、Lloyd アルゴリズムに従って分割およびコードブックを最適化します。以下のコードは、おおまかな初期推定から開始して、正弦波信号の 1 区間の分割とコードブックを最適化します。その後、これらのパラメーターを使用し、初期推定パラメーターと最適化パラメーターを使用して元の信号を量子化します。出力は、量子化後の平均二乗歪みが最適化パラメーターに対して非常に小さいことを示します。関数 quantiz は、平均二乗歪みを自動的に計算して 3 番目の出力パラメーターとして出力します。

% 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) です。

関数 dpcmencodpcmdeco、および dpcmopt を使用すると、線形予測子を使用して DPCM 予測量子化器を実装できます。

DPCM の用語

このような量子化器の符号化器を決定するには、パーティションの表現コードブックの表現で説明した分割とコードブックだけでなく、"予測子" を指定しなければなりません。 予測子は、各手順で経験に基づく推定を行うために 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 である特殊な場合は、"デルタ変調" と呼ばれます。

予測子の表現

x の以前の値に基づく信号 xk 番目の値の推定が次のように表される場合を考えてみます。

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)]

メモ

予測子ベクトルの最初の 0 は、ベクトルを有限インパルス応答 (FIR) フィルターの多項式伝達関数として考えると理解できます。

例:DPCM 符号化と復号化

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

DPCM パラメーターの最適化

この節の概要

量子化パラメーターの最適化の節では、信号の歪みを最小化する量子化パラメーターを求めるために関数 lloyds で学習データを使用する方法を説明しています。

この節では、前の節で紹介した 2 つの関数 (dpcmencodpcmdeco) と関数 dpcmopt を一緒に使用する同様の手順を説明します。

メモ

dpcmopt で使用する学習データは、dpcmenco で実際に量子化する典型的な種類の信号でなければなりません。

例:最適化および非最適化された DPCM パラメーターの比較

この例は、前の節の例に似ています。前の例では、わかりやすいが計画的ではない方法で predictorpartition、および 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

信号の圧伸

この節の概要

音声処理などの用途では、量子化の前に "圧縮器" と呼ばれる対数演算を使用するのが一般的です。圧縮器の逆演算は、"伸張器" と呼ばれます。圧縮器と伸張器を組み合わせて、"圧伸器" と呼ばれます。

詳細については、quantizcompand を参照してください。

μ 則を使用したデータ シーケンスの圧縮と伸張

データ シーケンスを生成します。

data = 2:2:12
data = 1×6

     2     4     6     8    10    12

μ 則圧縮器を使用してデータ シーケンスを圧縮します。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

μ 則伸張器を使用して圧縮されたデータ シーケンスを伸張します。伸張したデータ シーケンスは元のデータ シーケンスとほぼ同一になります。

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

A 則を使用したデータ シーケンスの圧縮と伸張

データ シーケンスを生成します。

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

ハフマン符号化

この節の概要

ハフマン符号化は、データを圧縮する方法を提供します。ハフマン符号の平均の長さは、ソースのアルファベットから各シンボルが生成される統計的な頻度に応じて異なります。各データ シンボルをコードワードと関連付けるハフマン符号ディクショナリの性質として、ディクショナリ内のコードワードはディクショナリ内の他のコードワードの接頭辞ではありません。

関数 huffmandicthuffmanenco、および huffmandeco は、ハフマン符号化と復号化をサポートします。

メモ

ソースからの長いシーケンスに歪んだ分布があり、アルファベットの数が少ない場合、算術符号化による圧縮はハフマン符号化よりも優れています。算術符号化の使用方法の詳細については、算術符号化を参照してください。

ハフマン符号化は、符号化されるデータのソースに関する統計的な情報を必要とします。特に、関数 huffmandict の入力引数 p は、ソースのアルファベットで各シンボルが生成される確率をリストします。

たとえば、確率 0.1 で 1 を生成し、確率 0.1 で 2 を生成し、確率 0.8 で 3 を生成するデータ ソースを考えます。このソースからハフマン符号を使用してデータを符号化する主な計算ステップは、各データ シンボルをコードワードと関連付けるディクショナリを作成することです。この例では、そのようなディクショナリを作成してから、データ ソースの特定の値と関連するコードワード ベクトルを示します。

MATLAB を使用したハフマン符号ディクショナリの作成

この例では、関数huffmandictを使用してハフマン符号ディクショナリを作成する方法を示します。

データ シンボルのベクトルを作成し、それぞれに確率を割り当てます。

symbols = [1 2 3];
prob = [0.1 0.1 0.8];

ハフマン符号ディクショナリを作成します。最も確率の高いデータ シンボル 3 が 1 桁のコードワードに関連し、確率の低いデータ シンボルが 2 桁のコードワードと関連します。

dict = huffmandict(symbols,prob)
dict=3×2 cell array
    {[1]}    {[1 1]}
    {[2]}    {[1 0]}
    {[3]}    {[  0]}

ディクショナリの 2 番目の行を表示します。この出力は、データ シンボル 2 を受け取るハフマン符号化器がシーケンスを 1 0 に置き換えることも示しています。

dict{2,:}
ans = 2
ans = 1×2

     1     0

MATLAB を使用したハフマン符号の作成と復号化

この例は、アルファベットに 3 つのシンボルがあるソースを使用して、ハフマン符号化および復号化を行います。関数huffmanencoおよびhuffmandecohuffmandictによって作成されたディクショナリを使用することに注意してください。

データ シーケンスを生成して符号化します。

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 は、算術符号化と復号化をサポートします。

算術符号化パラメーターの表現

算術符号化は、符号化するデータのソースに関する統計的な情報を必要とします。特に、関数 arithenco および arithdeco の入力引数 counts は、ソースのアルファベットで各シンボルが生成される頻度をリストします。ソースの一連のテスト データを検討することにより、頻度を決定することができます。アルファベット内の各シンボルの頻度が 0 以外であれば、テスト データのセットには任意のサイズを指定できます。

たとえば、典型的な 100 シンボルのテスト データにおいて、10 個の x、10 個の y、および 80 個の z を生成するソースからデータを符号化する前に、以下のように定義します。

counts = [10 10 80];

あるいは、22 個の x、23 個の y、185 個の z を含むソースで構成されるテスト データの大規模なセットの場合は、次のように定義します。

counts = [22 23 185];

MATLAB を使用した算術符号の作成と復号化

3 つのシンボルをもつソースのシーケンスを符号化および復号化します。

シンボルを含むシーケンス ベクトルを {1,2,3} のセットから作成します。

seq = [3 3 1 3 3 3 3 3 2 3];

counts ベクトルを設定してテスト データの一般的な 100 シンボル セットから 1、2 および 3 をそれぞれ 10、20、70 個生成する符号化器を定義します。

counts = [10 20 70];

算術符号化器と算術復号化器の各関数を適用します。

code = arithenco(seq,counts);
dseq = arithdeco(code,counts,length(seq));

符号化器出力が元の入力シーケンスと一致することを確認します。

isequal(seq,dseq)
ans = logical
   1

信号の量子化

スカラー量子化の例 1

以下のコードは、関数 quantizpartitioncodebook を使用して、どのように実数ベクトル 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

スカラー量子化の例 2

この例では、スカラー量子化の性質をより明確に説明します。サンプリングされた正弦波を量子化した後、元の信号と量子化信号をプロットします。プロットは、正弦波を表す 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])

参考

関数