ピーク検出
前回、Pythonで自作モジュールをパッケージ化する方法を紹介しました。
今回は信号解析でよく使うピーク検出の方法を紹介します。
それでは始めていきましょう。
ピーク検出の基本
まずとりあえずピーク検出をする方法を紹介していきます。
そこで必要なのはピーク検出をするためのデータです。
最初は単純なsin波を使ってみることにしましょう。
import matplotlib.pyplot as plt
import numpy as np
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) for i in x]
plt.plot(x,y)
plt.show()
sin波を作るには、xに角度の系列を作り、yにsinθの系列を作ります。
この際、numpyでのsinは角度に度数ではなくラジアンを入力する必要があるので注意しましょう。
nは360°の中で現れるピークの数です。
できたsin波はこんな感じです。
このsin波に対してピーク検出をしてみましょう。
ピーク検出をするには「scipy.signalのfind_peaks」をインポートします。
そして「find_peaks(yの系列)」とするとピークのインデックスが得られます。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) for i in x]
peaks = find_peaks(y)
print(peaks)
実行結果
(array([ 30, 150, 270]), {})
これをグラフ上に線で表示するには「plt.axvline(x値)」を使用します。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) for i in x]
peaks = find_peaks(y)
plt.plot(x,y)
for i in peaks[0]:
plt.axvline(x[i], color="Red")
plt.show()
ピークの取得に制限を掛ける方法
先の例のようにはっきりとして、必ずピーク位置が1点になる場合はかなり簡単にピーク検出をすることができます。
ですが、シグナルにノイズが乗っている場合はそうはいきません。
例えばこんな感じ。
import matplotlib.pyplot as plt
import numpy as np
import random
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) + random.random() for i in x]
plt.plot(x,y)
plt.show()
実行結果
人の目で見れば大体のピーク位置は分かるのですが、これを「find_peaks」するとこうなります。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) + random.random() for i in x]
peaks = find_peaks(y)
plt.plot(x,y)
for i in peaks[0]:
plt.axvline(x[i], color="Red")
plt.show()
実行結果
ノイズの小さなピークも検出してしまい、本来のsin波のピークはできていません。
こういう場合はピークの間隔とピークの高さを制限してあげます。
ピークの間隔を制限するには「find_peaks」に「distance」のオプションを追加します。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) + random.random() for i in x]
peaks = find_peaks(y, distance=25)
plt.plot(x,y)
for i in peaks[0]:
plt.axvline(i, color="Red")
plt.show()
実行結果
次にピークの高さを制限してみましょう。
ピークの高さを制限するには「find_peaks」のオプションに「height」を追加します。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
import random
n = 3
x = range(0, 360)
y = [np.sin(i*np.pi/180*n) + random.random() for i in x]
peaks = find_peaks(y, distance=25, height=1.5)
plt.plot(x,y)
for i in peaks[0]:
plt.axvline(i, color="Red")
plt.show()
実行結果
これでノイズがあってもsin波のピークを取得できました。
次回はPythonでZero Crossing(ゼロ交差)というプラスとマイナスが入れ替わる位置を取得する方法を紹介します。
ではでは今回はこんな感じで。
コメント