mikeo_410


音の高さと再生速度

1.FFTと逆変換

R言語を使って試して見ます。確かに完全に戻ります。

> s <- sin( seq(0,by=2*pi/16,length.out=16) )
> f <- fft( s )/16
> r <- fft( f, inverse=TRUE )
> s
 [1]  0.000000e+00  3.826834e-01  7.071068e-01  9.238795e-01  1.000000e+00
 [6]  9.238795e-01  7.071068e-01  3.826834e-01  1.224606e-16 -3.826834e-01
[11] -7.071068e-01 -9.238795e-01 -1.000000e+00 -9.238795e-01 -7.071068e-01
[16] -3.826834e-01
> Re(r)
 [1]  0.000000e+00  3.826834e-01  7.071068e-01  9.238795e-01  1.000000e+00
 [6]  9.238795e-01  7.071068e-01  3.826834e-01  1.224606e-16 -3.826834e-01
[11] -7.071068e-01 -9.238795e-01 -1.000000e+00 -9.238795e-01 -7.071068e-01
[16] -3.826834e-01

16分割した1周期のサイン波のFFTの結果を逆変換すると元のサイン波に戻ります。この例では、FFTの結果をサンプル数16で割っています。
この例の、FFTの結果のfは、指数表示され(ほとんどゼロの部分が-17乗と言った表記になって)見にくいので、16個のゼロを用意して、[2][]16]にだけ、値を設定して、FFTの逆変換をして見ます。表記法の差はありますが、入力のサイン波と同じ値になります。

> c <- seq(0,by=0,length.out=16)
> c[2] <- complex(re=0,im=-0.5)
> c[16] <- complex(re=0,im=0.5)
> c
 [1] 0+0.0i 0-0.5i 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.0i
[11] 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.0i 0+0.5i
> r2 <- fft( c, inverse=TRUE )
> Re(r2)
 [1]  0.0000000  0.3826834  0.7071068  0.9238795  1.0000000  0.9238795
 [7]  0.7071068  0.3826834  0.0000000 -0.3826834 -0.7071068 -0.9238795
[13] -1.0000000 -0.9238795 -0.7071068 -0.3826834

 FFTを行うサンプルの範囲で、1周期の信号成分の大きさは、先頭から2つ目(0,1なら1)に反映します。その共役数が最後に入ります。
周期が1と言ってもゼロから始まるとは限らない(位相が異なることもある)訳ですが、どんな風に表現されるのでしょうか。

 

位相を2π/16ずつずらしながら、16サンプルで1周期のサイン波を作って、FFTを行って、[2]の実部、虚部をプロットして見ました。(「R言語」「サンプル」にスクリプトを保存しました。)

 

 

 

 

 

 

 

 

 

同じもの( サンプル中で、1周期のFFTの結果のうち、1周期の分に相当する[2]の部分)を、実部、虚部でプロットして見ました。

 

 

 

 

 

 

 

 

 

 

 

2.FFTとその逆変換で再生速度を変えてみる

やって見たのですが、あまり上手くいきません。リアルタイムに、マイク入力をゆっくり再生するプログラムを作ったのですが、ぶつぶつとノイズが入ります。上手く行かない訳を考えて見ます。

2.1.意図したこと

 44100Hzでサンプリングします。これを、22050Hzで再生することで「ゆっくり再生」を実現します。これだけだと、周波数も低くなってしまうので、FFT、逆変換で周波数を2倍にします。
また、「ゆっくり再生」すれば、未再生部分が蓄積するので、無音検出を行って、無音部分を飛ばします。

これを作っては見たのですが、ぶつぶつとノイズが入ります。プログラムの間違いを除去するために、WAVファイルを変換する単純なプログラムを使って検討することにしました。

2.2.検証用WAVファイル

16000Hz、モノラルで録音された文章読み上げのサンプルです。これを、8000Hzでサンプリングしたものとして出力します。出力サイズは変わりません。本来、約8000HzまでFFTで検出するわけですが、4000Hzまでになります。

2.3.周波数を2倍にする

C#でのプログラム用に作った、私のFFTは、サンプル数の半分の値しか返しません。したがって、この半分で考えます。
FFTを512バイト単位に行うものとして説明します。サンプリングレートが16000Hzなので、32msに相当します。FFTの結果は、256になります。約8000Hzが最大の周波数になるので、分解能は、8000/256=31.25Hzです。

これを逆変換して、入力と同じものになるのを確認しました。

次に、FFTの結果の256のうち、後半の128を捨てます。4000Hz以上の成分がなくなることになります。
具体的には、ゼロから数えて、1-127を、256のうちの偶数番目に移します。奇数には、ゼロをセットします。これで、周波数が2倍になったことになります。
これを、逆変換します。逆変換の結果は、入力と同じ512個になります。

 

 

 

 

 

 

2.4.上手く行かない理由

 

 2.4.1.期待したこと

FFT ->  結果をシフト -> 逆変換
と、することで、同じサンプル数のPCMデータが得られます。これを、サンプリングレートを半分にして再生すれば、倍の時間で再生されます。周波数を2倍にしているので、音質はあまり変わらず、「ゆっくり再生」できると考えました。

 

 

 

 

 

 

---------------------------------------------------------

 

 2.4.2.実際は

最初は、FFTを計算するサンプル数を、512程度にしていて、気が付きませんでした。4096にしたら、同じ音節を繰り返していることが分かりました。
音素の長さより、短い変換をすると、意図どおり、ゆっくり再生され、ノイズがあるように感じます。
音素より長いと、同じ音素を繰り返すようになります。

FFTは、サイン波、コサイン波を合成して、元の振幅波形を近似していると言う大元を考えれば当然で、近似に使用した、サイン波、コサイン波の周期を半分にしたのですから、合成波形も半分になってしまいます。残りの半分は、同じ波形の合成が続くのですから、同じものが繰り返されるわけです。

「ぶつぶつ」は、つなぎ目で不整合かとも思いましたが、FFT区間内での特性が一様でないことに原因があるようです。

 下の「入力データ(4096)」は、FFTの入力となったPCM(振幅)データです。
「周波数2倍処理後の逆変換結果(4096)」は、

FFT ->  結果をシフト -> 逆変換
を、行って得た、PCMデータです。振幅の大きな箇所に着目して見ると、「下図は、中央(2096)付近で分けて、前半と後半でほぼ同じ形をしている」、「下図の前半(あるいは後半)と、上の図は良く似た形をしている」ことが分かります。

  

 

 「周波数2倍処理後の逆変換結果(4096)」のデータの先頭と中央の10個を見て見ます。

> cc<-scan("tmp.txt")
> cc[1:10]
 [1]  -2.3 -18.2 -19.4 -11.7 -23.7 -15.3  -6.5  -5.1   6.0  20.9
> cc[2049:2058]
 [1]  -3.8 -19.6 -20.9 -13.1 -25.1 -16.7  -7.9  -6.5   4.6  19.5
>

また、差をプロットすると左図になりました。

> diff <- cc[1:2048]-cc[2049:4096]
> plot(diff)
> title("逆変換した結果の前半と後半の差")

 

 

 2.5.どうすれば良いか

音素より短い時間でFFTを行い、そのデータを2回出力する方法が考えられます。
あるいは、FFTの結果の先頭1/4だけを使うことにして、FFTを計算するサンプル数の1/4ずつ、シフトしながら進める方法も考えられます。

しかし、これを良く考えて見ると、FFTを使う必要がないようです。
ダウン・サンプリングレートと重複出力と同じだと言うことです。FFTの入力となった、元のPCMデータの偶数番目(あるいは奇数番目)を取り出し、2回出力すれば、「上手く行かない理由」で行ったのと同じ結果が得られます。 

PCMデータを1つ飛びに取ることは、サンプリングレートを半分にして、サンプリングしたのと同じことです。
サンプル数は、半分になり、元のサンプリングレートのまま、再生すれば周波数は倍になります。

図、「サンプリングレート半分(偶数x2)」は、「上手く行かない理由」の入力に対して、この処理をした結果のPCMデータです。

 

3.わかったこと

  1.  PCMデータと、そのFFTの結果は同じ情報を含んでいて、相互に完全に変換できる。これは、サンプリング時間が長くても成り立つ。
  2. ただし、このことには余り使い道がなさそうで、主に音素など短い時間に対して使われる。FFTを計算するサンプル数の範囲では、入力に変化がないものと見なして使うものようだ。
  3. 入力に変化がないものと見なせる場合と、波形保存再生が目的の場合は、耳で聞いたときどうなるかが分かる。これ以外は、FFTの結果への変更が、どんな影響を与えるか良く分からない。「音素より長い」と言っても、音素の時間に決まりがあるわけではない。
  4. 窓関数について。必要性がわからなかった。波形保存再生が目的なら窓を掛けると40%ぐらい情報を失うので不要。ある短い区間を代表する周波数成分を抽出すると考える場合は必要。と言うことだと思う。
  5. サンプリングレート16000Hzの場合、128サンプル以下でFFT、逆変換すると音が割れる。64分割(8ms,分解能125Hz)では、荒すぎるようだ。

 


川崎市 不動産 足立区 不動産 松戸市 不動産 東京都 任意売却 習志野市 新築