【数理考古学】音楽と離散フーリエ変換(DFT)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/df76a458-f9c4-7209-b001-bbf92b3635db.png)
[【数理考古学】ヴェーバー‐フェヒナーの法則](https://qiita.com/ochimusha01/items/4eaf1972ff487b9bc713)

この投稿以降「**音の話**」が気になって…

#Rで離散フーリエ変換を試す。

準備としてとりあえず、以下のお題をそのまま解いて見ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/166eed79-4626-02ae-8569-e1a6161fee95.png)
[Rによる信号処理](https://tamosblog.wordpress.com/2015/01/09/signal_processing_by_r/)

>振幅が1で周波数10[Hz]の正弦波と，振幅が1/4で周波数30[Hz]の余弦波の合成波信号データについて，離散フーリエ変換（FFT）によって得られた振幅スペクトルを取得しなさい．ただし，サンプリング周波数FSは160[Hz]，標本間隔DTは6.25[ms]（1/FS）， 標本の個数Nは16個とする．

統計言語Rによるプログラミング例（初期値設定）

```R
FS <- 160    # サンプリング周波数 FS=160[Hz]
DT <- 1/FS  # 標本間隔 DT=1/160=0.00625[s]
N <- 16        # データ数 N=16
i <- 0:(N-1)   # 添字(index)の範囲 i
```

* DT*16=0.00625*16=0.1[s]を基本波の周期とする。
* 従ってその逆数である10[Hz]が基本波の周波数となる。

スペクトラム表示関数

```R
Spectrum_disp<-function(x,N){
i <- 0:(N-1) 
spec <- fft(x)/N
plot(i, Re(spec), type='h', xaxt='n', yaxt='n', col='blue', lty=3, lwd=2, ylim=c(-0.8,0.8), ylab='', xlab='')
par(new=T) #上書き
plot(i, Im(spec), type='h', xaxt='n', yaxt='n', col='red', lty=1, lwd=2, ylim=c(-0.8,0.8), ylab=expression(paste('Spectrum ', X[k])), xlab='Index k')
axis(1, pos=0, at=0:N, adj=0)
axis(2, at=seq(-1, 1, by=0.25))
legend(0.5, 0.7, legend=c(expression(Re(X[k])), expression(Im(X[k]))), lty=c(3,1), col=c('blue', 'red'), lwd=c(2,2))
}
```
振幅1，10[Hz]の正弦波

```R
siga <- sin(2*pi*10*DT*i)
plot(DT*i, siga, xlab='Time', type='o')  
#sigaのFFT結果
Spectrum_disp(siga,N)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/04e4968c-2f76-d29a-d314-f01ca9b775fd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/93196c4c-91bc-4a2b-4fd8-6f8cbe70c9d2.png)

* k=1の場合が基本周波数10[Hz]
* 奇関数Sinの成分なので虚部にスペクトルが現れる。
* ちょうどk=8を折り返し周波数として半分ずつの数値がk=1とk=15の位置に対照的に現れる。

振幅0.25，30[Hz]の余弦波(sigb)

```R
sigb <- 0.25*cos(2*pi*30*DT*i)
plot(DT*i, sigb, xlab='Time', type='o') 
#sigaのFFT結果
Spectrum_disp(sigb,N)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/51dce3e6-353e-ec25-e321-bbfa204c0d00.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/52cd4f5f-68bc-009e-645f-6db65cc3cbcc.png)

* k=3の場合が周波数30[Hz]
* 偶関数Cosの成分なので実部にスペクトルが現れる。
* ちょうどk=8を折り返し周波数として半分ずつの数値がk=3とk=13の位置に対照的に現れる。

合成波(sig)

```R
sig <- siga + sigb
plot(DT*i, sig, xlab='Time', type='o') 
#sigのFFT結果
Spectrum_disp(sig,N)
```

* スペクトルの内容はまさにsiga+sigbになっている。

スペクトルの3D表示
![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/o/ochimusha01/20190830/20190830053232.gif)

```R
library(rgl)
Samples_z<-i
Real_x<-Re(fft(sig))
Imagin_y<-Im(fft(sig))
plot3d(Real_x,Imagin_y,Samples_z)  
movie3d(spin3d(axis=c(0,0,1),rpm=5),duration=10,fps=25,movie="~/Desktop/test")
#Movieファイル出力ディレクトリーは環境依存
```
ここで一応、用語解説。
[サンプリング周波数](https://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AA%E3%83%B3%E3%82%B0%E5%91%A8%E6%B3%A2%E6%95%B0)
[帯域幅 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%B8%AF%E5%9F%9F%E5%B9%85)

#平均律と純正律
まずは基本中の基本から抑えて行きます。
[和音と波形 | You Look Too Cool](https://stabucky.com/wp/archives/10345)

とりあえず音の高さを1、周期を1とします。長３度和音ドミソは純正律（Just intonation）だときれいな協和音になりますが、この場合の周波数は次のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/5a9f973b-f4a5-73c1-0ec1-e6b8ab03ee0f.png)

* ド 1.0000
* ミ 5/4=1.2500
*ソ 3/2=1.5000

一方、平均律のドミソは次のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/9242af8d-425b-98fe-f765-33773359e18e.png)

* ド 1.0000
* ミ 2^(4/12)=1.2599
* ソ 2^(7/12)=1.4983

若干、ずれが生じます。したがって音にも影響します。 ちなみにこれは明るい感じのするメジャー和音ですが、ドレソ#は暗い感じがします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/be464d17-b432-3411-c7a3-05b7ed8614eb.png)

純正律（Just Intonation）

* ド 1.0000
* レ 9/8=1.2500
* ソ# 10/9=1.111111

平均律（Equal Temperament）

* ド 1.0000
* レ 2^(2/12) =1.122462
* ソ# 2^(8/12) =1.587401

[純正律 - Wikipedia](https://ja.wikipedia.org/wiki/%E7%B4%94%E6%AD%A3%E5%BE%8B)

統計言語Rによる純正律再生

```R
library(tuneR)
#純正律再生関数
Just_Intonation<-function(note){
f1<-function(x){(440*2^(-3/12))*x} #チューンダウン
notes<-f1(note)
for (i in notes) {
beep<- sine(i);
play(beep)
}
}
#ドレミファソラシド、ドシラソファミレド
c0<-c(1,9/8,5/4,4/3,3/2,5/3,15/8,2)
c1<-c(c0,rev(c0))
Just_Intonation(c1)
#ドミソ、ドミソ
c0<-c(1,5/4,3/2)
c1<-c(c0,c0)
Just_Intonation(c1)
#ドレソ#、ドレソ#
c0<-c(1,9/8,10/9+16/15-1)
c1<-c(c0,c0)
Just_Intonation(c1)
#ドミ♭ソ、ドミ♭ソ
c0<-c(1,5/4+16/15-1,3/2)
c1<-c(c0,c0)
Just_Intonation(c1)
```
統計言語Rによる平均律再生

```R
library(tuneR)
#平均律再生関数
Equal_Temperament<-function(note){
f1<-function(x){(440*2^(-3/12))*2^x} #チューンダウン
notes<-f1(note)
for (i in notes) {
beep<- sine(i);
play(beep)
}
}

#ドレミファソラシド、ドシラソファミレド
c0<-c(0,2/12,4/12,5/12,7/12,9/12,11/12,1)
c1<-c(c0,rev(c0))
Equal_Temperament(c1)
#ドミソ、ドミソ
c0<-c(1,4/12,7/12)
c1<-c(c0,c0)
Equal_Temperament(c1)
#ドレソ#、ドレソ#
c0<-c(1,2/12,8/12)
c1<-c(c0,c0)
Equal_Temperament(c1)
#ドミ♭ソ、ドミ♭ソ
c0<-c(1,3/12,7/12)
c1<-c(c0,c0)
Equal_Temperament(c1) 
```
[東京都高等学校軽音楽連盟](http://www.tokyo-keion.com/kouza08.html)

>平均律は周波数を12回、同じ倍率で大きくすると２倍になるような各１回を半音としています。具体的な倍率は２の12乗根で、1.059463倍です。(計算機でこの数字を12回掛けてみてください)つまり、各半音の幅がきっちり同じなわけです。
>
>純正律は、ある調専用(例えばハ長調限定)の調律法で、長３度和音(ドミソド)の周波数が
完全に整数倍になるように合わせます。平均律で合わせた場合はこの周波数が合いません。
>
>ギターで弾くとそれほどの違いは感じられませんし、単音で聞いてこの違いがわかる人もほとんどいないと思われますが、正弦波を発振する装置で両方の和音を聞き比べるとはっきり違いがわかります。チューニングの項で書いた「うなり」が、純正律だと全く発生しないわけです。ただし、ハ長調の純正律に合わせた楽器で別の調の曲を弾くと、平均律以上に狂いが目立ってきますので、いろいろな曲をひとつの楽器で弾く場合は平均律に合わせるのが常識となっています。
>
>なおギターのチューニングは、各フレットが平均律で作られていて、ハーモニックスチューニングをすると弦間が純正律という中途半端な形になります。

それでは離散フーリエ変換によって解析してみましょう。

統計言語Rによるプログラミング例（FFT解析結果表示関数）

```R
Spectrum_disp<-function(x){
N<-length(x)
i <- 0:(N-1) 
spec <- fft(x)/N
plot(i, Re(spec), type='h', xaxt='n', yaxt='n', col='blue', lty=3, lwd=2, ylim=c(-0.8,0.8), main='Spectrum by FFT',ylab='Spectrum', xlab='Samples')
par(new=T) #上書き
plot(i, Im(spec), type='h', xaxt='n', yaxt='n', col='red', lty=1, lwd=2, ylim=c(-0.8,0.8), main='',ylab='', xlab='')
axis(1, pos=0, at=0:N, adj=0)
axis(2, at=seq(-1, 1, by=0.25))
legend(0.5, 0.7, legend=c("Real Number","Imaginary Number"), lty=c(3,1), col=c('blue', 'red'), lwd=c(2,2))
}
```

統計言語Rによるプログラミング例（初期値設定）

```R
N<-12# データ数 N=12
i<-0:(N-1)# 添字(index)の範囲 i
j<-seq(0,2*pi,length=12)# 周期関数のX
```

基本波形「ド(Do)」の解析
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/1c41abbd-a3eb-f643-01de-f3e1b214f894.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/482bea35-0b14-124c-9a9e-406e9397868e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/9d35b815-cdef-5f9c-7c30-d5cb861aa8fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/e8dfde8e-75d1-3e1a-cd87-014a41d156a8.png)

```R
Do<-sin(j)
plot(i, Do, xlab='Time', xlim=c(0,11),ylim=c(-1,1),main="Sampling of Do",type='o')
```
純正律(Just intonation)「ドミソ」の合成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/40d763c0-d7ec-16e3-6031-ae0ddce37f5c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/9acace4b-6e46-8b37-d438-0363a9eb26cd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/e85dee1f-b9b1-85e7-e4fe-32ccac592a2b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/8573fabf-aaf7-8a63-2d5c-b3e4c6ebf462.png)

```R
Do_j<-sin(j)
Mi_j<-sin(j*5/4)
plot(i, Mi_j, xlab='Samples', xlim=c(0,11),ylim=c(-1,1),main="Sampling of Mi(Just intonation)",type='o')
So_j<-sin(j*3/2)
plot(i, So_j, xlab='Samples', xlim=c(0,11),ylim=c(-1,1),main="Sampling of So(Just intonation)",type='o')
DoMiSo_j<-Do_j+Mi_j+So_j
plot(i, DoMiSo_j, xlab='Samples', xlim=c(0,11),ylim=c(-3,3),main="Sampling of DoMiSo(Just intonation)",type='o')
Spectrum_disp(DoMiSo_j)
```
![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/o/ochimusha01/20190830/20190830052617.gif)

```R
#スペクトラムの3D表示
library(rgl)
Samples_z<-i
Real_x<-Re(fft(DoMiSo_j))
Imagin_y<-Im(fft(DoMiSo_j))
plot3d(Real_x,Imagin_y,Samples_z)  
movie3d(spin3d(axis=c(0,0,1),rpm=5),duration=10,fps=25,movie="~/Desktop/test")
#Movieファイル出力ディレクトリーは環境依存
```
平均律(Equal Temperament)「ドミソ」の合成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/c74c7a17-95e1-a1db-d003-cf242ea508c8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/fc32e930-b3ed-7c83-0ba9-b58ca3cf3cff.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/d4e1194b-9121-1ede-fe5a-c059e750f6d8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/31a6fc4e-830d-fb9b-db0b-9ec367fa45b5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/51b6e61c-cac9-7069-c6ca-3bef19e7f22a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597772/0b9cbd0a-3329-a9c6-5b39-6f70fd80c322.png)

```R
Do_e<-sin(j)
Mi_e<-sin(j*2^(4/12))
plot(i, Mi_e, xlab='Samples', xlim=c(0,11),ylim=c(-1,1),main="Sampling of Mi(Equal Temperament)",type='o')
Spectrum_disp(Mi_e)
So_e<-sin(j*2^(7/12))
plot(i, So_e, xlab='Samples', xlim=c(0,11),ylim=c(-1,1),main="Sampling of So(Equal Temperament)",type='o')
Spectrum_disp(So_e)
DoMiSo_e<-Do_e+Mi_e+So_e
plot(i, DoMiSo_e, xlab='Samples', xlim=c(0,11),ylim=c(-3,3),main="Sampling of DoMiSo(Equal Temperament)",type='o')
Spectrum_disp(DoMiSo_e)
```
![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/o/ochimusha01/20190830/20190830052355.gif)

```R
#3D表示
library(rgl)
Samples_z<-i
Real_x<-Re(fft(DoMiSo_e))
Imagin_y<-Im(fft(DoMiSo_e))
plot3d(Real_x,Imagin_y,Samples_z)  
movie3d(spin3d(axis=c(0,0,1),rpm=5),duration=10,fps=25,movie="~/Desktop/test")
#Movieファイル出力ディレクトリーは環境依存
```
とりあえず自分史上、このジャンル最初の投稿を果たしたという事で、以下続報…
[離散フーリエ変換(DFT)の仕組みを完全に理解する](https://qiita.com/TumoiYorozu/items/5855d75a47ef2c7e62c8)
[離散時間フーリエ変換の困るところ](http://www.ic.is.tohoku.ac.jp/~swk/lecture/yaruodsp/dft.html)
これからしばらくはこういう記事に目を通し続ける日々が続きます。