2016-12-12 8 views
8

私は、8つのストリップのLEDで家庭用スペクトルアナライザを作成しようとしています。FFTデータをスペクトラムアナライザに使用する方法が分かりません

私が苦労している部分は、FFTを実行し、結果の使用方法を理解することです。私はpitch方法で何をするかで苦労してい

import opc 
import time 
import pyaudio 
import wave 
import sys 
import numpy 
import math 

CHUNK = 1024 

# Gets the pitch from the audio 
def pitch(signal): 
    # NOT SURE IF ANY OF THIS IS CORRECT 
    signal = numpy.fromstring(signal, 'Int16'); 
    print "signal = ", signal 

    testing = numpy.fft.fft(signal) 
    print "testing = ", testing 

wf = wave.open(sys.argv[1], 'rb') 
RATE = wf.getframerate() 
p = pyaudio.PyAudio() # Instantiate PyAudio 

# Open Stream 
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 
       channels=wf.getnchannels(), 
       rate=wf.getframerate(), 
       output=True) 

# Read data 
data = wf.readframes(CHUNK) 

# Play Stream 
while data != '': 
    stream.write(data) 
    data = wf.readframes(CHUNK) 
    frequency = pitch(data) 
    print "%f frequency" %frequency 

は、これまでのところ、これは私が持っているものです。私は、渡されたデータに対してFFTを実行する必要があることを知っていますが、本当にそれを行う方法がわかりません。

また、this関数を使用する必要がありますか?

+2

あなたは何について確信していますか? 2つの関数のドキュメントを見てください。 numpy.fft.fftfreqのドキュメントページの例を見ましたか? http://www.dspguide.com/pdfbook.htmは良いリソースです。 – wwii

+0

このページの例では、長さ8の配列が示されています。これらの長さはどのようにして8になりましたか?私のチャンクサイズは1024と2チャンネルなので、配列の長さは2048です。https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.fftpack.fftfreq.html#scipy.fftpack.fftfreq – Catfish

+0

私は2つのチャンネルを別々に扱います。 'np.fft.fft()'は入力と同じ長さの複素数値の配列を返します。各値は周波数を表し、複素数の絶対値はその周波数の大きさであり、値の複素数成分はその位相シフト。 'np.fft.fftfreq()'はフーリエ変換からの値が返された実際の周波数の配列を返します。スペクトルnp.absolute(np.fft.fft(signal))をプロットしたい場合、縦座標(y値)とnp.fft.fftfreq(...)は横座標(x)になります。 。 – wwii

答えて

3

1024データポイントを使用する場合、np.fft.fftが機能するため、512の周波数(プラス0の値、0Hz、DCオフセット)の値が得られます。 8つの周波数だけが必要な場合は、16のデータポイントを供給する必要があります。

ダウンサンプリングで64倍にすることができます。その後、ダウンサンプリングされたポイントは、で、から1024オリジナルポイントになります。私はこれを探ったことがないので、これが何をするのか、落とし穴があるのか​​分かりません。

あなたはいくつかの学習を行う必要があるでしょう - The Scientist and Engineer's Guide to Digital Signal Processingは本当に優れたリソースです、少なくともそれは私のためでした。

オーディオCDの.wavファイルのサンプル周波数は44100 Hzです。1024サンプルのチャンクはののわずか23 mSです。

scipy.io.wavfile.readは、データを簡単に取得できます。 [:0]、との他の列1、データ

samp_rate, data = scipy.io.wavfile.read(filename) 

dataカラムゼロで、データ内の1つのチャネルと2次元numpyの配列である[:1]

matplotlibののspecgramとpsd関数はあなたに必要なデータを与えることができます。あなたが何をしようとしているのかを示すグラフは類似しています。

from matplotlib import pyplot as plt 
import scipy.io.wavfile 
samp_rate, data = scipy.io.wavfile.read(filename) 
Pxx, freqs, bins, im = plt.specgram(data[:1024,0], NFFT = 16, noverlap = 0, Fs = samp_rate) 
plt.show() 
plt.close() 

プロットしていないので、matplolib.mlab.specgramを使用してください。

Pxx, freqs, t = matplolib.mlab.specgram(data[:1024,0], NFFT = 16, noverlap = 0, Fs = samp_rate) 

その戻り値(のPxxfreqsトン)は、

Pxx[1:, 0]

 - *Pxx*: 2-D array, columns are the periodograms of successive segments 

    - *freqs*: 1-D array of frequencies corresponding to the rows in Pxx 

    - *t*: 1-D array of times corresponding to midpoints of segments. 
はT2のためにT0、T1用Pxx[1:, 1]Pxx[1:, 2]ための周波数の値であろういますこれはあなたのディスプレイに与えるものです。 Pxx[0, :]は0Hzのため使用しません。

パワースペクトル密度 - matplotlib.mlab.psd()


大きなチャンクを使用して、値を正規化することであろう 8つのバンドにダウン取得するかもしれない別の戦略。次に、値を8つのセグメントに分割し、各セグメントの合計を取得することができます。私はこれが有効だと思います - おそらくパワースペクトル密度のためだけです。 sklearn.preprocessing.normalize

w = sklearn.preprocessing.normalize(Pxx[1:,:], norm = 'l1', axis = 0) 

しかし、その後、再び、私はすべてのことをアップしました。

1

@wwiiが答えているscipy.io.wavfile.readの機能についてはわかりませんが、彼の提案は信号の読み込みを処理する方法だと思われます。しかし、フーリエ変換についてコメントしたかっただけです。

あなたがあなたのLEDの設定をするつもりだと思うのは、使用する8つの周波数帯域のそれぞれのスペクトルのパワーに応じてLEDの輝度をそれぞれ変更することです。したがって、私があなたが必要と理解していることは、時間が経つにつれて何らかの方法で力を計算することです。最初の複雑さは「スペクトルパワーの計算方法」です。

これを行う最良の方法は、実数(複素数ではない)だけの信号に対するフーリエ変換を計算するnumpy.fft.rfftです。一方、関数numpy.fft.fftは、複素数を持つ信号の高速フーリエ変換を計算できる汎用関数です。概念的な違いは、進行波とその伝搬方向を調べるためにnumpy.fft.fftを使用できることです。これは、返された振幅が、波がどのように移動するかを示すpositive or negative frequenciesに対応するために見られます。 numpy.fft.rfftは、numpy.fft.rfftfreqのような実数値周波数の振幅を生成します。これは必要なものです。

最後の問題は、スペクトルパワーを計算するための適切な周波数帯を選択することです。人間の耳は巨大な周波数応答範囲を有し、各帯域の幅は非常に変化し、低周波数帯域は非常に狭く、高周波数帯域は非常に広い。 20

  • ヘルツ60ベース:250〜500ヘルツ
  • :60低音域
  • ヘルツ〜250の周りグーグル、I 7、関連する周波数帯域

    1. サブベースを定義this素敵なリソースを発見しましたミッドレンジ:2 kHzまでは500Hz
    2. アッパーミッドレンジ:2プレゼンス
    3. kHzの4:4~6キロヘルツ
    4. ブリリアンス:6は20kHz

    これらのバンドを使用することをお勧めしますが、ミッドレンジの上限は2-3 kHzと3-4 kHzに分割してください。そうすれば、8つのLED設定を使用することができます。あなたは、コードの最初の部分は、FFT周波数を計算し、8周波数帯域のFFT周波数に対応するかを示すアレイFFT_FREQS_INDSを構築

    wf = wave.open(sys.argv[1], 'rb') 
    CHUNK = 1024 
    RATE = wf.getframerate() 
    DT = 1./float(RATE) # time between two successive audio frames 
    FFT_FREQS = numpy.fft.nfftfreq(CHUNCK,DT) 
    FFT_FREQS_INDS = -numpy.ones_like(FFT_FREQS) 
    bands_bounds = [[20,60],  # Sub-bass 
           [60,250],  # Bass 
           [250,500], # Low midrange 
           [500,2000], # Midrange 
           [2000,3000], # Upper midrange 0 
           [3000,4000], # Upper midrange 1 
           [4000,6000], # Presence 
           [6000,20000]] # Brilliance 
    
    for f_ind,freq in enumerate(FFT_FREQS): 
        for led_ind,bounds in enumerate(bands_bounds): 
         if freq<bounds[1] and freq>=bounds[0]: 
          FFT_FREQS_INDS[ind] = led_ind 
    
    # Returns the spectral power in each of the 8 bands assigned to the LEDs 
    def pitch(signal): 
        # CONSIDER SWITCHING TO scipy.io.wavfile.read TO GET SIGNAL 
        signal = numpy.fromstring(signal, 'Int16'); 
        amplitude = numpy.fft.rfft(signal.astype(numpy.float)) 
        power = [np.sum(np.abs(amplitude[FFT_FREQS_INDS==led_ind])**2) for led_ind in range(len(bands_bounds))] 
        return power 
    

    使用するために私が更新ピッチ機能をアップロードしています。次に、pitchにおいて、各バンドにおけるスペクトルのパワーが計算される。もちろん、これは最適化できますが、コードを自明にしようとしました。

  • +0

    このエラーが発生する: 'if freq = bounds [0]: IndexError:リストインデックスが範囲外にある ' – Catfish

    +0

    @catfish ups!私は境界リストにタイプミスがありました。私は '、'の代わりに ' - 'を書いていました – lucianopaz

    関連する問題