Cepstrumとスペクトル包絡
畳み込み合成
通常、音を合成するには加算します。おそらくステレオからモノラルへの変換は平均値が使われていると思います。
また、スペクトルについても、それぞれのパワーを加算することに不自然はありません。
畳み込み合成がどんな場合に有効なのか、今のところ理解できませんが、wikipedia の「畳み込み」の「畳み込み定理」の説明、「関数 f, g の高速フーリエ変換を掛け算した結果を逆高速フーリエ変換をすることで計算」をそのまま受領します。
Cepstrum
声の振幅波形は、音源(声帯) と調音系(声道)の信号の畳み込み合成したものだと言うことから始まっているのだと思います。もう一つの前提は、音源と調音系では周期性に大きな差があると言うことです。
また、
log m・n = log m + log n
で、m と n の積は、対数を取ると、それぞれの対数の和で表されます。
このことから、観測される振幅波形のFFTの結果の対数は、音源由来と調音系由来に分離できる言うことのようです。
観測される振幅波形は、それぞれのFFTの算出値の積を、FFTの逆変換したものと解釈されます。
観測される振幅波形のFFTを求め、対数を取って、FFTの逆変換を行ったものをCepstrumと言うようです。
これは、対数を取ることによって、復元される振幅波形が、音源由来と調音系由来に分離されていると見るもののようです。
しかし、どこで分離されているのかは定かではなく、単にFFTの結果を周波数で分離することとの差異も良くわかりません。
図は、seewave パケージのceps関数で描いたものです。
値は、FFTを組み合わせ手計算したものと一致します。
- > # seewave パッケージのケプストラム
- > y <- ceps(wavdata,44100)
- > # 普通に計算すると
- > c <- Re(fft(log(Mod(fft(wavdata))),inverse=T)[1:(length(wavdata)/2)])
- > # この2つは等しい
- > range(y[,2]-c)
- [1] 0 0
Y軸の目盛りは付与されていません。
X軸方向には、2つの目盛りが付けられます。
wavdata のサンプル数は、1765で、その半分(882)が描かれています。サンプリングが44100Hzなので0.02秒に相当し、この時間が下の目盛りになっています。
上は、1/(下の目盛り) Hz になっています。
この図の場合、音源の基本周波数は200Hz程度で、2ms以下に調音系の特性が示されていると見ることができるようです。
Cepstrumスペクトル包絡
Cepstrum の値のFFTを計算し、高域をカットして、振幅に戻したものをスペクトル包絡とするようです。
2msのインデックスは、882*0.002/0.02 = 88.2 なので、先頭の88個から振幅を作ってみます。
また、サンプリングレートが44100Hzなので、FFTの結果の全域は22050Hzになりますが4000Hzだけを描画します。
これは、882*4000/22050=160 です。
左図では、スペクトル(単にサンプルをFFTしたもの)は、対数軸になっています。
FFTの際にサンプル数で割るなどの処理をしていない値です。
- # データの長さ
- n <- length(wavdata)
- # ケプストラムを計算
- c <- Re(fft(log(Mod(fft(wavdata))),inverse=T)[1:(n/2)])
- # 2msに相当するサンプル数
- p <- 882 * 0.002/0.02
- # 2ms分だけでFFTを計算
- envelope <- Re(fft(c(c[1:p]/n,rep(0,n-p))))
- # 普通に元のサンプルをFFT
- spectrum <- Mod(fft(wavdata))
- # スペクトルと包絡の描画
- q <- 882*4000/(44100/2) # 4000Hzに相当するインデックス
- x <- seq(0,4000,length.out=q)
- par(mar=c(3,3,3,3),mgp=c(1.5,0.5,0))
- plot(x,spectrum[1:q],type="l",col="blue",log="y",axes=F,xlab="",ylab="")
- axis(4)
- mtext("FFTの算出値(対数)",4,1.5)
- par(new=T)
- plot(x,envelope[1:q],type="l",col="red",xlab="周波数(Hz)",ylab="包絡の算出値")
- title("スペクトルとCepstrumからのスペクトル包絡",cex.main=0.8)
- legend(1800,-1,c("スペクトル","スペクトル包絡"),col=c("blue","red"),lty=c(1,1),bty="n")
|