そこで、調和積スペクトルアルゴリズムを使用してピッチ計算アルゴリズムを修正しました。 Harmonic Product Spectrumのこの説明で、データセットにハニングウィンドウを実装する必要があると述べている理由について知りたいと思いました。他のウィンドウ関数をデータセットに実装する(そしてそれをFFTする)ことの効果は何でしょうか?周波数検出に実際に最適なウィンドウ関数はどれですか?コードで使用した関連メソッドは次のとおりです。

/** * Calculates the Frequency based off of the byte array, * @param bytes The audioData you want to analyze * @return The calculated frequency in Hertz. */ private int getFrequency(byte[] bytes){ double[] audioData = this.bytesToDoubleArray(bytes); audioData = applyHanningWindow(audioData); Complex[] complex = new Complex[audioData.length]; for(int i = 0; i<complex.length; i++){ complex[i] = new Complex(audioData[i], 0); } Complex[] fftTransformed = FFT.fft(complex); //return calculateFrequency(fftTransformed); System.out.println("Max size:" + (fftTransformed.length*getFFTBinSize(fftTransformed.length)/4)); return calculateFundamentalFrequency(fftTransformed,4); } private double[] applyHanningWindow(double[] data){ return applyHanningWindow(data, 0, data.length); } private double[] applyHanningWindow(double[] signal_in, int pos, int size) { for (int i = pos; i < pos + size; i++) { int j = i - pos; // j = index into Hann window function signal_in[i] = (double)(signal_in[i] * 0.5 * (1.0 - Math.cos(2.0 * Math.PI * j / size))); } return signal_in; } /** * Harmonic Product Spectrum * @param fftData * @param n * @return */ private int calculateFundamentalFrequency(Complex[] fftData, int n){ Complex[][] data = new Complex[n][fftData.length/n]; for(int i = 0; i<n; i++){ for(int j = 0; j<data[0].length; j++){ data[i][j] = fftData[j*(i+1)]; } } Complex[] result = new Complex[fftData.length/n];//Combines the arrays for(int i = 0; i<result.length; i++){ Complex tmp = new Complex(1,0); for(int j = 0; j<n; j++){ tmp = tmp.times(data[j][i]); } result[i] = tmp; } //Calculates Maximum Magnitude of the array double max = Double.MIN_VALUE; int index = -1; for(int i = 0; i<result.length; i++){ Complex c = result[i]; double tmp = c.getMagnitude(); if(tmp>max){ max = tmp;; index = i; } } return index*getFFTBinSize(fftData.length); } 

回答

FFTは、限られたデータチャンクに対してのみ実行できます。基本的な計算は、時間領域の信号が周期的である、つまりデータのチャンクが時間内に繰り返されるという仮定に基づいています。これは通常、チャンクのエッジで大きな不連続性をもたらします。簡単な例を見てみましょう。FFTサイズ= 1000ポイント、サンプルレート= 1000 Hz、周波数分解能=1Hz。10Hzの正弦波がある場合、正確に10周期がFFTウィンドウに収まるため、不連続性はありません。エッジの値(および導関数)は同じです。このシガンルのFFTは、ビン#10の単一の値を除いてゼロになります。これは、11Hzの正弦波でも同様に機能します。ただし、10.3 HZの正弦波の場合、多くの不連続性が発生し、FFTはすべてのビンにエネルギーを持ち、最大で約10または11になり、その後、横に転がる「スカート」が発生します。したがって、周波数の小さな変化は、FFT画像の大きな変化をもたらします。

ウィンドウ処理はこれを回避するために使用されます。Windowsはエッジのデータがゼロであることを確認するため、不連続性はありません。ただし、時間領域での乗算は周波数領域での畳み込みであり、その結果、スペクトル線とサイドローブが広がります。ウィンドウの選択により、メインローブの幅とサイドローブの間隔および高さの間のトレードオフが制御されます。アプリケーション固有の要件によって、使用するウィンドウが決まり、数十の選択肢があります。ハニングはその1つにすぎません。それは基本的に「より良いアイデアがない場合に選択するウィンドウ」です。個人的には、カイザーウィンドウの方が好きです。カイザーウィンドウには、ウィンドウの動作を広範囲にわたって制御できる連続パラメーターがあるからです。

一般に、FFTはピッチ検出に最適な方法ではありません。ほとんどのオーディオ信号では、スペクトルの最大値は基本波ではありません(通常、高調波のエネルギーは高くなります)。適切な解像度を得るには、長いデータが必要ですが、アルゴリズムが非常に遅くなり、変更への応答が遅くなります。はるかに優れたオプションは、位相ルックループ、遅延ルックループ、自己相関、最大/最小トラッカー、ゼロクロッシングトラッカーなどです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です