FFTの処理をする時、データ数が2のべき乗に制限される。 一方、WaveInで入力信号をキャプチャする場合はキャプチャ時間をms単位で指定する。 キャプチャされた信号は、必ずしも2のべき乗にならないので、調整が必要になる。
今まではBuffeMilliseconds = 200ms サンプルレート44100Hzでキャプチャしていたので、データ数は44100 * 0.2 = 8820。 これに近い2のべき乗の数として、FFTでのデータ数を8192としていた。
8820 – 8192 = 628データは捨てていた。 周期性のある入力信号にこの処理を行うと、連続性がなくなるので正確なFFTが行えないと思われる。
というわけで、キャプチャしたデータ数がなるべく8192に近づくように変更してみた。 また、いつもお世話になっている三上直樹著「デジタル信号処理プログラミング」の中では、”0埋め”という、足りないデータを0で埋めるという手法が紹介されている。
そこで、8192になるべく近く8192より小さいデータをキャプチャするサンプルレートとキャプチャ時間を設定した。
算出したサンプルレートは45511Hz、キャプチャ時間は、180ms。 サンプルレートが44100とか48000とかでなく規格外になるけど、特に問題ないと思う。
この条件でサンプリングするとデータ数は8191となり、1データ足りないけど0埋めする。
修正した場所だけ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Form1_Load waveIn.BufferMilliseconds = 180; //180ms waveIn.WaveFormat = new WaveFormat(45511, 2); //data siza 45511 * 180ms = 8191サンプル xtick = pb_width / (float)(Math.Log10(22756) - Math.Log10(50)); //左端 50HZ、右端 22756Hz //WaveIn_DataAvailable short[] data = new short[8192]; float[] snddata = new float[8192]; for (int index = 0; index < e.BytesRecorded; index += 4) { data[index / 4] = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]); snddata[index / 4] = (float)data[index / 4]; } |
1KHzの正弦波をサンプルレート45511Hz、サンプル時間180msでキャプチャし、1データ”0埋め”した時。
明らかに、裾の形状が改善されている。
三上さんの本によると、分析区間を部分的に重複させたり、FFTの出力を正規化したりする手法が紹介されているので、もう少し改善する余地がありそう。