Outils pour utilisateurs

Outils du site


detection_pics_signal

Comment trouver les pics d'un signal ?

En traitement du signal, trouver les pics ("peaks" en anglais) peut être assez utile. Comment faire cela en Python ?

La fonction scipy.signal.signal.find_peaks, comme son nom l'indique, est utile pour cela. Mais il est important de bien comprendre ses paramètres width, threshold, distance et surtout prominence pour obtenir une bonne détection.

D'après mes tests et la documentation, le concept de proéminence (prominence) est "le concept utile" pour garder les bons pics, et pour se débarrasser des pics secondaires.

Qu'est-ce que la proéminence topographique ? C'est "la hauteur minimale nécessaire à descendre depuis le sommet, pour pouvoir atteindre un sommet plus haut", comme on peut le voir ici :

L'idée est :

Plus la proéminence est élevée, plus le sommet est "important".

Test :

J'ai utilisé une sinusoïde bruitée dont la fréquence varie, volontairement, parce qu'elle présente de nombreuses difficultés. Nous pouvons voir que le paramètre width n'est pas très utile ici parce que si on définit une largeur minimale trop élevée, alors il ne pourra pas suivre les pics très proches dans la partie haute fréquence. Si on règle la largeur trop bas, on aura beaucoup de pics indésirables dans la partie gauche du signal. Même problème avec distance. threshold ne compare qu'aux voisins directs, ce qui n'est pas utile ici. prominence est celle qui donne la meilleure solution. Notez que l'on peut combiner plusieurs de ces paramètres ! (issu d'une réponse que j'ai postée sur stackoverflow).

Code :

import numpy as np
import matplotlib.pyplot as plt 
from scipy.signal import find_peaks

x = np.sin(2*np.pi*(2**np.linspace(2,10,1000))*np.arange(1000)/48000) + np.random.normal(0, 1, 1000) * 0.15
peaks, _ = find_peaks(x, distance=20)
peaks2, _ = find_peaks(x, prominence=1)      # MEILLEURE SOLUTION
peaks3, _ = find_peaks(x, width=20)
peaks4, _ = find_peaks(x, threshold=0.4)     
plt.subplot(2, 2, 1)
plt.plot(peaks, x[peaks], "xr"); plt.plot(x); plt.legend(['distance'])
plt.subplot(2, 2, 2)
plt.plot(peaks2, x[peaks2], "ob"); plt.plot(x); plt.legend(['prominence'])
plt.subplot(2, 2, 3)
plt.plot(peaks3, x[peaks3], "vg"); plt.plot(x); plt.legend(['width'])
plt.subplot(2, 2, 4)
plt.plot(peaks4, x[peaks4], "xk"); plt.plot(x); plt.legend(['threshold'])
plt.show()
detection_pics_signal.txt · Dernière modification: 2019/11/29 13:37 par joseph