MATLABを使った離散コサイン基底と離散コサイン変換入門No.1
1次元データ篇
Version 1.4.1
 
 
  
 
概要 離散コサイン基底と離散コサイン変換を線形代数の基礎的な話を仮定して,丁寧に解説した.No. 1 では 1次元データを扱い,No.2 では2次元データ(画像データ)を扱う.
内容目次
- 記号と用語
- 離散コサイン基底
- 正規直交基底
- 離散コサイン基底によるフーリエ展開
- 離散コサイン基底から離散コサイン変換(DCT)
- 離散コサイン変換と逆離散コサイン変換
- データの解析例(東京の潮位)
- データ圧縮事始め
*予備知識:線形代数の初歩.内積,基底,線形写像の定義をおおよそ知っていることが望ましい.
*本ノートは MATLAB R2024a と MATLAB ライブエディターにより作成した.
*MATLABを動かしながら,数学理論を修得することを目標とした.そのためプログラムは数学理論に沿うように作成した.
*フーリエ解析ではインデックスは 0 から始めることが多い.MATLABのインデックスは 1 から始まるので要注意.
clear %とりあえず本ノートに必要ないものを最初にワークスペースから消しておく.
 
1.記号と用語
ℝを実数全体からなる集合とする.実数から成るN次元縦ベクトル  
 を
 を  と略記する.また,実数から成る N 次元縦ベクトル全体のなす集合を
 と略記する.また,実数から成る N 次元縦ベクトル全体のなす集合を  により表す.特にすべての
 により表す.特にすべての  が 0 であるような N 次元縦ベクトルを
 が 0 であるような N 次元縦ベクトルを  と表し,ゼロベクトルという.
 と表し,ゼロベクトルという.  上で定義される次の演算を線形演算という.
 上で定義される次の演算を線形演算という.線形演算
 に対して
 に対して .
.また,内積が次のように定義される.
内積
 に対して
 に対してを  と
 と  の内積という.特に
 の内積という.特に  のとき,
 のとき, と
 と  は直交するという.
 は直交するという. % わざわざ作らなくてもよいが,数式にあわせるため.
function Ip = InnerProd(x,y)
Ip = x'*conj(y); % 本稿で扱うのは実数のみなので,conj は無くても良い.
「離散コサイン基底」のうち,「基底」という用語の説明をしておく.
定義1 (基底)
 が
 が  の一組の基底であるとは,次の (B1), (B2) が成り立つことである.
 の一組の基底であるとは,次の (B1), (B2) が成り立つことである.(B1) 任意の  は,ある実数
 は,ある実数  を選んで,必ず
 を選んで,必ず   と表すことができる.
(B2)  は線形独立である.すなわち,
 は線形独立である.すなわち, をみたす
 をみたす   実数  は 0 に限る.
 は 0 に限る.  
コメント なお,  が
 が  の基底ならば,
 の基底ならば, になることが証明される.すなわち
 になることが証明される.すなわち の基底をなすベクトルの個数は N 個である必要がある.
 の基底をなすベクトルの個数は N 個である必要がある. 基底としてどのようなものがあるかというと,最もシンプルなものとしては,次の標準基底がある.
 として,
 として, と定義する.
 と定義する. は
 は  の一組の基底であり,これは標準基底と呼ばれる.これから述べる離散コサイン基底は,標準基底とは異なる有用な基底である.
 の一組の基底であり,これは標準基底と呼ばれる.これから述べる離散コサイン基底は,標準基底とは異なる有用な基底である.  
2.離散コサイン基底
離散コサイン基底は,次のように定義されるN個のN次元縦ベクトル  からなる
 からなる の基底である.ただし基底であることは第3節で確認する.証明するまでは基底と呼ぶべきではないかもしれないが,便宜上,証明する前から離散コサイン基底と呼ぶことにしたい.
の基底である.ただし基底であることは第3節で確認する.証明するまでは基底と呼ぶべきではないかもしれないが,便宜上,証明する前から離散コサイン基底と呼ぶことにしたい.  ,
, に対して
 に対して .
.これが実際に  の基底であることは後で示すことにする.
の基底であることは後で示すことにする. まず離散コサイン基底をプログラムする.
Nを自然数とし,V=DCB(N) により,次の形で N 次元離散コサイン基底をまとめた行列が得られる.
 =
=
% N 次元離散コサイン基底 V を行列形式(上述)で生成する.
V(:,1)=1/sqrt(N)*ones(N,1);
        V(n,k) = sqrt(2/N)*cos(pi/(2*N)*(2*(n-1)+1)*(k-1));
ここでは, の場合の離散コサイン基底の各ベクトルの数値のグラフを記述する.なお
の場合の離散コサイン基底の各ベクトルの数値のグラフを記述する.なお はJPEG圧縮で使われるケースである.
はJPEG圧縮で使われるケースである.         plot(x, 'o', 'LineWidth', 0.5, 'MarkerSize', 3, 'MarkerFaceColor', 'r')
           line([i, i], [0, x(i)], 'LineStyle', '--', 'Color', 'k')
      title([' v(:,' num2str(k+4*(l-1)-1) ') のグラフ'], 'FontSize', 8, ...
 
3. 正規直交性基底
ここで正規直交基底の概念を導入しておく.正規直交基底は非常に重要な基底のクラスである.その有用性は次節で説明する.まずは定義から始める.
定義 2(正規直交基底)
 を
 を  の一組の基底とする.これが
 の一組の基底とする.これが(ON1)   

 をみたすとき, の一組の正規直交基底という.
 の一組の正規直交基底という. 
ここで,与えられた正規直交しているベクトルが正規直交基底であるための有用な条件を述べておく.
定理 1  
  とする.もしもこれが (ON1) を満たしていれば,
 とする.もしもこれが (ON1) を満たしていれば,  は
 は  の一組の正規直交基底になっている.
 の一組の正規直交基底になっている. 
つまり,空間の次元と同じ個数のベクトルは,(ON1)をみたしていれば基底になっているということである.証明は [1] を参照してほしい.
したがって,離散コサイン基底が基底になっていることは,
 =
 = 
を示せば十分である. の場合に,これをMATLABで確認しておこう.一般の場合の証明は例えば文献[3]参照.
 の場合に,これをMATLABで確認しておこう.一般の場合の証明は例えば文献[3]参照. (これまで離散コサイン基底と読んできたが,ここにおいて,基底であることが証明されたことになる.)
正規直交性の確認( の場合)
 の場合) InnerProduct = zeros(N,N);
        InnerProduct(k,l)=InnerProd(v(:,k),v(:,l));
disp('(v^(k)とv^(l)の内積)=');disp(InnerProduct);
(v^(k)とv^(l)の内積)=
    1.0000         0   -0.0000    0.0000    0.0000   -0.0000   -0.0000    0.0000
         0    1.0000    0.0000   -0.0000    0.0000    0.0000    0.0000   -0.0000
   -0.0000    0.0000    1.0000    0.0000   -0.0000    0.0000   -0.0000    0.0000
    0.0000   -0.0000    0.0000    1.0000    0.0000   -0.0000    0.0000   -0.0000
    0.0000    0.0000   -0.0000    0.0000    1.0000    0.0000   -0.0000   -0.0000
   -0.0000    0.0000    0.0000   -0.0000    0.0000    1.0000    0.0000    0.0000
   -0.0000    0.0000   -0.0000    0.0000   -0.0000    0.0000    1.0000   -0.0000
    0.0000   -0.0000    0.0000   -0.0000   -0.0000    0.0000   -0.0000    1.0000
 
4. 離散コサイン基底によるフーリエ展開
線形代数の一般論として,次の定理が知られている.
定理 2.  X を N次元線形空間とし,内積  を持つものとする.
 を持つものとする. を正規直交基底とする.このとき,任意の
を正規直交基底とする.このとき,任意の  に対して,
 に対して, が成り立つ.
したがって特に離散コサイン基底に対しても成り立つ.
このとき,縦ベクトル   ( ' は転置) を
 ( ' は転置) を  の基底
の基底 による表現という.特に,本稿では離散コサイン基底による表現を周波数表現と呼ぶ.
による表現という.特に,本稿では離散コサイン基底による表現を周波数表現と呼ぶ.   
5. 離散コサイン基底から離散コサイン変換(DCT)
離散コサイン基底と離散コサイン変換の関係を明確にしておく.離散コサイン基底  を定理1に当てはめると,次の展開式が得られる.
を定理1に当てはめると,次の展開式が得られる.  .
.ここでこの展開式を次の図のように二つのフェーズに分けて考え,前半の部分からDCT(離散コサイン変換),後半の部分から IDCT(逆離散コサイン変換)が定義される.
  
6. 離散コサイン変換と逆離散コサイン変換
ここでは上記の数学的な考え方を元に離散コサイン変換と逆離散コサイン変換のプログラムを作成する.数学理論に忠実に計算していくので,高速計算は考慮に入れていない.
% 離散コサイン変換(数学理論に沿ってプログラムしたもので,高速計算ではない)
function DC_X = DCTrans(x)
    DC_X(k) = InnerProd(x,v(:,k));
% 逆コサイン離散変換(数学理論に沿ってプログラムしたもので,高速計算ではない)
function IDC_X = IDCTrans(x)
コメント 簡単な検算
簡単な例で,検算と MATLAB の dct との比較をしておく.
まず本稿の数学理論重視に沿って作った(高速計算を考慮してない)プログラムの場合.
tic;DCX = DCTrans(x); toc
MATLAB の dct  の場合.
tic; MATLAB_dct = dct(x); toc
MATLAB の dct と等しいことの確認
er1=max(abs(DCX-MATLAB_dct));
disp(['誤差 =',num2str(er1)]) 
本稿での DCT の反転公式の確認
z = IDCTrans(DCX)
    1.0000
    2.0000
    3.0000
    4.0000
    5.0000
    6.0000
    7.0000
    8.0000
  
7. データの解析例(東京の潮位)
ここでは2024年4月の東京の潮位のデータを離散コサイン変換を使って解析する.
データは気象庁のホームページからダウンロードできる.
まずこの中から,「東京,2024年4月,観測基準面表示,毎時潮位」を選択してデータを取り込む.それをExcelファイルにしたものが「東京潮位202404.xlsx」である.このExcelファイルは,上記ホームページにある表を取り込んだもので,行が時間(1時~24時),列が日(1日~30日)を表す  行列,720個の数値からなっている.
 行列,720個の数値からなっている. 
filename = '東京潮位202404.xlsx';
data1 = readmatrix(filename);
%第1行は「時間」,第1列は「日」の表示なのでそれを省いておく.
data2 = data1(2:end,2:end);
%DCT変換するためにそれを1列のデータ(縦ベクトル)に並べ替える
data3 = reshape(data2',1,[]);
%このデータをExcelファイルに変換する.(今は必要ないが,後で使う場合を考えて.)
writematrix(data3,'data202404.xlsx');
plot(data3,'k','LineWidth', 1)
xticks([1 25 49 73 97 121 145 169 193 217 241 265 289 313 337 361 385 409 433 457 ...
    481 505 529 553 577 601 625 649 673 697]);
xticklabels({'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',});
xlabel('日', 'FontSize', 8)
ylabel('潮位 (cm)', 'FontSize', 8)
title('東京 2024年4月 (気象庁によるデータに基づく)', 'FontSize', 8, 'FontWeight', 'bold')
print('Tokyo_Tyoui_2024_4', '-dtiff', '-r300');
tic; DX = DCTrans(data3'); toc %本稿の数学理論重視に沿って作った(高速計算を考慮してない)DCT
tic;MATLAB_DX = dct(data3); toc %MATLAB の dct
両者の誤差
er2= max(abs(DX - MATLAB_DX'));
disp(['誤差 =',num2str(er2)]) 
DX_delete(1)=0; %直流成分は大きいので,直流成分は 0 に置き換えて表示する.
                %表示上の変更なので,DCTの計算への影響はなし.
title('東京 2024年4月(気象庁によるデータ)のDCTによる周波数表現', 'FontSize', 8, 'FontWeight', 'bold')
print('Tokyo_Tyoui_Freq_2024_4', '-dtiff', '-r300');
plot(data3,'k','LineWidth', 1)
xticks([1 25 49 73 97 121 145 169 193 217 241 265 289 313 337 361 385 409 433 457 ...
    481 505 529 553 577 601 625 649 673 697]);
xticklabels({'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',});
xlabel('日', 'FontSize', 8)
ylabel('潮位 (cm)', 'FontSize', 8)
title('東京 2024年4月 (気象庁によるデータに基づく)', 'FontSize', 8, 'FontWeight', 'bold')
DX_delete(1)=0; %直流成分は大きいので,直流成分は 0 に置き換えて表示する.
                %表示上の変更なので,DCTの計算への影響はなし.
title('東京 2024年4月(気象庁によるデータ)のDCTによる周波数表現', 'FontSize', 8, 'FontWeight', 'bold')
print('Tokyo_Tyoui_TimeFreq_2024_4', '-dtiff', '-r300');
この中で,特に離散コサイン変換値の絶対値が大きい順に,その大きな値をとる位置を抜き出す.
[~,max_perm] = sort(abs(DX),'descend');
そのうち,上位12番目までを抜き出す.
max_perm(1:12)'
     1   117   121    56    62   118   116    61   114    58    64   120
すると,120付近と60付近にDCTの絶対値が大きいところが集中していることがわかる.離散コサイン基底(変換)の定義の仕方から,これは潮位の波形の周波数成分が,
    時間周期と,
 時間周期と, 時間周期の部分
 時間周期の部分 が大きいことを意味している.ところで
潮汐には月や太陽の影響で,一日周期と半日周期があることが知られている.離散コサイン変換による解析と一致していることがわかる.
 
8. データ圧縮事始め
そこで,主要な周波数成分だけを使って,潮位のグラフがどの程度再現できるかを見てみよう.これはデータ圧縮の側面からの考察でもある.1番絶対値の大きなの周波数成分から作った波形が Approx.1,1番目からk番目までの絶対値の大きな周波数成分から作った波形を Approx.k とする.つまり,原信号を復元するには, の720個の周波数データが必要ところを Approx.k の波形を得るには k 個の周波数データで済むということである.
 の720個の周波数データが必要ところを Approx.k の波形を得るには k 個の周波数データで済むということである. 以下のプログラムでは,Approx.12 までを描いている.ただし,グラフを見やすくするため,表示の範囲は 0~360 までに限定している.
% ここでは理論に沿って離散コサイン基底を使ってプログラムしたが,MATLABの dct と idct を使っても可能.
        title(['Approx.' num2str(k)])
Approx.60 と元データのグラフを書いて比較してみる.60まで使うとかなり元データを近似できていることが視認できるであろう.本来ならば 720 個のデータが必要なところ,60個のデータのグラフの概形がわかることになる(ただし概形は似ていても,潮位の観測データとは異なるので注意).
title(['Approx.' num2str(12)])
title(['Approx.' num2str(L)])
これは「ロスありデータ圧縮」の観点からの考察で,潮位のデータとしての意味は考えてない.
ロスありデータ圧縮は,音声データや画像など人の感覚にとって有用なデータの圧縮に使われる.これについては No. 2で画像データ圧縮を題材に解説する.
    
参考文献
線形代数について.(本稿の定理1,2 の証明は[1]にある.潮位の「フーリエ基底」による解析は[2]参照.)
[1] 新井仁之,線形代数 基礎と応用,日本評論社,2006  (2017年 update版は Kindle).
[2] 新井仁之,基底とその応用 - 配列の数学と信号処理 (1) -,数学のたのしみ(日本評論社)2006年秋号,pp.101-126.
離散コサイン基底について.
[3] 新井仁之,フーリエ解析学,朝倉書店,2003.
 2025/01/28 追記
  No.2 画像データ圧縮篇を公開しました。
-----------------------------------------
本ノートの履歴
Version 1.1  公開日 2024/06/19
Version 1.2  公開日 2024/06/20 a minor change
Version 1.3  公開日 2024/06/21 a minor change
Version 1.4 公開日 2024/08/02 minor changes
Version 1.4.1 公開日 2025/01/28 追記リンク修正
------------------------------------------
Copyright  © 2024 by Hitoshi Arai.