web-dev-qa-db-ja.com

scipy.signal.spectrogramを使用するときの間違ったスペクトログラム

次のコードを使用してmatplotlibのplt.specgramを使用すると、生成されたスペクトログラムは正しいです

import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np

sample_rate, samples = wavfile.read('.\\Wav\\test.wav')

Pxx, freqs, bins, im = plt.specgram(samples[:,1], NFFT=1024, Fs=44100, noverlap=900)

spectrogram generated by using matplotlib

ただし、 scipy page で指定されたサンプルコードを次のコードで使用してスペクトログラムを生成すると、次のようになります。

import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np

sample_rate, samples = wavfile.read('.\\Wav\\test.wav')

frequencies, times, spectrogram = signal.spectrogram(samples[:,1],sample_rate,nfft=1024,noverlap=900, nperseg=1024)

plt.pcolormesh(times, frequencies, spectrogram)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')

enter image description here

何が起こっているかをデバッグするために、最初の方法で生成されたPxxfreqsbinsを使用してから、2番目の方法を使用してデータをプロットしてみました。

plt.pcolormesh(bins, freqs, Pxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')

enter image description here

生成されるグラフは、2番目の方法で生成されるグラフとほぼ同じです。ですから、結局scipy.signal.spectrogramは問題ないようです。問題は、グラフをプロットする方法です。 scipy document でこの方法が提案されているにもかかわらず、plt.pcolormeshがスペクトログラムをプロットする正しい方法であるかどうか疑問に思います。

同様の質問がありました ここ ですが、質問に対する解決策はまだありません。

7
Raven Cheuk

スペックグラムのデフォルトのスケーリングモードは「dB」です(スペックグラムのドキュメントから)

scale:[‘default’ | ‘linear’ | ‘dB’]仕様の値のスケーリング。 「線形」はスケーリングではありません。 'dB'はdBスケールで値を返します。モードが 'psd'の場合、これはdBパワー(10 * log10)です。それ以外の場合、これはdB振幅(20 * log10)です。モードは「psd」または「振幅」であり、それ以外の場合は「線形」です。モードが「角度」または「位相」の場合、これは「線形」である必要があります。

mode:[‘default’ | ‘psd’ | ‘magnitude’ | ‘angle’ | ‘phase’]使用するスペクトルの種類。 デフォルトは「psd」、これはパワースペクトル密度を取ります。 「complex」は、複素数値の周波数スペクトルを返します。 「マグニチュード」はマグニチュードスペクトルを返します。 「角度」は、アンラップせずに位相スペクトルを返します。 「位相」は、アンラップされた位相スペクトルを返します。

pcolormeshで同様の結果を得るには、データを同等にスケーリングする必要があります。

plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram))

Pcolormeshの例はスケーリングが正しいとは思いません。例ではキャリアをはっきりと見ることができますが、追加されたノイズ信号は見えません。

4
jaket

代わりにこれを使用してください:

plt.pcolormesh(times, frequencies, spectrogram, norm = matplotlib.colors.Normalize(0,1))

これにより、プロットする前にデータが正規化されるため、色を適切に視覚化できます。 matplotlib.colors.Colormap に関するドキュメントには、「通常、カラーマップインスタンスは、データ値(フロート)を間隔[0、1]からそれぞれのカラーマップが表すRGBAカラーに変換するために使用されます」と記載されています。値がこの範囲外の場合は、おそらく暗い色にプロットされます(私は信じています)。

0
Pawan Dixit