調和解析とフーリエ変換

GNU GPL2 © 2006 by T. Kitano
■ 調和分解とスペクトル
北野 利一
1) 最小自乗法による回帰係数の算出法を説明せよ.
ただし,標本サイズを n とし,被説明変量 y i ( i = 1 ~ n ) を m 個の説明変量
係数 β j を用いて検討することを考える.なお,被説明変量 y i および回帰係数
び β で表し,説明変量 x ij を行列 X で表すと便利である.
x ij ( j = 1 ~ m ) と回帰
β j をベクトル y およ
2) 名古屋港における 2000 年 1 月 1 日から2週間の潮位データを図示せよ.
3) 上記の潮位データを用いて,主要4分潮の大きさを求めよ.
4) 名古屋港の 2000 年の潮位データを用い,月平均潮位を求めよ.
5) 3次元空間における直交座標系は,1つに限らない.一般には,3つの単位ベクトルを
 0
 0
 1
r   r   r  
e1 = 0 , e 2 = 1 , e 3 = 0
 
 
 
 1
 0
 0
(1)
とする直交座標系を用いる.ただし,これは,他の無数にある直交系の1つに過ぎない.すなわち,直
交する単位ベクトル(これを,正規直交ベクトルという)の組を他に無数に選ぶことができるはずであ
る.それでは,次のような正規直交ベクトルを求めてみよ.
r*
r*
r
単位ベクトル e1 は,ベクトル a = ( 1, 2, 3 )′ に平行にとり,単位ベクトル e 2 は,ベクトル
r
b = ( 4, 5, 6 )′ との内積が最大となるようにとること.なお,横ベクトル x に対して,x ′ は縦ベクトル
を表す.つまり,ダッシュは転置を表す記号である.
また,単位ベクトル
r
r
e i*=1~ 3 を用いれば,ベクトル c = ( 7, 9, 8 )′ は,どのように表されるか?
6) 次式の3つの積分を考える.
I1 =
I2 =
I3 =
T
1
T
∫
1
T
T
∫
1
T
T
cos σ 1 t cos σ 2 t dt
(2)
sin σ 1 t sin σ 2 t dt
(3)
sin σ 1 t cos σ 2 t dt
(4)
0
0
∫
0
a) 積分範囲 T に対し,次式を満たすように角周波数 σ k =1, 2 をとれば,積分 I l =1, 2 , 3 の値は,いくらと
なるか?( σ k =1, 2 は,同一の値 σ 0 をとり,積分範囲でキッカリ1回だけ振動する角周波数である)
(
σ 1 = σ 2 = 2π T = σ 0
)
(5)
m, n は異なる自然数),角周波数 σ k =1, 2 が与えられる時,積分 I l =1, 2, 3 の値は,いくらと
なるか?( σ k =1, 2 は,異なる値をとり,積分範囲でキッカリ m と n 回だけ振動する角周波数である)
b) 次式により(
σ 1 = 2π m T ,
c) 任意の角周波数
(m ≠ n)
σ 2 = 2π n T
(6)
σ k =1, 2 に対して,任意の積分範囲で積分 I l =1, 2, 3 を考える場合には,どうなるか?
7) 範囲 0 < t < T で定義される,ある関数 f が次式のように書き表わされる時,その係数
b k ( k = 0,1, 2, ... ∞ ) を求めよ.
∞
(
)
f (t ) = a 0 + ∑ a k cos σ k t + b k sin σ k t , σ k = 2π k T
k =1
a k および
(7)
1
8) 次式に示す関数を前問の関数
f とする時,式 (7) における係数 a k および b k を求めよ.
f (t ) = t ,
0 < t < T
(8)
9) あなたの計算機環境における FFT のルーチンを用いて,次の数列に対する出力結果を示せ.
1,
なお,FFT のルーチンとは,連続関数
2,
3,
4,
5,
6,
7,
8
f (t ) の代わりに数列 f ( t0 + n ∆ t ), n = 0 ~ ( N − 1) を対象に,式
(7) における係数 a k および b k を求めるために必要な結果を与えるプログラムである(下線部が変な言い
回しになっているのは,正確に言ったからであり,FFT のルーチンは,係数 a k および b k そのものを算
出するものではないことを言っているワケです).
10) 図 -1 は,三角関数を等間隔の時刻で計測した記録である.いくつの波が見えますか?
図 -1 視力検査(?!)
11) 名古屋港を例に,1日間の潮位記録に対して,FFT のルーチンを用いて,スペクトルを求めよ.
また,連続する2日間および2週間の潮位記録に対しても,スペクトルを求め,1日間のものと比較せよ.
なお,スペクトルとは,端的に言えば,式 (7) の右辺の表現であり,本問は,その図示の検討である.
12) 水域防災工学の成績について,50人分と200人分の架空データを作成し,ヒストグラムを描け.
13) スペクトル解析におけるエネルギー密度の単位は?
14) FFT を用いて,下記のような適当な時系列を題材に,周波数スペクトルを図示せよ.
UNIX> cat examplewaves.txt | column -x | less
-0.6671012
-1.104542
-0.5364202
0.5128526
1.006578
1.188395
0.8261786
-0.4494395
-0.7825523
-0.8891466
-1.388340
:
-0.8163042
-1.020315
-0.4046849
0.7877356
0.9710443
1.148453
0.674116
-0.6950647
-0.6210156
-1.03455
-1.493346
-0.910189
-0.8992421
-0.2225413
0.9634399
1.006339
1.145067
0.5177846
-0.8727583
-0.556944
-1.133317
-1.507497
-1.052521
-0.7733919
0.004622992
1.031228
1.075349
1.077475
0.2795968
-0.9457991
-0.6078151
-1.165569
-1.481300
-1.139907
-0.6449788
0.2504878
1.037817
1.166497
0.9860885
-0.09407163
-0.9091944
-0.702125
-1.231912
-1.268255
ただし,この時系列は,時間間隔 0.03125 で計測されたものであり,時間および変位はともに無次元
量である.
15) 前問の時系列の全エネルギーを求めよ.
16) 前前問の時系列に対して,平均周波数
f m およびゼロクロス周波数 f z を求めよ.
◆ 宿題 ◆ 以上の設問とその解答例を熟読し,その理解の確認のために,君の出身地に近い港の,君の
誕生日に近い,ある1日の潮位記録について,調和解析とスペクトル解析を行い,その結果を図示せよ.
(下線部は,個人情報保護法に対する考慮を主な目的としているが,もう一つ理由がある.欠測のあるデー
タは,調和分解は可能であるが,FFT によるスペクトル解析は 基本的にできないからだ.また,たったの
1日=データ長24 としているのは,電卓程度の手計算で検算可能とすることを意図している.計算環境
は,R を推奨するが, Excel でも構わないし,伝統的な FORTRAN や C でもよい.)
2
■ 調和分解とスペクトル 【解答】
1) m 個の説明変量 x j =1~ m の線形和で,被説明変数 y を表現する統計モデルを考える.すなわち,こ
のモデルを式で表せば,
y = β0 +
∑β
j
xj +ε
(1)
j =1~ m
となる.ここで, ε は誤差を表す.また,回帰係数 β 0 は,定数項の係数を表す.
標本が与えられた時,誤差を最小にするためには,
∂
y − Xβ
∂ββ
2
= X′ ( y − Xβ ) = 0
となる必要がある.これを解いて,次式に示す β̂
β として,回帰係数
β̂
β = ( X ′X )
−1
(2)
β を 推定することができる.
X′ y
(3)
このような回帰係数の決定法を最小自乗法とよび,被説明変数 y の推定量(説明変量 X による予測
量) Xβ̂
β を原データ y から差引いた量 y − Xβ̂β ( = e とおく)を残差という(注:式 (1) に推定量 β̂β
を代入した時, ε に相当する量はもはや誤差とは言わない).また,式 (2) は正規方程式とよばれる.
2) 日本海洋データセンター(http://www.jodc.go.jp/)にアクセスし,日本沿岸域の潮汐観測(毎
時潮高)データを入手することができる(入手時には,使用目的および使用者の所属などの必要事項を必
ず記入すること).名古屋港の 2000 年のデータは,次のようなものである.
MA22,00/01/01,205,223,233,231,217,198,181,172,173,183,197,213,230,243,247,241,226,204,180,157,140,131,136,155
MA22,00/01/02,180,208,231,244,245,233,214,195,184,183,193,209,228,246,261,267,261,244,216,183,155,136,133,145
MA22,00/01/03,170,200,231,255,268,267,253,230,208,193,189,196,211,230,252,269,273,260,234,197,156,123,107,110
MA22,00/01/04,132,165,201,232,256,267,263,241,212,186,170,168,181,204,228,250,264,263,242,207,166,126,099,090
MA22,00/01/05,102,130,169,210,246,269,276,264,236,203,175,162,167,188,219,251,273,280,267,238,196,151,113,091
MA22,00/01/06,089,110,148,193,235,269,287,286,266,233,197,172,167,181,210,243,272,290,290,269,231,184,140,108
MA22,00/01/07,096,106,138,181,226,265,292,302,289,255,212,177,158,160,181,215,249,273,281,271,242,197,149,108
MA22,00/01/08,081,077,097,137,185,231,266,286,287,266,228,188,159,148,160,191,230,262,280,278,255,217,171,126
MA22,00/01/09,093,074,077,107,154,203,247,279,290,277,244,205,170,151,153,175,209,245,272,283,273,242,199,153
MA22,00/01/10,114,090,086,105,144,192,236,269,288,286,264,228,192,163,147,153,177,210,242,262,263,245,213,173
MA22,00/01/11,132,096,075,077,103,143,190,232,261,271,261,233,197,164,144,142,156,182,215,244,260,258,236,200
MA22,00/01/12,159,124,100,093,105,135,174,215,251,273,275,257,226,192,166,154,159,180,208,235,257,265,259,239
MA22,00/01/13,208,174,144,124,124,143,174,212,247,272,283,279,259,229,199,176,167,175,193,216,237,251,254,245
MA22,00/01/14,225,198,169,147,136,135,150,178,211,239,257,263,255,233,204,179,161,151,151,162,180,203,223,233
...
データ全体を R に読み込ませる場合には,read.table などを用いる必要がある(適切にオプションを設定).
ただし,2週間分のデーターであれば,港の名称(名古屋港は,MA22),日付の欄およびカンマをテキス
ト・エディタで削除して,コピー&ペーストにより,scan を用いて入力する方が簡便である.
200
100
nagoya
300
> scan() -> nagoya
1: 205 223 233 231 217 198 181 172 173 183 197 213 230 243 247 241 ...
Read 336 items
> days <- (1:(24*14) - 1)/24
> plot(days, nagoya, type="b")
0
2
4
6
8
10
12
14
days
図 -1 名古屋港の潮位変動(2000 年 1 月 1 日 ∼ 14 日)
3
図 -1 を見れば,潮位変動の第1の特徴として,1日に約2回の振動が確認できる.また,
(この場合に
は)干潮に着目すれば,潮位の低いものと高いものが交互に現れている.この現象を日潮不等という.
3) 本題に入る前に少々の寄り道: まずは,潮位変動を大雑把に見て,1日に約2回の振動であること
から,定数項に加えて,説明変数として,以下の4成分(1つの周波数に対して,cos と sin の2成分があ
るので,周波数成分としては2つ)をとることにする.1日に1回の振動成分は必要ないのではないか?
と考えるかも知れない.しかし,平均潮位=定数項=振動しない成分=1日に0回の振動成分は,説明変
数に必要であることも考え合わせれば,系統的に,
(0,1,2)回/1日の振動成分を全て説明変数とし
て含めて検討する方が自然である.
> rep(1, 24*14) -> flat
> cos(2*pi*days) -> cos.1;
sin(2*pi*days) -> sin.1
> cos(2*pi*days*2) -> cos.2; sin(2*pi*days*2) -> sin.2
前問1)の解答にしたがえば,次のように,行列 X を求めて,正規方程式を解けばよい.
> as.matrix(data.frame(flat, cos.1, sin.1, cos.2, sin.2)) -> X
> solve(crossprod(X), t(X) %*% nagoya) -> coefs; t(coefs)
flat
cos.1
sin.1
cos.2
sin.2
[1,] 201.4821 -28.78871 -1.011963 -30.01552 -14.44009
このような回帰モデルの計算は,以下のように行うこともできる.
> (lm(nagoya ~ cos.1 + sin.1 + cos.2 + sin.2) -> model.1)
Call:
lm(formula = nagoya ~ cos.1 + sin.1 + cos.2 + sin.2)
Coefficients:
(Intercept)
201.482
cos.1
-28.789
sin.1
-1.012
cos.2
-30.016
sin.2
-14.440
実測の潮位と合わせて,推算潮位を表示したものを図 -2 に示す.
> plot(days, predict(model.1), type="l", col="blue", ylim=range(nagoya))
> points(days, nagoya)
潮位変動の第2の特徴として,
「周期を約2週間とする振幅の変調」という性質が,図 -2 の実線で示さ
れた推算潮位には見られない.この振幅の変調は,大潮・小潮として知られる現象であり,新月(朔)と
満月(望)で,大潮となることは,有名である(月の朔望周期は,約 29.5 日である).このことを検討す
るためには,以下に示すような最低限4つの周波数の振動を成分にとる必要がある.なお,この振動周期
は,天体(太陽と月)の運動により,定められるものである.このような振動成分を,一般に,分潮とよ
び,ここで用いる4つ分潮( K1, O1, M2, S2 )を主要4分潮という.
->
->
->
->
cos.K1;
cos.O1;
cos.M2;
cos.S2;
sin(2*pi*hours/23.93)
sin(2*pi*hours/25.82)
sin(2*pi*hours/12.42)
sin(2*pi*hours/12.00)
->
->
->
->
sin.K1
sin.O1
sin.M2
sin.S2
200
300
hours <- days * 24
cos(2*pi*hours/23.93)
cos(2*pi*hours/25.82)
cos(2*pi*hours/12.42)
cos(2*pi*hours/12.00)
100
predict(model.1)
>
>
>
>
>
0
2
4
6
8
10
12
14
days
図 -2 2つの振動成分による推算潮位
4
さて,これらの主要4分潮と定数項を説明変数とした統計モデルの回帰係数を求めよう.
> (lm(nagoya ~ cos.K1 + sin.K1 + cos.O1 + sin.O1 +
+
cos.M2 + sin.M2 + cos.S2 + sin.S2) -> model.2)
Call:
lm(formula = nagoya ~ cos.K1 + sin.K1 + cos.O1 + sin.O1 + cos.M2 +
sin.M2 + cos.S2 + sin.S2)
Coefficients:
(Intercept)
201.447
cos.K1
-28.370
cos.M2
54.982
sin.K1
-4.670
sin.M2
27.353
cos.O1
14.838
cos.S2
-26.815
sin.O1
3.685
sin.S2
-13.428
図 -3 を見るとおり,主要4分潮による推算潮位は,実測の潮位を極めて良く再現している.また,各分潮
の振幅の大きさは,下記のとおり得られる(単位:cm ).
> matrix(coef(model.2)[-1], nrow=2,
+
dimnames=list(c("cos","sin"), c("K1","O1","M2","S2"))) -> res
> (apply(res, 2, function(vec) round(sqrt(crossprod(vec)), 1)) -> major4)
K1
O1
M2
S2
28.8 15.3 61.4 30.0
名古屋港における潮位の調和定数(ここでは振幅のみ)は, K1=24.2, O1=18.4, M2=65.4, S2=30.9 (cm) と
知られている(海上保安庁 , 1995).なお,実際には,分潮の振幅が 18.6 年間で緩やかに変動することも
考慮し,また,1日に3回以上振動する高周波の分潮や,1年間で1回振動する気象潮などの低周波の分
潮も含め,日本の場合は60分潮で,調和分解が行われることが多い.
主要4分潮の振幅比から,日潮不等の分類も行われる.主要4分潮の振幅値に対して,次式の F 値が,
0 ≤ F ≤ 0.25 であれば,半日周潮型,F > 3.00 であれば,日周潮型,0.25 < F ≤ 3.00 であれば,混
合型として分類している(Foreman, 1996).
F=
K1 + O1
M 2 + S2
(4)
名古屋港の場合,上記の計算結果から以下のように F 値を求めて,混合型と判定できる.
> sum(major4[c("K1", "O1")])/sum(major4[c("M2", "S2")])
[1] 0.4824945
4) 日本海洋データセンターにて入手した,2000 年の名古屋港の年間全体のデータに対し,設問2)のよ
うなコピー&ペーストによる入力法は適さない.データをファイルに保存して,以下のように読み込む.
> read.table("ftp_MA22_2000_01.csv", sep=",",
+
colClass=c("character","character", rep("numeric", 24))) -> nag2k
> dim(nag2k)
[1] 366 26
300
200
100
predict(model.2)
366行*26列の表として読み込んでいることがわかる.各行に,港名,日付,および24時間の毎時
0
2
4
6
8
10
12
14
days
図 -3 主要4分潮による推算潮位
5
潮高記録があるので,26列となっている.これに対し,366行というのは,対象とする1年間の日数
である.西暦 2000 年=うるう年をアタリマエ!と思う人は,少々軽薄か,あるいは,かなり思慮深いか,
いずれかである.なぜなら,西暦 1900 年は,うるう年ではない.そもそも,現在,西暦とよんでいるのは,
グレゴリオ暦のことである.暦について興味がでてきた人は,少し調べてみよ!(例えば,Duncan, 1998)
UNIX> cal 2
February
S M Tu W
1 2
6 7 8 9
13 14 15 16
20 21 22 23
27 28 29
2000
2000
Th F S
3 4 5
10 11 12
17 18 19
24 25 26
UNIX> cal 2 1900
February 1900
S M Tu W Th F S
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
蛇足であるが,以下の結果には,あれれ?と驚くかも知れない.実は,西暦には11日間の欠落がある(ユ
リウス暦からグレゴリオ暦への切り替え時に生じる)
.以下は,当時英国領であった米国の場合を示してい
る.なお,法王おひざもとのイタリアでは,1582年10月に不連続が生じている.
UNIX> cal 9 1752
September 1752
S M Tu W Th F S
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
まずは,日平均潮位を求めよう.9月中旬に不自然に突出しているのは,東海豪雨の影響かもしれない.
> apply(nag2k[, -(1:2)], 1, mean) -> nag2k.dailym
> plot(1:366/366*12 +.5, nag2k.dailym, type="l", axes=F,
+
xlab="Month", ylab="Sea Level")
> axis(1, 1:12, month.abb); axis(2); box(); title("Nagoya: year 2000")
次に,月平均潮位を求めよう.図 -4 を見るとおり,平均潮位は,春先に最も低く,秋に最も高い.これは,
2000 年に限らず,一般的にいえることである.台風の来襲時には,平均的に見ても潮位が高いため,高潮
に御用心!ということである.また,春先の「潮干狩り」は,日本の風物詩の1つと知られる(原田,2005).
秋には,潮干狩りをしないネ! 図 -4 は,このことを示している,というのは言い過ぎか?
> nag2k.mon <- unstack(data.frame(data=nag2k.dailym,
+
month=rep(month.abb, c(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31))))
> unlist(lapply(nag2k.mon, mean)) -> nag2k.m
> lines(nag2k.m[month.abb], type="b", col="blue")
220
200
180
Sea Level
240
Nagoya: year 2000
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
Month
図 -4 名古屋港の平均潮位(2000 年)
6
5) ベクトル
r
r
a に平行な単位ベクトル e1* は,以下のようになる.
 1
1  
2
14  
 3
r
e1* =
また,ベクトル
(5)
r **
r
e1* に直交する適当な (数多くあるもののうちの1つの)単位ベクトル e 2 を
 1 
r **
1  
e2 =
1
3 
 −1 
(6)
と定めると,これら2つの単位ベクトルに直交する第3の単位ベクトル
r
r
e 3** ⊥ e1*
r
r
e 3** ⊥ e 2**
r
e 3** = ( x, y, z )′ は,
⇒
x + 2 y + 3z = 0
(7)
⇒
x+y−z=0
(8)
x2 + y2 + z2 = 1
(9)
という条件を満足しなければならない.これを解いて,単位ベクトル
r
e 3** =
 5 
1 
− 4

42 
 1 
r
e 3** は,
(10)
と定められる.これで準備が整った.
r
a を法線ベクトルとする平面 A に対し,この平面内の点は,以下のように表される.
r
r
r
a ⊥ = r cos ϕ e 2** + r sin ϕ e 3**
(11)
r*
そこで,原点からの距離 r を1として,平面 A に含まれる単位ベクトル e 2 は,
ベクトル
 5 
 1 
r * cos ϕ   sin ϕ 
− 4
e2 =
1 +

3  
42 
 1 
 −1 
r
と表すことができる.この時,ベクトル b との内積は,
r r
6
b ⋅ e 2* = 3 cos ϕ +
sin ϕ
42
と整理できる.ここで,角
=
3 21
cos ( ϕ − ϕ 0 )
7
(13)
ϕ 0 は,以下を満たすものである.
cos ϕ 0 =
角
(12)
7
2
, sin ϕ 0 =
3
3
(14)
r
ϕ を角 ϕ 0 に一致するようにとれば,式 (13) が最大となる.したがって,単位ベクトル e 2* は,
r
e 2* =
r*
 4 
1 
1 

21 
 −2
(15)
r*
と得られる.また,単位ベクトル e 3 は,単位ベクトル e 2 を 90 度回転して得られるので,回転の
向きに応じて2種類(+/−)のものが有り得る.ここでは,式 (12) の右辺にて,角 ϕ を角 ϕ 0 + π 2
7
として代入したものを
r
e 3* として採用する.
 1 
r*
1 
e3 =
−2
(16)

6 
 1 
r*
以上の式 (5),(15) および (16) に示された e i =1~ 3 が,求めるべき正規直交ベクトルである.
r
r
さて,得られた正規直交ベクトル e i* を用いて,ベクトル c を表したとする.すなわち,
r
r*
r*
r*
c = c 1 e1 + c 2 e 2 + c 3 e 3
(17)
r
と表現する.この時, e i* は互いに直交すること,つまり,
r r
r r
r r
e1* ⋅ e 2* = e 2* ⋅ e 3* = e 3* ⋅ e1* = 0
(18)
r*
r
であることを利用すれば,ベクトル c と各正規直交ベクトル e i =1~ 3 との内積により,式(17)の係数 c i は,
7 14
6
r r
r r
r r
c1 = c ⋅ e1* =
, c 2 = c ⋅ e 2* = 21 , c 3 = c ⋅ e 3* = −
(19)
2
2
r
として得られる.なお,ベクトル c の大きさに関して,以下の関係が成立することも確認できる.
r2
(20)
c = 7 2 + 9 2 + 8 2 = c12 + c 22 + c 32 = 194
r
r
◇ (射影ベクトル) ベクトル b との内積が最大となるように定めた単位ベクトル e 2* の誘導の考え方に
r
r
A
基づけば,ベクトル c に対する平面 A 上の射影ベクトル c を見つけることができる.射影ベクトルと
は,射影面の法線の向きに光をあててできる影ベクトルのことである(図 -5 参照)
.したがって,射影ベ
rA
r
クトルの向きを表す単位ベクトル e c は,平面 A に含まれるベクトルの1つで,ベクトル c との内積が
rA
r
最大となる.式 (12) の左辺をベクトル e c とおいて,ベクトル c との内積をとれば,以下のようになる.
r r
8
c ⋅ e cA =
cos ϕ +
3
ここで,角
7
sin ϕ
42
=
3 10
cos ( ϕ − ϕ c )
2
cos ϕ c =
8 30
, sin ϕ c =
45
(21)
ϕ c は,以下を満たす.
したがって,角
105
45
(22)
r
ϕ を角 ϕ c とする時,式 (21) の内積は最大となり,この時,ベクトル e cA は,
r
e cA =
 7 
1 
4 

3 10 
 − 5
(23)
となる.ユークリッド空間における内積は,2つのベクトルのなす角の余弦にそれぞれのベクトルの大き
図 -5 射影ベクトル
8
r
e cA の大きさは1であることに注意して,
さを掛けたものに等しいので,単位ベクトル
3 10
r
r r
c cosθ = c ⋅ e cA =
(24)
2
r
r
r
となる(角 θ は,平面 A とベクトル c のなす角であり,法線ベクトル a とベクトル c のなす角と角 θ
r
rA
の和は,直角となる).つまり,この値は,ベクトル c の平面 A への射影ベクトル c の長さを意味す
rA
る.よって,射影ベクトル c は,
 7 
rA
r rA rA 1 
4 
c = c ⋅ ec ec =
(25)

2
 −5
r
と表される.この結果は,式 (17) に示したベクトル c の表現において,平面 A に張られた正規直交ベ
r*
rA
クトル e i = 2 , 3 のみを取り出したもの(あるいは,平面 A の法線成分を抜いたもの)が,射影ベクトル c
(
)
に相当することを示している.すなわち,射影ベクトルは,
r
r
r
r
r
c A = c 2 e 2* + c 3 e 3* = c − c1 e1*
(26)
rA
となる.また,式 (26) の表現から,射影ベクトル c の大きさは,式 (24) で求めた値に一致する(当然).
3 10
(27)
2
r
r
◇ (最小自乗法との関係) 説明変量を正規直交ベクトル e i*= 2 , 3 に選び,被説明変量をベクトル c を次
c 22 + c 32 =
式のように表すとしよう.
r
r
r
r
c = c˜ 2 e 2* + c˜ 3 e 3* + e
(28)
r
ここで, e は残差ベクトルである(設問 1)の解答での但書きを逆読みすれば,係数 c˜ i = 2 , 3 には,まだ
推定値を代入していない時点では,
誤差でよいのでは?と思うが,
そうではない! それを誤差とよぶには,
係数 c˜ i = 2 , 3 に真値が代入されないといけない;本問の状況下では,そもそも真値という概念はない).残
差ベクトルの大きさが最小となるように係数 c˜ i = 2 , 3 を決定する,ということが,最小自乗法の定式である.
r
ベクトル c は,式 (17) として表されることに注意して,残差ベクトルの大きさの自乗は,
r2
e = c12 + c˜ 2 − c 2
(
) + (c˜
2
3
− c3
) ( >c )
2
2
1
(29)
となる.したがって,
c˜ 2 = c 2 , c˜ 3 = c 3
(30)
r
となる時に最小となる.すなわち,最小自乗法による,被説明変量の予測ベクトルは,射影ベクトル c A
r
r
r
= c 2 e 2* + c 3 e 3* として表現されるのである.また,この時,残差ベクトル e は,
(
)
r
r r
r
= c − c A = c1 e1*
(31)
rA
r
となり,平面 A に直交する.したがって,予測ベクトル c と残差ベクトル e は直交する.以上を整理
e
図 -6 最小自乗法における一般化されたピタゴラスの定理
9
すれば,最小自乗法は,以下のように表される.
r r
r
c = cA + e,
r r
cA ⋅ e = 0
(32)
また,この時,次の“一般化されたピタゴラスの定理”が成立することは重要である(図 -6 参照)
.
r
c
2
r
= cA
2
r
+ e
2
(= [ c
2
2
+ c 32
]+c )
2
1
(33)
なお,注意すべき点は,ここでの議論は,説明変数が互いに直交している場合を示している.最小自乗法
を適用する一般の問題で,説明変数が互いに直交することは稀である.ただし,互いに直交しない場合の
議論でも,説明変量のベクトルが張る平面が存在し,最小自乗法による予測ベクトルは,その平面への射
影ベクトルとなることには,変わりはない(最小自乗法が解ける場合には,線形代数の知識を活用すれば,
直交しないベクトルを再構築して,同じランクの直交するベクトルに変換することは可能である).
◆ 以上の最小自乗法の議論を,R に解かせてみよう.まずは,被説明変量と説明変量を与える.
> vec.c <- c(7, 9, 8)
> e2 <- c(4, 1, -2)/sqrt(21)
> e3 <- c(1, -2, 1)/sqrt(6)
注意すべきは,R での推定モデルの表現は,定数項を暗黙に含む.したがって,定数項を含まない今回の
ような場合には,陽に定数項を含まないことを指示する必要がある(次式のように,-1 を加える).
> lm(vec.c ~ e2 + e3 - 1) -> c.on.A
> c.on.A
Call:
lm(formula = vec.c ~ e2 + e3 - 1)
Coefficients:
e2
e3
4.583 -1.225
推定された係数は,式 (17) の c i = 2 , 3 に一致する.
> c(sqrt(21), -sqrt(6)/2)
[1] 4.582576 -1.224745
また,射影ベクトル,すなわち,予測ベクトルは,以下のように得られる(式 (25) に一致).
> predict(c.on.A)
1
2
3
3.5 2.0 -2.5
予測ベクトルは,残差ベクトルと直交することも,以下のように確かめることができる.
> predict(c.on.A) %*% residuals(c.on.A)
[,1]
[1,] 4.884981e-15
ただし,計算機による結果であるので,厳密にゼロとはならない.また,一般化されたピタゴラスの定理
については,以下のとおり確認できる.
> c(crossprod(predict(c.on.A)) + crossprod(residuals(c.on.A)), crossprod(vec.c))
[1] 194 194
r
r
◆ 余談:問題の雰囲気からすれば,ベクトル c は, c = ( 7, 8, 9 )′ として与えられた方が,スッキリする
んだけれど,
.
..と思うかも知れません. r
c = ( 7, 8, 9 )′ とする場合に,式 (17) における係数 c i =1~ 3 は,
25 14
6 21
r r
r r
r r
c1 = c ⋅ e1* =
, c 2 = c ⋅ e 2* =
, c 3 = c ⋅ e 3* = 0
7
7
(34)
10
となり,さらに,式 (21) の内積
r r
c ⋅ e cA は,
r r
6
12
c ⋅ e cA =
cos ϕ +
sin ϕ
3
42
=
6 21
cos ( ϕ − ϕ c )
7
(35)
となる.式 (35) の内積は,式 (21) をキッカリ2倍したものとなり,気持ちが悪い(むしろ,スッキリしま
せん)
.つまり,この気持ちの悪さは,特別な場合をとりあげているために生じているからだ.この特別さ
r r
r
は,ベクトル a , b および c が同一平面上にある,ということに起因している.3つのベクトルが同一
平面上にあるかどうかは,以下のようにして判定ができる.
> ma <- matrix(1:9, nr=3)
> ma
[,1] [,2] [,3]
[1,]
1
4
7
[2,]
2
5
8
[3,]
3
6
9
> det(ma)
[1] 0
> ma[2:3,3] <- c(9,8)
> ma
[,1] [,2] [,3]
[1,]
1
4
7
[2,]
2
5
9
[3,]
3
6
8
> det(ma)
[1] 9
◎ お説教じみた話はできるだけ避けたいが,線形代数の復習も重要である.また,本問では,概念として
重要なものは絵で示したが,計算する上で役に立ちそうなような図は故意に載せていない.各自が必要と
思うような図をメモした上で計算することをすすめる(代数は,幾何の助けがあると理解しやすい).
6) 本問は,単なる積分の問題ではない.関数をベクトルと考え,内積と距離を導入する話である.
距離を導入すれば,最小自乗法に帰着するワケである.このことは,次問 7)と併せて検討する.
a) まずは,式 (5) の条件の下で,積分
I 1 は,次のように整理できる.
I1 =
1
T
T
∫
cos 2 σ 0 t dt
(36)
0
変数変換:
θ = σ 0t
(37)
を用いれば,積分 I 1 は,
1
I1 =
2π
2π
∫
0
1
cos θ dθ =
2π
2
2π
∫
0
1 + cos 2θ
dθ
2
(38)
と変換される.三角関数の積分は,真面目に計算しても良いけれど,図 -7 の面積(正/負あり)と考えれ
ば,被積分関数の第2項による寄与はゼロである.したがって,
I1 =
1
2
(39)
となる.
11
積分 I 2 についても,同様に,式 (37) の変数変換を用いて,以下のように計算できる.
1
I2 =
T
T
∫
0
1
sin σ 0 t dt =
2π
2π
2
1
sin θ dθ =
2π
∫
2
0
2π
∫
0
1 − cos 2θ
1
dθ =
2
2
(40)
また,積分 I 3 についても,同様に,以下のように計算できる.
I3 =
1
T
T
∫
sin σ 0 t cos σ 0 t dt =
0
1
2π
2π
∫
sin θ cos θ dθ =
0
2π
1
2π
∫
0
sin 2θ
dθ = 0
2
(41)
b) 式 (6) で与えられた周波数に対しても,式 (37) の変数変換を用いれば,
1
I1 =
T
1
=
2π
1
I2 =
T
1
=
2π
T
1
cos σ 1 t cos σ 2 t dt =
2π
∫
0
2π
∫
0
T
0
2π
∫
0
∫
cos mθ cos nθ dθ
0
cos ( m + n)θ + cos ( m − n)θ
dθ = 0
2
1
sin σ 1 t sin σ 2 t dt =
2π
∫
2π
(42)
2π
∫
sin mθ sin nθ dθ
0
cos ( m − n)θ − cos ( m + n)θ
dθ = 0
2
(43)
および
I3 =
=
1
T
1
2π
T
∫
sin σ 1 t cos σ 2 t dt =
0
2π
∫
0
1
2π
2π
∫
sin mθ cos nθ dθ
0
sin ( m + n)θ + sin ( m − n)θ
dθ = 0
2
(44)
となる.
以下は,図 -7 を描くのに必要なコードである.
>
+
+
+
+
+
+
+
+
+
+
area <- function(p, k=1) {
if (p == 0)
{tt <- seq(0, pi/2, by=pi/20)
+ p*pi
ww <- c(0, cos(tt))
tt <- c(p*pi, tt)}
else if (p == 2*k) {tt <- seq(0, -pi/2, by=-pi/20)
+ p*pi
ww <- c(0, cos(tt))
tt <- c(p*pi, tt)}
else
{tt <- seq(-pi/2, pi/2, by=pi/20) + p*pi
ww <- cos(tt)
tt <- tt}
polygon(tt, ww, col=ifelse(p %% 2, "cadetblue", "tomato"), border=NA)}
theta/pi
0
0.5
1
1.5
2
0
0.25
0.5
0.75
1
T
図 -7 式 (36) の被積分関数 ( σ 0
= 2π T
の場合)
12
>
+
+
+
+
+
twist <- function(k=1) { kk <- (k %/% 1)
t <- seq(0, 2*pi*k, length=200)
plot(t, cos(t), type="l", ylim=c(-2,2), axes=F, xlab="T", ylab="")
axis(1, 0:4/2*pi*k, 0:4/4); axis(3, 0:4/2*pi*kk, 0:4/4*kk)
mtext("theta/pi", side=3, line=2.5)
for (j in 0:(2*kk)) area(j, k=kk)}
> twist(2)
以上の a) および b) での積分の値は,0 あるいは 1/2 のいずれかの値しかとらない.そこで,全ての三角
関数に定数 2 を掛けることにより正規化して,以下のような関数群 f n を考える(注:定数 1 も関数
として扱い,個々の関数を識別する添字 k は,自然数をとる).
2π kt 
2 cos 
,
 T 
f 0 (t ) = 1, f 2 k (t ) =
2π kt 
2 sin 
;
 T 
f 2 k −1 (t ) =
0 <t <T
(45)
これらの各関数をベクトルとみなし,積分を内積として扱う.つまり,関数 f (t ) および g(t ) に対して,
内積 f , g を以下のように定義する(以下の定義が,内積の公理を満足する等などの詳細については,例
えば,**を参照せよ).
f, g =
1
T
T
∫
f (t ) g(t ) dt
(46)
0
このとき,
 0
fm, fn = 
 1
(m ≠ n)
(m = n)
(47)
となるので,関数群 f n は,正規直交ベクトルであることがわかる(三角関数の直交性).
c) 任意の周波数
σ k に対して,次のように自然数ではない実数 sk を導入する.
σ k =1, 2 = 2π sk T
(48)
この時,例えば,σ 1 = σ 2 であれば(式 (5) の条件と少し異なる条件)
, θ = σ 1 t とおいて,
1
I1 =
T
T
∫
0
1
cos σ 1 t dt =
2π s1
2
2π s 1
∫
0
1
1
= +
2 2π s1
1 + cos 2θ
dθ
2
2π s 1
∫
0
 1 
cos 2θ
dθ  ≠ 
2
 2 
(49)
となり,式 (5) の条件の下では,式 (38) および (39) を見るとおり,積分 I 1 の値は 1/2 となるのに対し,こ
の場合はそうならない.また,σ 1 ≠ σ 2 であれば(式 (6) の条件と少し異なる条件)
,
θ=
σ1 +σ 2
s + s2
s − s2
t; s = 1
; s′ = 1
2
2
2s
(50)
とおいて,
1
I1 =
T
T
∫
0
1
cos σ 1 t cos σ 2 t dt =
2π s
2π s
∫
0
cos 2 θ + cos 2 s ′ θ
dθ
2
(≠ 0 )
(51)
となる.式 (6) の条件の下では,式 (42) を見るとおり,積分 I 1 の値は 0 となるが,この場合はそうならな
い.いずれの例でも,重要な点は,i) 積分範囲が 2π の整数倍にキッカリとはならないことと,ii) 積分の
前に振動数 s1(あるいは,平均振動数 s )の逆数が係ることである.このことが原因となって,積分 I l =1, 2 , 3
の値が,0 あるいは 1/2 とはならないのである(雑な言い方をすれば,数字が汚れる)
.したがって,積分
範囲での振動数がキッカリ整数にならない振動関数は,正規直交ベクトルにならないということだ.
13
以上から,積分 I l =1, 2 , 3 の値が,0 あるいは 1/2 とはならない,が本問の答えである(意地悪クイズでは
ないけれど,設問 a) および b) では「いくらとなるか」ときいているのに対し,設問 c) では「どうなるか」
と言い方を変えてある点に御用心)
.
冗談はさておき,上の解答には,もう少し検討の余地がある.つまり,特別な場合: 振動数が十分に多い
という極限を考える.感覚的に,図 -8 をパッと見て,ピンとくるはず(直感は,工学的センスの1つとし
て重要)
.解説すれば,.
.
.振動数を増加させれば,面積の等しい峰と谷の組み(=キッカリ相殺される面積)
が増え,他方,振動周期が小さくなるので,端数の面積は小さくなる.したがって,式 (49) の第2項の積分
や,式 (51) の積分は,限りなくゼロに近づく.よって,より正確な本問の解答は,積分 I l =1, 2 , 3 の値が,キッ
カリと 0 あるいは 1/2 とはならないが,各振動数の増加に伴い,0 あるいは 1/2 に近似できる,となる.
上述の議論をキチンと数式で表現できることも重要な能力である.例えば,式 (49) の第2項(これを,積
分 Ĩ 1 と記す)について,積分区間を次のように分解する.
2π s 1
∫
2π s 1
2π k ′
=
0
∫
+
0
∫
(52)
2π k ′
ここで, k ′ は,次式を満足する整数である.
s1 − 1 < k ′ < s1
(53)
したがって,三角関数は1を越える値をとらないことに着目すれば,以下の関係が成り立つ.
˜
I1 =
1
2π s1
2π s 1
∫
0
cos 2θ
1
dθ =
2
2π s1
2π s 1
∫
2π k ′
cos 2θ
1
dθ ≤
2
2π s1
2π s 1
∫
2π k ′
s − k′
1
π
dθ = 1
<
2
2 s1
2 s1
(54)
同様に,三角関数は−1未満をとらないことから,
1
I˜1 =
2π s1
となる. s1
2π s 1
∫
2π k ′
cos 2θ
π
dθ > −
2
2 s1
(55)
→ ∞ の極限を考えれば,ハサミウチの定理から,積分 Ĩ 1 はゼロに収束する.
theta/pi
0
3
6
9
12
0
0.25
0.5
0.75
1
T
theta/pi
0
3
0
0.25
6
9
0.5
0.75
12
1
T
図 -8 積分
Ĩ 1 の被積分関数: σ 1 = 12 π T ( s1 が自然数) と σ 1 = 12.3 π T ( s1 が実数)の場合
14
以下は,図 -8 を描くのに必要なコードである.
> twist(12)
> twist(12.3)
> tt <- seq(0, pi/2, by=pi/20) + 2*12*pi
> polygon(c(2*12*pi, tt), c(0, cos(tt)), col="black", border=NA)
> tt <- seq(0.3*2*pi, pi/2, by=-pi/20) + 2*12*pi
> polygon(c(2*12.3*pi, tt), c(0, cos(tt)), col="black", border=NA)
ところで,この問題に対して,何かオチが欲しいかもしれません,
.
.
. オチは,ひとまずオアズケです.
7) 式(7)を以下のように整理する.
f (t ) = a 0 × 1 +
 ak
 2
∞
∑
k =1
)
2 cos σ k t +
bk
2
(

2 sin σ k t 

)
b
 ak

f 2 k (t ) + k f 2 k −1 (t ) 

2
 2

∞
∑
= a 0 f 0 (t ) +
(
k =1
(56)
ここで, f j (t ) は式 (45) に示される関数である.上記の表現は,設問 5) における式 (17) に類似する.異
なる点は,式 (17) でベクトルであるところが関数となっていることと,式 (17) では有限個(3個)のベク
r*
トルの和であるが,無限個の総和であることだ.式 (17) の係数 c i は,正規直交ベクトル e i を両辺に掛
ける(つまり,内積をとる)ことにより得られたことを思い出せば,式 (56) に対しても,正規直交ベクト
ル f n (t ) との内積をとればよいことに気付く.したがって,係数 a 0 ,a k および b k は,
f , f0 = a0
f , f 2k =
⇒ a0 =
ak
⇒ ak =
2
f , f 2 k −1 =
bk
2
⇒ bk =
T
1
T
∫
2
T
T
∫
2
T
T
f (t ) dt
(57)
f (t ) cos σ k t dt
(58)
f (t ) sin σ k t dt
(59)
0
0
∫
0
と得られる.ただし, k は自然数である.式 (7) のような関数の展開をフーリエ級数展開とよび,式 (57)
~ (59) で得られた係数をフーリエ係数という.
テキストによっては,式 (57) で定まる係数 a 0 を採用せずに,式 (58) の係数 a k に a 0 を含めて, k を非
負の整数とする表現が用いられることもある(その場合,式 (58) にて k = 0 としたものは,式 (57) の2倍
になるので,式 (7) における係数 a 0 を a 0 2 に差替える,という調整が必要である)
.なお,本問では, そ
のような表現を採用せずに,係数 a 0 を特別扱いをする理由がある.式(57)によれば,係数 a 0 は関数 f n (t )
の平均という意味を持つからである.本問は, 表現の統一性よりも,意味を重視する立場である.
◇ 式 (7) において,有限個の和で打ち切る場合を考える.すなわち,関数
N
(
f (t ) = a˜ 0 + ∑ a˜ k cos σ k t + b˜ k sin σ k t
k =1
f (t ) は,
) + e (t )
(60)
として,残差関数 e (t ) を用いて表現される(ここでも, e (t ) を誤差関数とよばないのは,式 (28) での理由
に同じ)
.この時,係数 ã 0 , ã k および b̃ k の決定にあたり,残差関数の大きさが最小となるように,最小
自乗法を適用したい.さて,関数の大きさとは,なんだろうか? そんなものは,現時点ではまだ定義して
いないネ!.実は,大きさとは,距離で計る.ここでは,内積が式 (46) により定義されているので,関数(ベ
クトル) f に対する距離 f は,以下のように導入できる(これを,自乗平均平方距離とよぶ)
.
f =
f, f =
1
T
T
∫
f (t )
2
dt
(61)
0
15
関数
e
f (t ) は式 (7) で表されるので,残差の自乗平均は,以下のように得られる.
2
(
= a˜ 0 − a 0
)
2
{
∑ ( a˜
N
+
k =1
k
− ak
)
2
(
+ b˜ k − b k
)}+
2
e
2
min
≥
e
2
min
=
∞
a k2 + b k2
k = N +1
2
∑
(62)
したがって,
a˜ 0 = a 0 ;
a˜ k = a k ,
(k = 1 ~ N )
b˜ k = b k
(63)
2
2
の時, e は,最小値 e min をとる.以上から,フーリエ級数展開は,任意の関数を被説明変数にとり,
三角関数を説明変数として,最小自乗法であてはめたものであることがわかる.また,別の言い方をすれ
ば,フーリエ級数展開とは,三角関数で張られた平面への射影ベクトルである.
なお,式 (60) の表現には,無限の総和を含むため,その注意が必要である.ところで,テーラー展開は関
数展開として基本であるが,その場合も,総和級数の収束性については議論が必要であったことを思い出し
てほしい.フーリエ級数展開の場合も,もちろん,そのような収束性について注意を要する(その詳細は,
例えば,高木 (1961) を参照せよ)
.
8) 式(8)の関数 f (t ) を式(57),(58) および (59) に代入することにより,フーリエ係数
は,以下のように得られる.
T
1
a0 =
T
∫
2
ak =
T
T
∫
2
T
T
bk =
0
0
∫
t2
t dt =
2T
T
=
t =0
T
2
(64)
2 
t cos σ k t dt =
t sin σ k t
σ k T 
t sin σ k t dt =
0
a 0 , a k および b k
−2
σkT

 t cos σ k t

T
t =0
T
t =0

− ∫ sin σ k t dt  = 0

0
T
T

−T
− ∫ cos σ k t dt  =
πk

0
(65)
(66)
よって,
∞
f (t ) 1
1
2π k 
=
−∑
sin 

T
2 k =1 π k
T 
(67)
と表される.図 -9 において,太実線は式 (8) に示す原関数であり,細実線は式 (67) を有限項( k =第 N
項まで含む)で打ち切ったものである.両端点付近を除き, N の増加に伴い,細実線は太実線に近似され
0.6
0.4
0.2
original
N=3
N=6
N=9
0.0
f(t)/T
0.8
1.0
Fourier Series for f(t) = t
0.0
0.2
0.4
0.6
0.8
1.0
t/T
図 -9 式 (8) の関数とそのフーリエ級数展開
16
る様子がわかる.また,端点そのものは,式 (67) の左辺では,0 および 1 であるのに対し,式 (67) の右辺
では 1/2 となるので,両辺は一致しない(正確には,式 (8) を見るように,原関数は両端点で定義してい
ない.式 (67) の結果から,両端点では 1/2 として定義すればよい).さらに注目すべきは,端点を除く両
端点付近での細実線のふるまいである. N の増加に伴い,太実線からどんどん外れる.これをギブスの現
象という.
以下を実行すれば,図 -9 は得られる.
>
+
>
+
+
+
>
>
>
>
+
>
plot(c(0,1), c(0,1), type="l", lwd=2, xlab="t/T", ylab="f(t)/T",
ylim=c(-.05,1.05))
f.fourier <- function(t, N, period=1) {
res <- rep(period/2, length(t))
for (k in 1:N) res <- res - sin(2*pi*k*t)*period/pi/k
res}
lines(t, f.fourier(t, 3), col="gray")
lines(t, f.fourier(t, 6), col="red")
lines(t, f.fourier(t, 9), col="blue")
legend(.7, .3, c("original", paste("N =", c(3,6,9))), lty=1,
lwd=c(2, rep(1, 3)), col=c("black", "gray", "red", "blue"))
title("Fourier Series for f(t) = t")
9) ここで前提としている計算環境は R である.FFT のルーチンは fft であるので,以下のようになる.
> fft(1:8)
[1] 36+0.000000i -4+9.656854i -4+4.000000i -4+1.656854i -4+0.000000i
[6] -4-1.656854i -4-4.000000i -4-9.656854i
なんだかよくわからない結果が得られたと感じるかも知れない.FFT のルーチンによる結果の第1の特徴
は,複素数である点だ! 入力した数列と出力される複素数の数列の長さは同じである点も見逃せない.ち
なみに,逆変換は,次のとおりである.
> fft(.Last.value, inverse=TRUE)
[1] 8-8.881784e-16i 16+2.664535e-15i 24-2.664535e-15i 32-2.664535e-15i
[5] 40+8.881784e-16i 48-8.881784e-16i 56+2.664535e-15i 64+8.881784e-16i
> zapsmall(.Last.value)
[1] 8+0i 16+0i 24+0i 32+0i 40+0i 48+0i 56+0i 64+0i
もとの数列に戻るのではなく,8倍されている! もし,Mathematica を計算環境にしている場合は,
$ math
Mathematica 3.0 for Linux
Copyright 1988-97 Wolfram Research, Inc.
-- Terminal graphics initialized -In[1]:= Fourier[Table[j, {j, 1, 8}]]
Out[1]= {12.7279 + 0. I, -1.41421 - 3.41421 I, -1.41421 - 1.41421 I,
>
-1.41421 - 0.585786 I, -1.41421 + 0. I, -1.41421 + 0.585786 I,
>
-1.41421 + 1.41421 I, -1.41421 + 3.41421 I}
In[2]:= InverseFourier[%]
-16
-16
Out[2]= {1. + 0. I, 2. + 1.10999 10
I, 3. - 3.13985 10
I,
-16
-17
>
4. - 2.94994 10
I, 5. + 0. I, 6. - 1.90247 10
I,
-16
-16
>
7. + 3.13985 10
I, 8. + 2.0302 10
I}
In[3]:= Chop[%]
Out[3]= {1., 2., 3., 4., 5., 6., 7., 8.}
となる. あれれ! 結果が異なるヨ!! ただし,第2項と最終項などのペアは,共役複素数の関係になっ
17
ていること,そして,そのように共役複素数のペアが作れない項(第1項と,この例では,第5項)も虚
部がゼロとなっていることは,共通している.これは,FFT のルーチンによる結果の第2の特徴である.
表計算ソフトでも FFT は使えるものもある.残念ながら,OpenOffice ではできないようである.Microsoft
Office の Excel は,分析ツールをインストールすれば,第1コラム(A)に対する FFT の演算結果を第2
コラム(B)に出力して,以下のように得られる.逆変換は,第3コラム(C)に出力している.
1
2
3
4
5
6
7
8
A
1
2
3
4
5
6
7
8
B
36
-3.99999999999999+9.65685424949238i
-4+4i
-3.99999999999999+1.65685424949238i
-4
-4-1.65685424949238i
-4-4i
-4.00000000000001-9.65685424949238i
C
1
2
3
4
5
6
7
8
matlab では,以下のように, Microsoft Office の Excel とほぼ同じ結果である.
To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.
>> fft(1:8)
ans =
Columns 1 through 4
36.0000
-4.0000 + 9.6569i
-4.0000 + 4.0000i
-4.0000 + 1.6569i
Columns 5 through 8
-4.0000
-4.0000 - 1.6569i
-4.0000 - 4.0000i
-4.0000 - 9.6569i
>> ifft(ans)
ans =
Columns 1 through 4
1.0000
2.0000 + 0.0000i
3.0000 + 0.0000i
4.0000 + 0.0000i
Columns 5 through 8
5.0000
6.0000 - 0.0000i
7.0000 - 0.0000i
8.0000 - 0.0000i
R の先祖の1つである LISP-STAT (その実行媒体が, xlispstat )では,
$ xlispstat
XLISP-PLUS version 3.04
Portions Copyright (c) 1988, by David Betz.
Modified by Thomas Almy and others.
XLISP-STAT Release 3.52.16 (Beta).
Copyright (c) 1989-1999, by Luke Tierney.
> (fft (iseq 1 8))
#(#C(36.0 0.0) #C(-3.9999999999999925 9.656854249492378) #C(-4.0 4.0)
#C(-3.999999999999999 1.6568542494923824) #C(-4.0 0.0) #C(-4.00000000
0000002 -1.656854249492378) #C(-4.0 -4.0) #C(-4.000000000000008 -9.65
6854249492383))
> (fft * t)
#(#C(8.0 0.0) #C(16.000000000000004 -1.3720995995543063E-14) #C(24.0
1.2434497875801753E-14) #C(31.999999999999993 1.4609174415243188E-14
) #C(40.0 0.0) #C(48.0 4.898587196589414E-16) #C(56.0 -1.243449787580
1753E-14) #C(64.0 -1.3780371393590666E-15))
となる.なんだか相当に読みにくいが, 逆変換も含め R の結果と同じである.このように,ソフトウェア
に依存して結果が異なる原因は,
.
.. ひとまず,ヒミツにしておこう(その種明かしは,次問の解答の
後で)
.ここでは,あと幾つかの数列の FFT を見ておこう.
18
> # example 1
> fft(c(1, 1))
[1] 2+0i 0+0i
> fft(c(1, -1))
[1] 0+0i 2+0i
いずれも,虚部はゼロである.ところで,2次元平面の正規直交ベクトルは,
r
1  1 
1  1 r
e1 =
 , e2 =
 
2  −1 
2  1
(68)
の2つであり,上の計算は,2次元平面の直交ベクトルを FFT により変換したことになる.また,
> fft(1:2)
[1] 3+0i -1+0i
> c(1, 1) * 3/2 + c(1, -1) * (-1/2)
[1] 1 2
> fft(c(1, 1)) * 3/2 + fft(c(1, -1)) * (-1/2)
[1] 3+0i -1+0i
という点で,FFT による変換操作は線形である(第3の特徴)ことが確認できる.以上から,2次元平面
内の任意のベクトルを変換しても,虚部は必ずゼロとなる.これは,前述した第2の特徴からもいえる.
> # example 2
> fft(c(1, 1, 1))
[1] 3+0i 0+0i 0+0i
> fft(c(2, -1, -1))
[1] 0+0i 3+0i 3+0i
> fft(c(0, 1, -1)*sqrt(3))
[1] 0+0i 0-3i 0+3i
3次元空間の正規直交ベクトルは,
 1
r
1   r
e1 =
1 , e2 =
3 
 1
 2 
r
1 2
−1  , e 3 =

3 2
 −1 
 0 
1 2
3 

3 2
 − 3
(69)
の3つである.この場合は,数列(ベクトル)の長さが奇数であるので,共役複素数のペアにならないの
は,第1項のみである.そして,虚部がゼロでない場合もでてきたゾ! 式 (69) において,ワザと変な係
数のとりかた等をしているのは少々ワケありだ.実は,式 (69) のベクトルは,三角関数により生成するこ
とができる.
> (cos(2*pi*0:2/3 *0) -> cos0by3)
[1] 1 1 1
> (cos(2*pi*0:2/3)
-> cos1by3)
[1] 1.0 -0.5 -0.5
> (sin(2*pi*0:2/3)
-> sin1by3)
[1] 0.0000000 0.8660254 -0.8660254
> sqrt(3)/2
[1] 0.8660254
もちろん,式 (68) の2次元ベクトルにも当てはまる.
> (cos(2*pi*0:1/2 *0) -> cos0by2)
[1] 1 1
> (cos(2*pi*0:1/2 *1) -> cos1by2)
[1] 1 -1
19
FFT の第4の特徴(これが,最も重要)として,三角関数から生成される直交ベクトルに対して,FFT の
計算結果は,出力される数列における1項もしくは2項(この場合は共役複素数)を除いて全てゼロとな
る.また,ゼロでない複素数も,実部か虚部のいずれかはゼロである.残りのゼロでない値が,数列の何
番目にあるか,それが実部か虚部か,ということを見れば,振動数と種類(余弦/正弦)を識別できると
いうワケだ.これは,式 (45) と (47) で表される三角関数の直交性に基づく.次の計算結果を参照せよ.
> sum(cos0by3 * cos1by3) # = exactly zero, which means orthogonality
[1] -2.220446e-16
> sum(cos0by3 ^2)
[1] 3
> zapsmall(fft(cos0by3))
[1] 3+0i 0+0i 0+0i
> sum(cos1by3 ^2)
[1] 1.5
> zapsmall(fft(cos1by3))
[1] 0.0+0i 1.5+0i 1.5+0i
> sum(sin1by3 ^2)
[1] 1.5
> zapsmall(fft(sin1by3))
[1] 0+0.0i 0-1.5i 0+1.5i
さらに,4次元の直交ベクトルを三角関数を用いて生成し,各々の FFT をとれば,以下のようになる.
> zapsmall( fft(cos(2*pi*0:3/4
)) )
[1] 0+0i 2+0i 0+0i 2+0i
> zapsmall( fft(sin(2*pi*0:3/4
)) )
[1] 0+0i 0-2i 0+0i 0+2i
> zapsmall( fft(cos(2*pi*0:3/4 *2)) )
[1] 0+0i 0+0i 4+0i 0+0i
> zapsmall( fft(cos(2*pi*0:3/4 *0)) )
[1] 4+0i 0+0i 0+0i 0+0i
また,8次元の直交ベクトルについても,同様に,
> zapsmall( fft(cos(2*pi*0:7/8
)) )
[1] 0+0i 4+0i 0+0i 0+0i 0+0i 0+0i 0+0i
> zapsmall( fft(sin(2*pi*0:7/8
)) )
[1] 0+0i 0-4i 0+0i 0+0i 0+0i 0+0i 0+0i
> zapsmall( fft(cos(2*pi*0:7/8 *2)) )
[1] 0+0i 0+0i 4+0i 0+0i 0+0i 0+0i 4+0i
> zapsmall( fft(sin(2*pi*0:7/8 *2)) )
[1] 0+0i 0+0i 0-4i 0+0i 0+0i 0+0i 0+4i
> zapsmall( fft(cos(2*pi*0:7/8 *3)) )
[1] 0+0i 0+0i 0+0i 4+0i 0+0i 4+0i 0+0i
> zapsmall( fft(sin(2*pi*0:7/8 *3)) )
[1] 0+0i 0+0i 0+0i 0-4i 0+0i 0+4i 0+0i
> zapsmall( fft(cos(2*pi*0:7/8 *4)) )
[1] 0+0i 0+0i 0+0i 0+0i 8+0i 0+0i 0+0i
> zapsmall( fft(cos(2*pi*0:7/8 *0)) )
[1] 8+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
4+0i
0+4i
0+0i
0+0i
0+0i
0+0i
0+0i
0+0i
となる.出力される複素数列の規則性と線形性から,FFT の出力を見れば,元の数列が三角関数による数
列の和でどのように表現できるか,ということは簡単に逆算できる.以下は,fft(1:8) の結果から,逆
変換を用いずに“手作業で”
,元の数列に戻ることを示したものである.
20
8
6
4
0
2
fn
1
2
3
4
5
6
7
8
Index
図 -10 等差級数 1:8 とそのフーリエ級数展開
> fn <- 36/8
> (fn <- ((-4)
* cos(2*pi*0:7/8
) +
+
(-9.656854) * sin(2*pi*0:7/8
))/4 + fn)
[1] 3.500000 2.085786 2.085787 3.500000 5.500000 6.914214 6.914213 5.500000
> plot(fn, type="b", ylim=c(0, 8))
> (fn <- ((-4)
* cos(2*pi*0:7/8 *2) +
+
(-4)
* sin(2*pi*0:7/8 *2))/4 + fn)
[1] 2.500000 1.085786 3.085787 4.500000 4.500000 5.914214 7.914213 6.500000
> points(fn, type="b", col="blue")
> (fn <- ((-4)
* cos(2*pi*0:7/8 *3) +
+
(-1.656854) * sin(2*pi*0:7/8 *3))/4 + fn)
[1] 1.5 1.5 3.5 3.5 5.5 5.5 7.5 7.5
> points(fn, type="b", col="darkgreen")
> (fn <- ((-4)
* cos(2*pi*0:7/8 *4))/8 + fn)
[1] 1 2 3 4 5 6 7 8
> points(fn, type="b", col="magenta")
10) 前問において,8次元のベクトルとして三角関数の fftを調べた際,振動数は4回までしか検討し
ていない.振動数が5回以上の8次元のベクトルのfftはどうなるであろうか?例えば,振動数5回では,
> zapsmall( fft(cos(2*pi*0:7/8 *5)) )
[1] 0+0i 0+0i 0+0i 4+0i 0+0i 4+0i 0+0i 0+0i
> zapsmall( fft(sin(2*pi*0:7/8 *5)) )
[1] 0+0i 0+0i 0+0i 0+4i 0+0i 0-4i 0+0i 0+0i
なんと! 3回の振動に対する fft の結果と全く同じである.
図 -1 の区間で同じだけ目盛りをとって,振動数が1∼12回の三角関数を描いてみよう.2回の振動と
10回の振動は,もちろん波形は異なるが,目盛りでの波形の値は全く同じである(図 -11 を参照).した
図 -11 キチンと見えましたか?
21
1
2
3
4
5
6
7
8
9
10
11
12
図 -12 振動数1∼12回の波形を12点で計測(左:余弦波形,右:正弦波形)
がって,当然,fft による結果は同じになる.
> zapsmall( fft(cos(2*pi*0:11/12 *2)) )
[1] 0+0i 0+0i 6+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 6+0i 0+0i
> zapsmall( fft(cos(2*pi*0:11/12 *10)) )
[1] 0+0i 0+0i 6+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 6+0i 0+0i
これは,大問題である! 本問の答は,2波あるいは10波という,2つの可能性がありうるわけだ!
スペクトル解析では,答が2つにならないように,取り決めを行う.つまり,
ナイキスト周波数を最も周波数の高い周波数とする
のである.ナイキスト周波数とは,計測の時間間隔の2倍を周期とする周波数である.本問の場合は,区
間を12で刻んでいるので,振動数 6が上限である.したがって,余弦成分は,公比が −1の振動級数で
あるが,正弦成分は全てゼロであり,振動級数ではないことに注意する(図 -12 を参照).
> zapsmall(cos(2*pi*0:11/12*6))
[1] 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1
> zapsmall(sin(2*pi*0:11/12*6))
[1] 0.000000e+00 1.224650e-16 -2.449290e-16 3.673940e-16 -4.898590e-16
[6] 6.123230e-16 -7.347880e-16 8.572530e-16 -9.797170e-16 1.102182e-15
[11] -1.224647e-15 4.899825e-15
FFT の第2の特徴として前述したとおり,第1項めを除いて,共役複素数のペアとならない複素数は,虚
部がゼロであり,それはナイキスト周波数で振動する正弦成分を表している(ゼロではない実部が余弦成
分).また,振動数ゼロの余弦関数は,常に1となる定数項を意味し,FFT では,第1項の実部に現れる.
FFT でゼロとなる第1項の虚部は,振動数ゼロの正弦成分(ゼロだけの数列)である(図 -12 を参照).
22
> zapsmall(cos(2*pi*0:11/12*0))
[1] 1 1 1 1 1 1 1 1 1 1 1 1
> zapsmall(sin(2*pi*0:11/12*0))
[1] 0 0 0 0 0 0 0 0 0 0 0 0
また,数列の長さが奇数の場合には,ナイキスト周波数に一致する周波数の成分は現れずに,第1項を除
き,残りは共役複素数のペアとなる.例えば,以下のような11個の数列の場合をみよ.
> fft(1:11)
[1] 66.0+ 0.0000000i -5.5+18.7312798i -5.5+ 8.5581671i -5.5+ 4.7657771i
[5] -5.5+ 2.5117658i -5.5+ 0.7907806i -5.5- 0.7907806i -5.5- 2.5117658i
[9] -5.5- 4.7657771i -5.5- 8.5581671i -5.5-18.7312798i
共役複素数は,一方が定まれば,他方は自動的に決まる(他方は,従属している).したがって,独立し
ている数字の個数は,偶数長の数列の場合,(N−2)/2 個の共役複素数の実部と虚部(×2)+2個
の共役複素数とならない項の実部(虚部は必ずゼロ)の合計 = N個となり,FFT の入力と出力の個数は
一致する.奇数長さの場合も,
(N−1)/2 個の共役複素数の実部と虚部(×2)+1個の共役複素数
とならない項の実部(虚部は必ずゼロ)の合計 = N個となり,独立している数字の個数は,入力と出力で
過不足なしに一致する.このことも,FFT の特徴の1つと言えよう.
ナイキスト周波数のルールに従えば,本問の答えは2波である.実際のところ,図 -1 は,以下を実行す
ることにより描かれている(! 以下のコードだけを見ても,2波とは言えないことが以上の議論である!)
>
>
>
>
plot(0:12, cos(2*pi*0:12/6), xlab="", ylab="", axes=F, ylim=c(-2,2))
arrows(0, 0, 12, 0, angle=90, length=.1, code=3)
segments(1:11, rep(0, 11), 1:11, rep(.2, 11))
points(0:11, cos(2*pi*0:11/6), pch=16)
> # lines(t, cos(2*pi*t/12*2))
# for Fig.11
> # lines(t, cos(2*pi*t/12*10), lty=3) # for Fig.11
◇ 本問は,データが与えられて,どのように解析すべきか?という立場である.もし,このデータが,本
当は10波の現象を観測したデータであるならば,データから本当の現象を再現できないことになる.つ
まり,この問題は解析する立場にあるのではなく,観測する立場にある.したがって,観測に先立ち,振
動現象の最高周波数がナイキスト周波数より小さくなるように,時間間隔を定める必要がある.
◆ あらためて,fft(1:8) が三角関数との内積として得られることを確認する.
> sum((1:8) * exp(-2i*pi*0:7/8
[1] 36+0i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4+9.656854i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4+4i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4+1.656854i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4-3.91887e-15i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4-1.656854i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4-4i
> sum((1:8) * exp(-2i*pi*0:7/8
[1] -4-9.656854i
*0))
*1))
*2))
*3))
*4))
*5))
*6))
*7))
> fft(1:8)
[1] 36+0.000000i -4+9.656854i -4+4.000000i -4+1.656854i -4+0.000000i
[6] -4-1.656854i -4-4.000000i -4-9.656854i
一般的な表現として,長さ
(
)
N の実数値の数列 f n = 0 ~ ( N −1) = f t 0 + n∆ t に対する FFT は,以下の長さ
23
N の複素数値の数列を算出することである.
N −1
∑
c ′k =
n=0
この時,k
f n exp −

2π i k n 
N 
(70)
= 0 および k = N 2 ( k が偶数の時)を除き,
 2π i (N − k) n 
 2 π k n  + i sin 2 π k n  = exp − 2 π i k n  
exp  −
 = cos

 N   
N
N 
N 


であるので,次のように, c ′N − k と c ′k は共役複素数の関係にあることがわかる.
*
( )
c ′N − k = c ′k
(71)
*
(72)
逆変換は,fft(1:8) に対して,次のように得られる.
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *0)) )
[1] 8+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *1)) )
[1] 16+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *2)) )
[1] 24+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *3)) )
[1] 32+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *4)) )
[1] 40+0i
> zapsmall( sum(fft(1:8) * exp(-2i*pi*0:7/8 *5)) )
[1] 32+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *6)) )
[1] 56+0i
> zapsmall( sum(fft(1:8) * exp(+2i*pi*0:7/8 *7)) )
[1] 64+0i
> zapsmall( fft(fft(1:8), inverse=TRUE) )
[1] 8+0i 16+0i 24+0i 32+0i 40+0i 48+0i 56+0i 64+0i
したがって,一般的に逆変換を表せば,以下のとおりとなる.
1
fn =
N
N −1
∑ c′ exp
k
k =0
2π i k n 
N 
(73)
式 (70) と (73) を組み合わせれば,次式が得られる.これをフーリエの恒等式という.
fn =
1
N
N −1 N −1
∑∑
k =0 j =0
f n exp −

2 π ij k 
2π i k n 
exp
 N 
N 
(74)
フーリエの恒等式の分解は,式 (70) と (73) に限らない.例えば,分配を平等にとれば,
c ′′k =
1
N
N −1
∑
n=0
f n exp −

2π i k n 
,
N 
fn =
1
N
N −1
∑ c′′ exp
k
k =0
2π i k n 
N 
(75)
となる.Mathematica の Fourier は,この分解を行うものであることがわかる.
> fft(1:8)/sqrt(8)
[1] 12.727922+0.0000000i -1.414214+3.4142136i -1.414214+1.4142136i -1.414214+0.5857864i
[5] -1.414214+0.0000000i -1.414214-0.5857864i -1.414214-1.4142136i -1.414214-3.4142136i
なお,FFT とは,Fast Fourier Transform の頭文字をとったものであり,式 (70) と (73) などについて効率的
な演算処理を行うアルゴリズムを指す.したがって, ここで説明したような,三角関数との内積を逐一計
算しない.ここでは,FFT の入出力に着目して解説を行っており,FFT の高速( Fast )に相当する解説は,
Cooly・Tukey (1965) を参照せよ.数列の長さが2のベキ数の場合に最も効率的であることは,よく知られ
ている.
24
◇ 調和解析との関連性(再び!である. # 16 では,連続関数の場合に,その関連性を検討している)
:
ここで扱うのは,関数が時刻 t n = t 0 + (n − 1) ∆ t , n = 1 ~ N において離散化されている場合である.
設問 1)の表記に従い,縦ベクトル x j を成分とする行列 X を用いよう( x 1 は使用しない).
{
X = x 0 , x 2 , x 3 , ... ,
x m −1
}
(76)
設問 3)では,ベクトル x j は三角関数そのものを用いているが,式 (45) と (75) を参考にして,
x0 =
1
, x 2k =
N
2
2π k n 
cos 
, x 2 k −1 =

N
N 
ととる場合を考える.第1ベクトル
2
2π k n 
sin 

N
N 
(77)
x 0 は,振動しない成分(=定数項)の役割をする.この時,
x ′i x j = x i ⋅ x j = δ ij
(78)
となる( δ ij は,クロネッカーの記号を表し, i と j が等しい時に1を,異なる時にゼロを表す)ので,
ベクトル x j は正規直交ベクトルである ( j ≠ 1 ) .また,行列 X ′X は,
 x 2
0

X ′X =  x 2 ⋅ x 0

...

x 0 ⋅ x2
x2
2
...
x 0 ⋅ x 3 ... 

x 2 ⋅ x 3 ... 
...
... 

(79)
となり,その成分は式 (78) の内積で表されることに注意すれば,単位行列であることがわかる.すなわち,
X ′X
である.これを式 (3) に代入すれば,係数
=I
(80)
β̂β は得られる.
β̂
β=
X′ y
(81)
上式の左辺は,縦ベクトルであり,その第 j 成分は,
β̂ j
= x ′j y = x j ⋅ y
(82)
であり,これは,式 (57),(58) および (59) で表されるフーリエ係数に相当する( N 2 倍の違いは有).
さて,連続関数の場合は,縦ベクトルの個数 m を無限にとることができたけれど,離散化された時刻
でのみ値をもつ時系列に対しては,縦ベクトルのとりうる最大の個数は,時系列の長さ N である.最大
個数の縦ベクトルを用いた時には,行列 X は正方行列となる.また,式 (80) より, X の逆行列は,転置
行列 X ′ である.さらに,設問 5)での射影ベクトルの知識を思い出せば,ベクトル y の次元(= 時系
列の長さ)と射影平面の次元(=縦ベクトルの個数)が一致しているので,残差ベクトルはゼロとなる.す
なわち,式 (1) は,
y = Xβ + 0
(83)
と表すことができる.したがって,この場合には特別に,式 (2) に示す正規方程式を用いることなく,
β = X′ y
(84)
として係数 β が得られる.
式 (83) には残差がないので,式 (84) をよく見ると,係数 β にはハット(^)が付いていない?! 時系
列のスペクトル解析とは,無限に続く時系列の一部を観測して標本時系列を得て,それを基に母スペクト
ルを推定するものである.この場合には,統計的誤差というものは,どこに消えたのであろうか??!
(式 (84) の係数 β もハットを付けて,推定値 β̂
β とすべきである.この件については別の機会に検討する)
◇ 設問 8)と 9)の答えの比較: 設問 9)の数列は,設問 8)の式 (8) で与えられる直線を観測して
得られる.式 (67) には,定数関数と正弦関数のみが現れており,余弦関数が含まれない.にもかかわらず,
設問 9)の等差数列に対する FFT の結果には,# 21 を見るとおり,余弦関数による振動数列が含まれて
いる.なぜだろうか?!
25
Discrete
Continuous
a) 設問 9)の等差数列
b) 設問 8)の直線
図 -13 類似品に御注意!
Fourier coefs.
5
10
15
cos−component: i=even
sin−component: i= odd
0
Amplitude: a_(i/2) or b_((i+1)/2)
20
By Many Dots
0
10
20
30
40
50
60
i
図 -14 1:64 の等差数列
図 -15 各成分波の振幅
この答えは,実は,図 -1 の白丸に隠されている.設問9)の等差数列を白丸付きで図示したものが,図
-13 a である(対比のために,設問8)の直線も図 -13 b に示す).図を見て明らかなように,等差数列は,
点対称でも線対称でもない.一方,直線は,点対称である.したがって,設問8)の答えは,点対称であ
る正弦関数のみで記述される.そして,等差数列は,点対称ではないので,線対称である余弦関数も含ま
れるワケである(点対称でも線対称でもないので,点対称と線対称の両方の関数を用いる,という発想が
オモシロイですね,..
. そもそも直線を曲線で表す,という発想もオドロキですネ!)
.以上の観点から,
図 -14 に示すような比較的長い等差数列であれば,近似的に点対象とみなせるので,たとえ余弦関数が現
れても,その寄与が小さいことは予想できる(図 -15 に結果を示す).
>
+
+
+
+
+
+
+
+
asym <- function(len) {
plot(1:(len +1), c(1:len, 1) - (len+1)/2,
xlab="", ylab="", axes=F, ylim=c(-1,1)*len*1.05/2)
arrows(1, 0, len +1, 0, angle=90, length=.1, code=3)
segments(2:len, rep(0, len-1), 2:len, rep(.2, len-1))
points(1:len, 1:len - (len+1)/2, pch=16)
abline(h=c(-1,1)*len*1.05/2, lty=2)
x <- seq(1, len +1, length=100)
lines(x, sin(2*pi*(x - 1)/len)*len*1.05/2, col="blue")}
>
>
>
>
>
par(mfrow=c(1,2)) -> op; asym(8); title("Discrete")
plot(c(0, 2*pi), c(-.95, .95), type="l", lwd=2, axes=F, xlab="", ylab="")
arrows(0, 0, 2*pi, 0, angle=90, length=.1, code=3)
abline(h=c(-1,1), lty=2)
curve(sin, 0, 2*pi, col="blue", add=T); title("Continuous")
26
> asym(64); title("By Many Dots")
> (fft(1:64)[64:33]/c(rep(32, 31), 64) -> ab)
[1] -1.0-20.35546762i -1.0-10.15317039i -1.0[5] -1.0- 3.99222378i -1.0- 3.29655821i -1.0[9] -1.0- 2.11432236i -1.0- 1.87086841i -1.0[13] -1.0- 1.34834391i -1.0- 1.21850353i -1.0[17] -1.0- 0.90634717i -1.0- 0.82067879i -1.0[21] -1.0- 0.59937693i -1.0- 0.53451114i -1.0[25] -1.0- 0.35780572i -1.0- 0.30334668i -1.0[29] -1.0- 0.14833599i -1.0- 0.09849140i -1.0>
+
>
>
+
>
6.74145241i
2.79481277i
1.66839921i
1.10332998i
0.74165055i
0.47296478i
0.25048696i
0.04912685i
-1.0-1.0-1.0-1.0-1.0-1.0-1.0-0.5+
5.02733949i
2.41421356i
1.49660576i
1.00000000i
0.66817864i
0.41421356i
0.19891237i
0.00000000i
plot(2*(1:32)-1, abs(Im(ab)), type="h", col="blue",
xlab="i", ylab="Amplitude: a_(i/2) or b_((i+1)/2)")
lines(2*(1:32), abs(Re(ab)), type="h", col="red")
legend(20, 20, c("cos-component: i=even",
"sin-component: i= odd"), lty=1, col=c("red","blue"))
title("Fourier coefs.")
◆ フーリエ変換: 実数軸全体を定義域とする関数に対するフーリエ展開
関数 f ( t ) の原点を移動し,積分範囲をひとまず ( − T 2 , T 2 ) に変更すれば,式 (58) および (59) を
次のように再定義できる.
2
ak =
T
T 2
2
f (t ) cos σ k t dt , b k =
∫
T
−T 2
T 2
∫
f (t ) sin σ k t dt
(85)
−T 2
この時,次の数列 c k を定義する.
ck =
なお, 上式には,k
c−k =
a k − i bk
2
1
=
T
T 2
∫
(
)
f (t ) exp − i σ k t dt
−T 2
(86)
= 0 の場合も含めることができる.また,負の項 c − k も以下のように定義する.
a k + i bk
=
2
以上により定義された係数
(
(
1
T
T 2
∫
(
)
f (t ) exp − i σ − k t dt, σ − k =
−T 2
− 2π k
T
(87)
c k は,式 (85) の係数 a k および b k と以下の関係がある.
)
)
(
)
(k ≠ 0)
 c k exp i σ k t + c − k exp i σ − k t = a k cos σ k t + b k sin σ k t


= a0
 c 0 exp i σ 0 t
(k = 0)
(88)
したがって,式 (7) は,以下のように整理できる.
∞
f (t ) =
∑c
k
積分範囲でキッカリ1回振動する角周波数
(
exp i σ k t
k = −∞
)
(89)
σ 0 を基準として,特別に,
δσ =
σ0 =
2π
T
(90)
と表して,式 (86) および (87) を式 (89) に代入すると,次式が得られる.
f (t ) =
∞
∑
k = −∞
この時,積分範囲について,極限
δσ
2π
T 2
∫ dt ′ f (t ′) exp ( − i σ t ′ ) exp( i σ t )
k
k
(91)
−T 2
T → ∞ をとれば, δσ → dσ となって総和は積分に変更される.よっ
27
て,式 (91) は,次のように表せる.
1
f (t ) =
2π
∞
∞
−∞
−∞
∫ dσ ∫ dt ′ f (t ′) exp ( − i σ t ′ ) exp( i σ t )
(92)
これは,FFT における式 (74) のフーリエの恒等式に相当する.これについて,
fˆ (σ ) =
∞
∫
f (t ) exp ( − i σ t ) dt ,
f (t ) =
−∞
1
2π
∞
∫
fˆ (σ ) exp( i σ t ) dσ
(93)
−∞
と分解したり,
fˆ (σ ) =
1
2π
∞
∫
f (t ) exp ( − i σ t ) dt ,
f (t ) =
−∞
1
2π
∞
∫
fˆ (σ ) exp( i σ t ) dσ
−∞
(94)
と分解して,各々の第1式をフーリエ変換,第2式をフーリエ逆変換とよんでいる.
なお,式 (91) において,積分区間を ( 0, T ) に戻し,関数 f が等時間間隔 ∆t で離散化されている時,
t ′ = j ∆t
( j = 0 ~ N − 1 ),
t = n∆t
( n = 0 ~ N −1)
(95)
などと置換え,適切に整理すれば,式 (91) は,以下のように変形できる.
fn =
1
T
N −1 N −1
∑ ∑ ∆t
k =0
(
) (
f j exp − i σ k j ∆ t exp i σ k n ∆ t
j =0
)
(96)
ところで, T = N ∆ t であることから,上式における全ての ∆t は消去されて,式(74)を得る.つまり,FFT
の計算において,総時間 T も,時間間隔 ∆t も必要ないということである(fft の引き数は数列だけで
あることから,明らかであるが,改めて確認しておく価値はあると思う).
11) 設問2)で読み込んだ名古屋の潮位データ( nagoya )を用いて, fft に入力する.
> nagoya[121:132] # am. 06-Jan.
[1] 89 110 148 193 235 269 287 286 266 233 197 172
> 24*14
[1] 336
> (fft(nagoya[121:132])[12:7 ]/c(rep( 6, 5), 12) -> amplitudes.halfday)
[1] -85.404156-24.797005i -9.083333- 9.093267i -7.000000- 6.500000i
[4] -6.583333- 3.897114i -6.595844- 1.702995i -3.416667+ 0.000000i
> (fft(nagoya[121:168])[48:25]/c(rep(24, 11), 48) -> amplitudes.twodays)
[1] -1.10035525+2.006954177i -33.75212670+2.968298246i
7.96022900-1.316868227i
[4] -79.69691752-4.771820919i -6.04420578+0.850716130i
0.37796116+0.645220057i
[7] -1.41826043-0.395732247i -2.50000000+1.732050808i -0.98868094+0.393850455i
...
[22] -0.06918296+0.088918339i -0.20084759-0.043896468i -0.06250000+0.000000000i
> (fft(nagoya)[336:169]/c(rep(168, 167), 336) -> amplitudes.14days)
[1] 1.47479484+ 4.990665559i 3.10135958- 1.445188337i -2.90219182[4] -6.04490631- 3.600518461i 0.43331386+ 1.465980506i 1.40583581[7] 1.46722850+ 0.589234819i 0.69278410+ 2.150432815i 2.49566102...
[166] -0.15395520- 0.048280353i -0.10048268- 0.020828825i -0.04166667+
0.294395556i
0.077172908i
0.254930737i
0.000000000i
以上により得られた結果は,各周波数成分における複素振幅 a k + ib k (実部が余弦成分の,虚部が正弦
成分の振幅)である.したがって,各周波数成分に位相 ϕ k を導入すれば,
a k cos σ k t + b k sin σ k t =
(
a 2k + b 2k cos σ k t + ϕ k
)
(97)
となるので,上記の fft の計算で得られた複素数の絶対値が振幅を表す.
28
0
1
2
3
4
Frequency (cpd)
5
6
80
60
0
20
40
Amplitude (cm)
60
0
20
40
Amplitude (cm)
60
40
0
20
Amplitude (cm)
For Two Weeks
80
For Two Days
80
For Half Day
0
1
2
3
4
5
Frequency (cpd)
6
0
1
2
3
4
5
6
Frequency (cpd)
図 -15 振幅スペクトル
前問の最後の解説にあるように,FFT の計算では,総時間 T も,時間間隔 ∆t も必要ない.しかし,FFT
の計算結果を使用する上では, T あるいは ∆t のいずれかは必要である(級数を与えるので,級数の長さ
N は与えられると考えれば,∆t が与えられれば,T = N ∆ t により T は得られる).
それぞれ,総時間は,0.5日,2日あるいは14日であるので,周波数 [ cpd (= cycle per day) ] の刻み
∆ f ( = 1 T ) は,2, 0.5 あるいは 0.0714 (= 1/14) となる.時間の刻み幅は 1/24 であるので,いずれの場合
も,ナイキスト周波数は 12 cpd である.この時,振幅スペクトル(周波数と各周波数成分の振幅との関係
図)は,図 -15 のように表される(表示の見やすさのため,横軸は 6 cpd で打ち切っていることに注意).
半日分の観測データでは,1日に1回振動する成分は当然現れない.2日分のデータを用いれば,その
成分は現れる.つまり,データ数を増やせば,周波数の刻み幅 ∆ f がより小さくなるためである.これ
を“分解能が向上する”と表現する.勘違いを避けるために強調しておくことは,いずれの場合も時間の
刻みは等しいので,ナイキスト周波数は等しく,周波数のとりうる範囲は同じである.また,3つのグラ
フを比較して,得られる振幅の大きさが順に小さくなっていることが明確である.これは,周波数の分解
能に応じて,分解される成分数が増加するために生じている. ..
.となると,この図示表現は,チョット
まずくないだろうか? なお,図 -15 を描くためのコードは,以下のとおりである.
>
+
+
>
>
>
>
freq.amp.plot <function(ampser) plot(1:length(ampser)/(length(ampser)/12), abs(ampser), type="h",
lwd=2, xlim=c(0, 6), ylim=c(0,90), xlab="Frequency (cpd)", ylab="Amplitude (cm)")
par(mfrow=c(1,3)) -> op
freq.amp.plot(amplitudes.halfday); title("For Half Day")
freq.amp.plot(amplitudes.twodays); title("For Two Days")
freq.amp.plot(amplitudes.14days ); title("For Two Weeks"); par(op)
12) 正規分布に基づいて架空のデータを作成してもよいが,ここでは,ワイブル分布(2母数)を用
いよう.生成されるのは実数値であるため,整数化を行い,また,確率変数の定義域が無限大を含むた
め,100を越えるものは強制的に100点とした.なお,両者は同一の母分布からの標本とした.
>
>
>
>
>
>
rweibull(50, shape=2.5, scale=40) -> scores.50
scores.50 <- round(scores.50)
scores.50[scores.50 > 100] <- 100
rweibull(200, shape=2.5, scale=40) -> scores.200
scores.200 <- round(scores.200)
scores.200[scores.200 > 100] <- 100
区間(50 人分に対しては10点刻み,200 人分に対しては5点刻み)に含まれる人数を縦軸にとり,図
示したものを図 -16 に示す.両者を比較する上で,これは都合が悪い(ピンとこなければ,50 人分に対し,
5点刻みも描いてみよ).(人数)/(総人数)/(得点の刻み幅)を縦軸にとったものを図 -17 に示す.
この図が比較しやすいのは,面積が全確率1となるからであり,この場合の縦軸を確率密度とよぶ.
29
30
0
10
20
Frequency
20
0
10
Frequency
30
40
Histogram of scores.200
40
Histogram of scores.50
0
20
40
60
80
100
0
20
scores.50
40
60
80
100
scores.200
図 -16 50人分と200人分の成績の比較(?)
0.03
0.00
0.01
0.02
Density
0.02
0.00
0.01
Density
0.03
0.04
Histogram of scores.200
0.04
Histogram of scores.50
0
20
40
60
80
100
0
scores.50
20
40
60
80
100
scores.200
図 -17 50人分と200人分の成績の比較(!)
> par(mfrow=c(1,2)) -> op
> hist(scores.50, breaks=0:10*10, ylim=c(0, 40))
> hist(scores.200, breaks=0:20*5, ylim=c(0, 40))
>
>
>
>
>
hist(scores.50, breaks=0:10*10, prob=T, ylim=c(0, .04))
x <- seq(0, 100, length=200)
lines(x, dweibull(x, shape=2.5, scale=40), col="blue")
hist(scores.200, breaks=0:20*5, prob=T, ylim=c(0, .04))
lines(x, dweibull(x, shape=2.5, scale=40), col="blue"); par(op)
スペクトルの場合は,振動の強弱に応じて,面積の大小が変化する方がよい.そのため,面積が振動の
エネルギーを表すことが好ましい.したがって,図 -15 の縦軸は,
(エネルギー:振幅の自乗÷2)/(周
波数の刻み幅)とするべきである(図 -15 とは逆に,図 -18 では,スペクトル密度が順に増大していてマ
ズイのでは?と思うかもしれないが,この場合は,分解能の向上とともに,潮汐の振動に対応した周波数
にエネルギーが集中する度合いが顕著化していることを示している).なお,エネルギーを振幅の自乗のま
まで扱う(2で除さない)こともある.
> freq.dens.plot <+ function(ampser) plot(c(0, (0:length(ampser)+.5)/(length(ampser)/12)),
+
c(0, abs(ampser)^2*length(ampser)/12/10000, 0), type="s",
+ xlim=c(0,6), ylim=c(0,5), xlab="Frequency (cpd)", ylab="Density (m^2*day)")
>
>
>
>
par(mfrow=c(1,3)) -> op
freq.dens.plot(amplitudes.halfday); title("For Half Day")
freq.dens.plot(amplitudes.twodays); title("For Two Days")
freq.dens.plot(amplitudes.14days ); title("For Two Weeks"); par(op)
◇ 調和分解の考えには,周波数の刻みという概念はない.したがって,図 -15 の表現が正しい.した
がって,潮位に関しては,スペクトル解析の場合も 図 -15 を採用しても問題はない.もちろん,その場
合には,十分に高い分解能の場合に限る.
30
0
1
2
3
4
5
6
5
4
3
1
0
0
Frequency (cpd)
2
Density (m^2*day)
4
3
0
1
2
Density (m^2*day)
4
3
2
0
1
Density (m^2*day)
For Two Weeks
5
For Two Days
5
For Half Day
1
2
3
4
5
6
0
1
Frequency (cpd)
2
3
4
5
6
Frequency (cpd)
図 -18 エネルギー密度スペクトル
ところで, # 15 でのオアズケの件,設問 6)の c) にて,整数でない振動数に対して,振動数が十分
に大きければ,式 (49) の積分の値は 1/2 に,式 (51) のそれは, 0 に近似できることを示した.そこで,ま
ず,式 (70) を真似て,各分潮の振動数( sM 2 ,sS2 など)を用いて,次のようなベクトルを導入する.
x0 =
1
, x2 =
N
x4 =
2
2π sM 2 n 
cos 
, x1 =

N
N 
2
2π sM 2 n 
sin 
,

N
N 
2
2π sS 2 n 
cos 
,

N
N 
2
2π sS 2 n 
sin 
, ...

N
N 
x3 =
(98)
これらの分潮ベクトルを式 (76)のようにまとめて,行列 X で表した時,式 (80) を満足しない. sM 2 ,sS2
など(これらは,総時間に対する振動数であることに注意)は,各分潮の1日あたりの振動数( σ M 2 ,
σ S2 など)を用いて,
sM 2 = N σ M 2 , sS 2 = N σ S 2 , ...
と表せることから,データ数
(99)
N が十分に大きければ,振動数 sM 2 ,sS2 などが増大し, X ′X ≈ I
(100)
となる.以上は,設問 6) の c) の事柄をベクトル・行列による表現をしたことになる. したがって,式
(100) を式 (3) に代入すれば,次式を得る.
β̂β ≈ X′ y
(101)
200
100
nagoya
300
これは,式 (81) あるいは式 (84) が近似的に成立すること,すなわち,調和解析はフーリエ解析に近似で
きることを示している.このことを逆手に,フーリエ解析は調和解析に近似的できる,ととれば,前述
のとおり,潮位に関しては,スペクトル解析の場合も 図 -15 を採用しても問題はない,ワケになる.
(以上のことは,感覚的にはアタリマエのことだけど,ある程度キッチリいうことは有意義である.なぜな
0
2
4
6
8
10
12
14
days
図 -19 欠測のある潮位データ
31
ら,それらの違いが浮き出るためだ.上述の議論で,逆手にとるあたりにも両者の違いが現れるので,さ
らなる議論は必要であるが省略する)
◆ 調和解析の利点: データに欠測があっても構わない.具体的にいえば, # 3 でのデータ nagoya に関
して,仮に,1 月 3 日の観測値がなんらかの都合で入手できなかったとしよう.
> nagoya[24*3 + 1:24] <- NA
> plot(days, nagoya, type="o")
R では,欠測値を NA として扱う(Not Available).この時,調和解析を以下のように行うことができる.
> data.frame(nagoya,
+ cos.K1, sin.K1, cos.O1, sin.O1, cos.M2, sin.M2, cos.S2, sin.S2) -> nag
> lm(nagoya ~ cos.K1 + sin.K1 + cos.O1 + sin.O1 + cos.M2 + sin.M2 +
+
cos.S2 + sin.S2, data=nag[complete.cases(nag),])
Call:
lm(formula = nagoya ~ cos.K1 + sin.K1 + cos.O1 + sin.O1 + cos.M2 +
sin.M2 + cos.S2 + sin.S2, data = nag[complete.cases(nag), ])
Coefficients:
(Intercept)
201.638
cos.K1
-28.385
cos.M2
55.138
sin.K1
-4.929
sin.M2
27.230
cos.O1
14.590
cos.S2
-26.653
sin.O1
3.745
sin.S2
-13.320
完全データの結果(# 6 を参照)と類似していることが確認できる.なお,上の計算で,分潮の時系列は
完全データの場合と同じものを使っているものの,
データが欠測した部分を回帰の計算では除外している.
> dim(nag)
[1] 336
9
> dim(nag[complete.cases(nag),])
[1] 312
9
13) もはや前問から明らかである.周期を日(day)で,潮位を m で計る場合には,エネルギー密度は,
m2 day となる.また,
(現地)波浪データの場合には,周期を s で,水位変動を m で計るため, m2 s とな
る.なお,より正確な解答を求めるのであれば,室内実験も考慮し,水位変動を cm で計る場合もあるの
で,その際は,cm2 s となることを付記しておく.
なお,同じ意味で確率密度にも単位がある.図 -17 の縦軸の単位は,1/点数 である.
14) データのファイルを R に読み込む.scan を用いて読み取れば,データ長は 8192 であることを知ら
せてくれる.全てを図示しても,この用紙の幅では個々の波形を認識できないので,データのアタマだけ
を取り出して図示したものを図 -20 に示す.潮位波形とは様子が異なることが直感できるだろうか?
1
0
−2 −1
waves[1:400]
2
> scan("examplewaves.txt") -> waves
Read 8192 items
> plot(0.03125 * 1:400, waves[1:400], type="l", xlab="t")
0
2
4
6
8
10
12
t
図 -19 examplewaves.txt の波形(先頭のみを表示)
32
エネルギー密度スペクトルを表示する関数を以下のように定義する(以下の R の関数は,できるだけ初
心者にもコードが読めるよう,簡素に作成することを目的としている.そのため, データ長が偶数の場合
に限り適用できるものとして作成した).
>
+
+
+
+
+
+
+
+
+
+
spect2 <function(series, deltat, add=FALSE, ...) {
len <- length(series)
dens <- abs(fft(series)[len:(len/2+1)])^2*2*deltat/len
dens[len/2] <- dens[len/2]/4
freq <- c(0, 0:(len/2) +.5)/deltat/len
dens <- c(min(dens)/100, dens, 0)
if (add) lines(freq, dens, type="s", ...)
else plot(freq, dens, type="s", xlab="Frequency", ylab="Density", ...)
invisible(data.frame(frequency=(0:(len/2))/deltat/len,
density=dens[- (len/2 + 1)]))}
> spect2(waves, 0.03125, xlim=c(0, 3), col="gray70") -> spect.waves
> spect2(waves[1:256], 0.03125, add=T, col="blue")
せっかくなので,幾つかのスペクトルを描いておこう.図 -21 は,全データを用いたものを gray70 で,
先頭 256 個のデータを用いたものを blue で描いている.ナイキスト周波数 16 であるが,この図の場合
も見やすさのためから,横軸を打ち切っている.
> 1/2/0.03125
[1] 16
> spect.waves[c(1:7, 4096 +1),]
frequency
density
1
0.00000000 4.296667e-19
2
0.00390625 6.038755e-16
3
0.00781250 5.104503e-16
4
0.01171875 5.523221e-15
5
0.01562500 2.287275e-15
6
0.01953125 3.968993e-15
7
0.02343750 5.665754e-16
4097 16.00000000 4.296667e-19
10
種明かしをすれば,この波形は,次式に示すピアソン・モスコビッツ型スペクトルを母スペクトルとし
6
4
2
0
Density
8
Sample (8192)
Sample (256)
Population
0.0
0.5
1.0
1.5
2.0
2.5
3.0
Frequency
図 -21 examplewaves.txt のスペクトル
33
て,乱数発生により得られた標本波形である.
S( f ) = β f
−5
exp( − α f
−4
)
(102)
(これまでに,関数に記号 f を用いているので,周波数に記号 f を用いると混乱するので,反則じゃない
か!と指摘されれば,そのとおりである.しかし,いずれも慣用として用いられるので,ここではそれらを
採用した.上記が主な理由ではないだろうが,関数 f を用いる場合には,周波数ではなく,角周波数を用
い,他方,周波数 f を用いる分野では,関数に別の記号,例えば,水位変動 η を用いている.もっとも,
関数と変数であるので,大きな混乱を招くとは思えない,.
.
.その観点で,オブジェクト指向言語のように,
数学的な式にクラスを導入できれば問題は解決するのかもしれない.同類のことは,時系列の成分を識別す
るための index として i を用いると,虚数 i との混乱がある.そのため,虚数を j と記す分野もある.
)
図 -21 にて太線描いたものが,母スペクトルである.太線と細線を比較すれば,標本波形から得られる
スペクトル密度の誤差の特性が実感できる(相当に大きいネ!)
.
>
+
+
+
+
>
>
>
+
wallops <function(m, f){
alpha <- (gamma((m-1)/4)/gamma((m-2)/4))^4
beta <- 4 * gamma((m-1)/4)^(m-2)/gamma((m-2)/4)^(m-1)
beta * exp( - alpha * f^-4)/f^m }
freq <- seq(0, 3, length=200)
lines(freq, wallops(5, freq), lwd=2)
legend(2, 10, c("Sample (8192)", "Sample (256)", "Population"),
lty=1, col=c("gray70", "blue", "black"), lwd=c(1,1,2), bty="n")
波浪のスペクトルは,縦軸を対数表示することも多い.図 -22 は,図 -21 の縦軸を対数表示したものである.
>
>
>
>
+
spect2(waves, 0.03125, xlim=c(0,3), ylim=c(.001,10), col="gray70", log="y")
spect2(waves[1:256], 0.03125, add=T, col="blue")
lines(freq, wallops(5, freq), lwd=2)
legend(2, 10, c("Sample (8192)", "Sample (256)", "Population"),
lty=1, col=c("gray70", "blue", "black"), lwd=c(1,1,2), bty="n")
大数の法則は,統計的な誤差変動を減少させる効果がある.つまり,各区間を併合して,スペクトル密
度の平均をとればよい.平滑化されたスペクトルを図 -23 に示す.
1e+01
> apply(matrix(spect.waves$frequency[-1], 32), 2, mean) -> freq.32m
> apply(matrix(spect.waves$density[ -1], 32), 2, mean) -> dens.32m
1e−01
1e−02
1e−03
Density
1e+00
Sample (8192)
Sample (256)
Population
0.0
0.5
1.0
1.5
2.0
2.5
3.0
Frequency
図 -22 examplewaves.txt のスペクトル(対数表示)
34
2.5
1.5
1.0
0.0
0.5
Density
2.0
o Sample (Smooth)
Sample (Raw)
Population
0.0
0.5
1.0
1.5
2.0
2.5
3.0
Frequency
図 -23 examplewaves.txt のスペクトル(平滑化による)
>
>
>
>
+
spect2(waves, 0.03125, xlim=c(0, 3), ylim=c(0, 2.5), col="gray70")
lines(freq.32m, dens.32m, type="b", col="red")
lines(freq, wallops(5, freq))
legend(2, 2.5, c("Sample (Smooth)", "Sample (Raw)", "Population"),
lty=1, pch=c("o", NA, NA), col=c("red", "gray70", "black"), bty="n")
15) 平均周波数は,スペクトル・モーメントの比により計算される.なお,スペクトルの
ト m k は以下に定義する量である.
k 次モーメン
m k = ∫ f k S( f ) df
(103)
0次モーメント m 0 は総エネルギーを意味し,それは,スペクトルの全面積を計算すればよい.つまり,
(周波数の刻み幅)*(エネルギー密度)の総和を計算する.面積に関しては,平滑化前と後で変わらない
(平滑化操作を考えれば,当然ですネ!)
.
> (1/8192/0.03125 -> df)
[1] 0.00390625
> sum(spect.waves$density * df)
[1] 0.9305057
> (sum(dens.32m * df * 32) -> m0)
[1] 0.9305057
この値は,スペクトルを計算しなくても求めることができる.時系列データのみを用いて,
> sum(waves^2)/8192
[1] 0.9305057
となる(ココ,オドロク・トコロです).なお,定数項はスペクトルで除いているが,対象としている時系
列では,無視できる量である(上記の計算結果には,この分の差異はある,ということだ).
> mean(waves)
[1] 1.135754e-09
この種明かしを数式で表現すれば,次のようである.式 (84) を両辺の自乗を求めれば,
y ′ y = β ′ X ′ X β = β ′β
となる.また,係数ベクトル
(104)
β の成分は,式 (57)~(59) に示されるフーリエ係数 a k および b k を用いて,
β′ =
N
2
{ 2a , a , b , a , b , a ,
0
1
1
2
2
3
... , a N
2
}
(105)
35
に相当することから,以下が成立する.この関係式をパーセバルの公式という.

y′ y
1 N 2−1
= a 02 +  ∑ a k2 + b k2 + a 2N 2 
(106)
N
2  j =1

定数項 a 0 がゼロであれば,左辺は,振動の総エネルギー m 0 を表すことがわかる.この観点から,# 30 に
(
)
記すように,エネルギーを,振幅の自乗÷2とし,2で除す方が都合よい.以上により,# 34 のオドロクベ
キ計算が裏付けられる.また,式(7)の連続関数 f (t ) に対し,式 (106) に相当する式は,以下のようになる.
∫
f 2 (t ) dt = a 02 +
1
2
∞
∑ (a
2
k
+ b k2
k =1
)
(107)
2
テキストによっては,右辺の第1項が, a 0 4 となっているものもある.これは,# 15 に述べたように,係
数 a 0 の定義による違いである.式 (106) および (107) の左辺の平方根を ηRMS (RMS: root-mean-square)と
記し,また,スペクトル密度関数 S( f ) を用いれば,パーセバルの公式を次のように表現することもできる.
( ηRMS ) 2 = ∫ S( f ) df
(108)
以上の議論は,時系列の形態の違い(数列/連続関数)やエネルギーの扱いの違い(振幅の自乗和/密度
関数の積分)に,離散量/連続量の混用が見られる.しかし,これらをキッチリ区別して表記する方が,
かえって理解の妨げになると考え,あえて上述の混用をしている.気に入らない人は,ガッチリ区別して
表記することを練習問題として試みよ.
さて,本題に戻ろう.次に求めるべきは,スペクトルの1次モーメント m1 である.
> (sum(dens.32m * freq.32m * df * 32) -> m1)
[1] 0.9167327
> sum(spect.waves$density * spect.waves$frequency * df)
[1] 0.9157697
よって,平均周波数
(
)
f m = m1 m 0 は,次のように得られる.
> m1/m0
[1] 0.9851985
また,ゼロクロス周波数 f z は,次のように導かれている(Cartwright ・ Longuet-Higgins, 1956).
f z =
2次モーメント
m2 m0
(109)
m 2 を算出し,ゼロクロス周波数 f z は以下のように得られる.
> (sum(dens.32m * freq.32m^2 * df * 32) -> m2)
[1] 1.074043
> sum(spect.waves$density * spect.waves$frequency^2 * df)
[1] 1.071069
> sqrt(m2/m0)
[1] 1.074363
母スペクトルからスペクトル・モーメントを求めると,以下のようになる(ただし,ピアソン・モスコビッ
ツ型スペクトルのモーメントは,ガンマ関数により求めるのが一般的である)
.
> integrate(wallops, 0, Inf, m=5)
1 with absolute error < 3.4e-05
> integrate(function(f) f * wallops(5, f), 0, Inf)
1 with absolute error < 1.8e-05
> integrate(function(f) f^2 * wallops(5, f), 0, Inf)
1.180341 with absolute error < 5.6e-06
したがって,母スペクトルの平均周波数は 1 ,ゼロクロス周波数は 1.09 となる.
> sqrt(.Last.value$value)
[1] 1.086435
36
1e−03
1e−05
spectrum
1e−01
Series: ts(waves[1:256], frequency = 1/0.03125)
Raw Periodogram
0
5
10
15
frequency
bandwidth = 0.0361
図 -25 組込み関数 spectrum によるスペクトル表示(その1)
◇ 実は, R にはスペクトルを算出する便利な関数( spectrum )がある.
> spectrum(ts(waves[1:256], frequency=1/0.03125),
+
detrend=FALSE, taper=0) -> spec256
いきなり,グラフまで作成される! # 32 で作成した spect2 に上書きして確認する(図 -26 参照)
.
> spect2(waves[1:256], 0.03125, col="blue", xlim=c(0, 3))
> points(spec256$freq, spec256$spec*2)
> legend(2.5, 4, c("spect2", "spectrum"),
+
lty=c(1, NA), pch=c(NA, 1), col=c("blue", "black"))
なお,組込み関数としての spectrum (実体は spec.pgram であり,spectrum は,そのエイリアスで
ある)は,さまざまなオプションが指定できる(既にデフォルトで指定されているものもある).組込み関
数 spectrum は,便利すぎて,スペクトル初心者には,かえって困惑するかもしれない, ..
.
> args(spec.pgram)
function (x, spans = NULL, kernel = NULL, taper = 0.1, pad = 0,
fast = TRUE, demean = FALSE, detrend = TRUE, plot = TRUE,
na.action = na.fail, ...)
NULL
4
上述の計算では,spect2 と同じ処理をさせるために,taper や detrend を無効化している.これらの
オプションの意味については,別の機会に紹介しよう(あるいは,参考文献に挙げたテキストで勉強され
たい).
2
1
0
Density
3
spect2
spectrum
0.0
0.5
1.0
1.5
2.0
2.5
3.0
Frequency
図 -26 組込み関数 spectrum によるスペクトル表示(その2)
37
◇ FFT に関する話題は尽きない,... このプリントの最後のシメとして,与えられた時系列の i) 微分と ii) 解析接続を考えよう.
i) 数列で与えられているので,ここでいう微分とは,もちろん,階差数列のことである.
> plot(0.03125 * (1:399 + 0.5), diff(waves[1:400]/2/pi)/0.03125,
+
type="l", xlab="t")
> lines(0.03125 * 1:400, waves[1:400], lty=3)
図 -23 にて,元の時系列(破線)と,その時系列を微分して 2π で除したもの(実線)を示す.
d  cos( 2π t ) 

 = − sin( 2π t ) = cos( 2π t +
dt  2π 
π
2
)
(110)
であるため,実線は破線に比して,位相に関して 1/4 周期早い波形に類似している(角周波数の分だけ振
幅が変わる).実線の波形のエネルギーを RMS により算出すると,
> sum((diff(waves/2/pi)/0.03125)^2)/8191
[1] 1.056453
となる.これは,上で算出した2次モーメントの近似値である.与えられた時系列は,連続関数ではない
ので,キッカリと一致するものではない.たとえるなら,# 26 での等差数列と直線の違いによる同種の差
異が現れている.もちろん,連続関数であれば,その微分波形の RMS は,2次モーメントに一致する.つ
まり,式 (7) より微分波形
∞
(
f ′(t ) = ∑ σ k a k cos σ k t + b k sin σ k t
k =1
)
(111)
について,式 (106) に相当する式は,以下のとおりとなる.
∫ { f ′(t )} dt =
2
1
2
∞
∑
k =1
(
)
σ k2 a k2 + b k2 = ( 2π )
∞
2
∫
f 2 S( f ) df
(112)
0
右辺は,2次のスペクトル・モーメント m 2 である.これをさらに応用すれば,FFT により,数列の整数
階微分だけでなく,小数階微分も定義できる.また,発想を逆転させて,時系列の積分を行い,積分波形
の RMS を考えることにより,負の次数のスペクトル・モーメントを定義することもできる.WAM などの
波浪推算の計算出力に,波浪の代表周期として,エネルギー周期 TE = m −1 m 0 を用いている(The
WAMDI group, 1988; Tucker ・ Pitt, 2001).これは,負のスペクトル・モーメントの使用例の1つであり, 0.5
階の積分波形の RMS が含まれている点で興味深い.
(
)
ii) 解析接続とは,例えば,実軸上で定義された関数を複素関数として拡張することである.逆に,虚部
関数だけを与えて,その実部関数を見い出すことも解析接続である.次式に示すヒルベルト変換
ξ (τ ) = p.v.
∞
∫
−∞
η(τ ) dτ
t −τ π
(113)
を実部関数 η に適用して,虚部関数 ξ が得られる.このように,実数値の時系列をもとに複素化した時
系列を解析信号という.最も単純な解析接続の例の1つとして,オイラーの公式
e ix
= cos x + i sin x
(114)
を見てみよう.これは,実数関数である余弦関数を複素関数として拡張すれば,指数関数であることを示
している.言い換えれば,余弦関数をヒルベルト変換すれば,正弦関数が得られることになる.また,
− i e i x = sin x − i cos x
(115)
であるので,正弦関数をヒルベルト変換すれば,(余弦関数)*(−1)が得られる.式 (113) に対し,
η(t ) = p.v.
∞
∫
−∞
ξ (τ ) dτ
τ −t π
(116)
38
は,逆ヒルベルト変換である.式(116)をヒルベルト変換とよぶ分野もある(Erdélyi et al., 1954)ので,注
意を要する(その場合は,虚部関数 ξ をヒルベルト変換して,実部関数 η を得ることになる).なお,海
岸工学では,一般に,式 (113) の定義を用いている(例えば,Longuet-Higgins, 1983; Huang et al. 1998).式
(113) と (116) の定義の違いは,由来となるコ−シーの積分公式
f ( a) =
1
2π i
η( z )
dz
z−a
∫
(117)
に対して,係数 2π i の虚数を分母に残すか,分子に移すか,という解釈による.ヒルベルト変換は,信
号処理だけに応用されるものではなく,スタンプ問題(あるいは,Riemann-Hilbert 問題)と呼ばれる応用
力学分野にも多用される(例えば,Mei, 1995).
ところで(やや唐突ではあるが),
sin x
dx = 1
x
x →0
lim
(118)
であり,例えば,有名な(微分積分学でも,複素解析学でも有名な)定積分の公式(笠原, 1974; 永谷, 1986)
∞
∫
0
sin x
π
dx =
x
2
(119)
の点からも,正弦関数のヒルベルト変換を考えるにあたり,式 (113) の積分は通常の意味で困らない.しか
し,余弦関数のヒルベルト変換を考える場合には,
lim
x →0
cos x
1
= =∞
x
0
(120)
であり,通常の積分の定義では,その値が発散する.そのため,積分区間から1点を取り除いて,
∞
p.v.
∫
−∞

= lim 
ε →0 
t− ε
∫
+
−∞

∫
t +ε 
∞
(121)
とする.すなわち,式 (113) における積分は主値積分である.主値( principal value )というコトバが聞き
慣れないかもしれないが,主値という考え方は,これまでにも使っている(はずである).その状況とは,
多価関数を扱う時に生じる.三角関数は振動関数であり,その逆関数は多価関数であるので,値域を限定
する必要がある(一松 , 1998).例えば,
y = arccos x ( = cos − 1 x )
(122)
という関数に対して,定義域 ( − 1, 1 ) の値域を
π 2)
−2
−1
0
1
2
3
(123)
−3
diff(waves[1:400]/2/pi)/0.03125
( − π 2 ,
0
2
4
6
8
10
12
t
図 -23 時系列とその微分
39
としてもよいし,
{ (2n − 1) π
2 , (2 n + 1) π 2 }
(124)
としてもよい( n は任意の整数).値域がイロイロあるとヤッカイであるので,式 (123) として値域を1つ
に限定したい.その場合,式 (122)の値域に対し,式(123)が主値の範囲であるという断わり書きが必要であ
る.その時,例えば,“ x = 1 / 2 に対し,式 (122) の主値は y = π / 3 である” という言い回しを使う.
任意の時系列は,フーリエ変換により,さまざまな周波数の余弦と正弦の振動に分解される.したがっ
て,任意の時系列のヒルベルト変換は,FFT を利用すれば,容易に実装できる.例えば,与えられた時系
列 tser が,得られる複素時系列の実部となるように複素化するには,以下のようにすればよい.
> sin(2*pi*0:7/8) + .3 * cos(2*pi*0:7/8 * 4) -> tser
> zapsmall(fft(tser) -> fft.tser)
[1] 0.0+0i 0.0-4i 0.0+0i 0.0+0i 2.4+0i 0.0+0i 0.0+0i 0.0+4i
> fft.tser[2:4] <- 2 * fft.tser[2:4]
> fft.tser[6:8] <- 0
> zapsmall(fft.tser)
[1] 0.0+0i 0.0-8i 0.0+0i 0.0+0i 2.4+0i 0.0+0i 0.0+0i 0.0+0i
> zapsmall(fft(fft.tser, inverse=T)/8)
[1] 0.3000000-1.0000000i 0.4071068-0.7071068i 1.3000000+0.0000000i
[4] 0.4071068+0.7071068i 0.3000000+1.0000000i -1.0071068+0.7071068i
[7] -0.7000000+0.0000000i -1.0071068-0.7071068i
> zapsmall(- 1i * exp(2i*pi*0:7/8) + .3 * exp(2i*pi*0:7/8 * 4))
[1] 0.3000000-1.0000000i 0.4071068-0.7071068i 1.3000000+0.0000000i
[4] 0.4071068+0.7071068i 0.3000000+1.0000000i -1.0071068+0.7071068i
[7] -0.7000000+0.0000000i -1.0071068-0.7071068i
したがって,実数値の時系列(長さが偶数)に対し,複素値の時系列を算出するコードは,
> complex.series <- function(time.series) {
+
len <- length(time.series)
+
if (len %% 2) stop("length is odd")
+
fft.res <- fft(time.series)
+
fft.res[ 2:( len/2)] <- 2 * fft.res[2:(len/2)]
+
fft.res[(2 + (len/2)):len] <- 0
+ fft(fft.res, inverse=TRUE)/len}
となる.以下は,その確認である.
1
0
−1
−2
Im(cmplwaves)
2
> complex.series(tser)
[1] 0.3000000-1.000000e+00i 0.4071068-7.071068e-01i 1.3000000+1.665335e-16i
[4] 0.4071068+7.071068e-01i 0.3000000+1.000000e+00i -1.0071068+7.071068e-01i
[7] -0.7000000+5.551115e-17i -1.0071068-7.071068e-01i
0
2
4
6
8
10
12
t
図 -24 解析信号
40
10 12
8
6
4
2
0
Im(complex.series(log(1:2000/200)))
0
500
1000
1500
2000
Index
図 -25 対数関数のヒルベルト変換
> complex.series(tser[-1])
Error in complex.series(tser[-1]) : length is odd
さて,設問14)の時系列に適用して,図示したものを図 -24 に示す.
>
>
>
>
complex.series(waves[1:400]) -> cmplwaves
plot( 0.03125 * 1:400, Im(cmplwaves), col="blue", type="l", xlab="t")
(125)
lines(0.03125 * 1:400, Re(cmplwaves), col="red")
lines(0.03125 * 1:400, waves[1:400], lty=3)
図 -23 に示した微分波形と類似しており,与えられた時系列(黒点線および赤線)を実部とする解析信号
の虚部(青線)は,実部の位相に対し 1/4 周期遅れたような波形となっている.このことは,次式からも
わかる.
∞
p.v.
∫
−∞
a cos σ k τ + b sin σ k τ dτ
= a sin σ k t − b cos σ k t
t −τ
π
= a cos ( σ k t −
π
2
) + b sin ( σ k t − π2 )
実軸上の対数関数は,以下のように複素関数の対数関数に解析接続される.
log( x + 0 i ) = log x + 0 i
(126)
対数の場合は,実軸にオモテとウラがあることに注意しなければならない.すなわち,上式は実軸のオモ
テ面を対象にしているが,そのウラ面を対象にすれば,
log( x − 0 i ) = log x + 2π i
(127)
となる.したがって,ここでも主値という考えが必要である.さて,式 (113) を数値的に確認しよう.
> plot(Im(complex.series(log(1:2000/200))), type="l")
> abline(h=0, lty=2)
定数ゼロが虚部であるが,図 -26 を見るように,両端で大きなズレが生じている.この原因は,
b
ξ (τ ) ≈ p.v. ∫
a
η(τ ) dτ
t −τ π
(128)
として数値的に式(113)は実行されるため,時系列の中央部では,
 a ∞  η(τ ) dτ
 ∫ + ∫  t −τ π ≈ 0
 −∞ b 
(129)
が近似的にほぼ成立するが,端部では上式が成立しないことによる.さらなる検討は,ここでの議論の主
旨からどんどんと外れていくので,これ以上の議論は省略するが,これを機に,少し変わったモノへの好
奇心が芽生えればさいわいである.
参考文献:
一松 信 (1998): 初等関数概説 - いろいろな関数 -,森北出版,187p.
海上保安庁 (1992): 日本沿岸 潮汐調和定数表,書誌第742号,267p.
笠原晧司 (1974): 微分積分学,サイエンス社,330p.
41
高木貞治 (1961): 解析概論,改訂第三版,岩波書店,477p.
永谷 彬 (1986): 複素解析とその応用,サイエンス社,187p.
Cartwright, D. E. and M. S. Longuet-Higgins (1956): The statistical distribution of the maxima of a rundom function,
Proc. Roy. Soc,Lond., ser. A, vol. 237, pp.212-232.
Cooly, J. W. and J. W. Tukey (1965): An algorithm for the machine calculation of complex Fourier series, Math.
Comp., vol. 19, No.90, pp.297-300.
Duncan, D. E. (1998): Calender - Humanity’s Epic Struggle to Determine a True and Accurate Year, William Morris
Agency, Inc. (邦訳:松浦俊輔,暦をつくった人々 - 人類は正確な1年をどう決めてきたか,河出書房
新社,1998, 343p.)
Erdélyi, A., W. Magnus, F. Oberhettinger, F. G. Tricomi (1954): Tables of Integral Transforms, Vol. II, Bateman Manuscript Project, California Institute of Technology, McGraw-Hill, 451p.
Foreman, M. G. G. (1977): Manual for Tidal Heights Analysis and Prediction, Pacific Marine ScienceReport 77-10,
Institute of Ocean Sciences, Patricia Bay, Sidney, B. C., 58p.
Huang, N. E., Z. Shen, S. R. Long, M. C. Wu, H. H. Shih, Q. Zheng, N.-C. Yen, C. C. Tung and H. H. Liu (1998):
The empirical mode decomposition and the Hilbert spectrum for nonlinear and non-stationary time series analysis, Proc.
Roy. Soc. Lond., ser. A, vol. 454, pp.903-995.
Longuet-Higgins, M. S. (1984): Statistical properties of wave group in a random sea state, Phil. Trans. Roy. Soc. Lond.,
ser. A, Vol. 312, pp.219-250.
Mei, C. C. (1995): Mathematical Analysis in Engineering - How to Use the Basic Tools, Cambridge Univ. Press, 461p.
The WAMDI group (1988): The WAM model - A third generation ocean wave prediction model, Jour. Phys. Oceanogr.,
vol. 18, pp.1775-1810.
Tucker, M. J. and E. G. Pitt (2001): Waves in Ocean Engineering, Elsevier, 521p.
以下のものは,本文中では引用していないが,参考にすべきと思うのでとりあげた.ただし,本論にも述
べているように,統計的側面は今回は見送り,解析的側面だけに注視しているため,以下の文献リストに
も統計的側面を論じたものは省略している.
◎ 周波数スペクトルの基本に関して,日本語で書かれたテキストを以下に紹介する.
日野幹雄 (1977): スペクトル解析,朝倉書店,300p.
大崎順彦 (1994): 新・地震動のスペクトル解析,鹿島出版会,299p.
◎ 次のものは,フーリエ解析のテキストを装いながら,多岐にわたる話題を含み,また他分野への興味を
わかせ,非常に読みごたえがある.
Korner, T. W. (1988): Fourier Analysis, Cambridge Univ. Press
Korner, T. W. (1993): Exercise for Fourier Analysis, Cambridge Univ. Press
(邦訳:高橋陽一郎,フーリエ解析大全,(上,下),(演習編,上,下),朝倉書店,1996, 2003)
◎ 次のものは,上のテキストとは逆に,画像処理技術に関する応用数学のテキストを装いながら,手をか
え品をかえて,フーリエ解析を展開している.「ディスカション」が楽しい.
金谷健一 (2003): これなら分かる応用数学教室,共立出版,270p.
◎ Hilbert 変換は,突然に用いられることが多く,系統的にまとまった記述のある文献は少ない.そのた
めか,これまでに数多くの直接/間接的な問い合わせがあった.その応対の際に,初心者に親しみ易く,
かつ,すぐに応用できるような適切な解説書がないのを言訳にしつつも,私の説明に私自身がもどかしさ
を感じていた.その経験を基に,今回の FFT の解説のシメククリとして,Hilbert 変換の解説を試みた.
さらに理解を深めたい人のために,以下の文献を挙げる.
Cohen, L. (1995): Time-frequency Analysis, Prentice Hall.
(邦訳:吉川 昭・佐藤俊輔,時間 - 周波数解析,朝倉書店,1998, 300p.)
Hahn, S. L. (1996): Hilbert Transform in Signal Processing, Artech House, 442p.
Vakman, D. E. (1976): Do we know what are the instantaneous frequency and instantaneous amplitude of a signal,
Trans. in Radio Eng. and Electron. Phy., vol. 21, pp.95-100.
42