web-dev-qa-db-ja.com

高速フーリエ変換を使用してオーディオを分析する

Pythonでグラフィカルなスペクトルアナライザーを作成しようとしています。

現在、16ビットデュアルチャンネル44,100 Hzのサンプルレートオーディオストリームの1024バイトを読み取り、2つのチャンネルの振幅を平均しています。だから今、私は256の署名付きショートパンツの配列を持っています。 numpyなどのモジュールを使用して、その配列でfftを実行し、その結果を使用してグラフィカルなスペクトルアナライザーを作成します。

私は高速フーリエ変換と離散フーリエ変換に関するウィキペディアの記事を読みましたが、結果の配列が何を表しているのかまだわかりません。これは、numpyを使用して配列にfftを実行した後の配列の外観です。

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
   4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
   2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
  -2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
  -1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
  -4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
   1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
  -2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
  -2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
  -1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
  -1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
  -2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
   3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

これらの数字が正確に何を表しているのか、これらの数字を32個のバーそれぞれの高さのパーセンテージに変換する方法を疑問に思っています。また、2つのチャネルを一緒に平均化する必要がありますか?

105
user19745

表示している配列は、オーディオ信号のフーリエ変換係数です。これらの係数は、オーディオの周波数コンテンツを取得するために使用できます。 FFTは複素数値の入力関数に対して定義されているため、入力がすべて実数値であっても、得られる係数は虚数になります。各周波数の電力量を取得するには、各周波数のFFT係数の大きさを計算する必要があります。これはnot係数の実数成分であるため、実数成分と虚数成分の平方和の平方根を計算する必要があります。つまり、係数がa + b * jの場合、その大きさはsqrt(a ^ 2 + b ^ 2)です。

各FFT係数の大きさを計算したら、各FFT係数が属するオーディオ周波数を把握する必要があります。 NポイントFFTは、0から始まる等間隔のN個の周波数での信号の周波数成分を提供します。サンプリング周波数は44100サンプル/秒であるためです。 FFTのポイント数が256の場合、周波数間隔は44100/256 = 172 Hz(概算)です。

配列の最初の係数は0の周波数係数になります。これは基本的に、すべての周波数の平均電力レベルです。残りの係数は、172 Hzの倍数で0から128に達するまでカウントアップします。FFTでは、サンプルポイントの半分までの周波数しか測定できません。 ナイキスト周波数 および ナイキスト-シャノンサンプリング定理 でこれらのリンクを読んでください複製されるか、より高い頻度のバケットで aliased になります。したがって、周波数は0から始まり、N/2係数まで各係数で172 Hz増加し、次にN-1係数まで172 Hz減少します。

それはあなたが始めるのに十分な情報でなければなりません。ウィキペディアで提供されているよりもはるかに親しみやすいFFTの紹介が必要な場合は、 nderstanding Digital Signal Processing:2nd Ed。 を試してみてください。とても助かりました。

それがそれらの数字が表すものです。高さのパーセンテージへの変換は、各周波数成分の大きさをすべての成分の大きさの合計でスケーリングすることにより実行できます。ただし、それは相対的な頻度分布の表現を提供するだけで、各周波数の実際のパワーは提供しません。周波数成分に対して可能な最大の大きさでスケーリングを試みることができますが、それが非常にうまく表示されるかどうかはわかりません。実行可能なスケーリング係数を見つけるための最も簡単な方法は、適切な設定を見つけるために大音量の音声信号とソフトな音声信号を実験することです。

最後に、オーディオ信号全体の周波数成分を全体として表示する場合は、2つのチャネルを一緒に平均化する必要があります。ステレオオーディオをモノラルオーディオにミキシングし、結合された周波数を表示しています。左右の周波数に2つの別々のディスプレイが必要な場合は、各チャネルでフーリエ変換を個別に実行する必要があります。

203
A. Levy

このスレッドは数年前のものですが、非常に役立ちました。これを見つけて、似たようなものを作成しようとしている人に自分の意見を伝えたかっただけです。

バーへの分割に関しては、バーの数に基づいてデータを均等に分割することにより、これをanttiが示唆するように行うべきではありません。最も有用なのは、データをオクターブ部分に分割することです。各オクターブは前の周波数の2倍です。 (つまり、100hzは50hzから1オクターブ上、25hzから1オクターブ上です)。

必要なバーの数に応じて、範囲全体を1/Xオクターブ範囲に分割します。与えられたバーの中心周波数Aに基づいて、バーの上限と下限を以下から取得します。

upper limit = A * 2 ^ ( 1 / 2X )
lower limit = A / 2 ^ ( 1 / 2X )

次の隣接する中心周波数を計算するには、同様の計算を使用します。

next lower =  A / 2 ^ ( 1 / X )
next higher = A * 2 ^ ( 1 / X )

次に、これらの範囲に収まるデータを平均して、各バーの振幅を取得します。

例:1/3オクターブの範囲に分割し、1kHzの中心周波数から始めます。

Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9

44100hzと1024個のサンプル(各データポイント間の43hz)が与えられた場合、21から26までの値を平均する必要があります(890.9/43 = 20.72〜21および1122.5/43 = 26.10〜26)

(1/3オクターブ小節では、〜40hzから〜20khzの間で約30小節が得られます)。ここまででわかるように、上に行くほど、より広い範囲の数値が平均化されます。通常、低いバーには1つまたは少数のデータポイントのみが含まれます。一方、高いバーは数百ポイントの平均になります。 86hzは43hzより1オクターブ高いためです。10086hzは10043hzとほとんど同じように聞こえます。

26
Erik A.

持っているのは、時間の長さが256/44100 = 0.00580499秒のサンプルです。これは、周波数分解能が1/0.00580499 = 172 Hzであることを意味します。 Pythonから得られる256個の値は、基本的に86 Hz〜255 * 172 + 86 Hz = 43946 Hzの周波数に対応します。得られる数値は複素数です(したがって、 j」を2番目の数字の最後に追加します)。

編集:間違った情報を修正

Sqrt(iを計算して、複素数を振幅に変換する必要があります2 + j2)ここで、iとjは実数部と虚数部です。

32小節にしたい場合は、4つの連続する振幅の平均を把握し、必要な256/4 = 32小節を取得する必要があります。

10
Antti Huima