web-dev-qa-db-fra.com

Détection de crête en temps réel dans des séries chronologiques sinusoïdales bruyantes

J'ai essayé de détecter des pics dans des données chronologiques sinusoïdales en temps réel , mais je n'ai pas eu de succès jusqu'à présent. Je n'arrive pas à trouver un algorithme en temps réel qui fonctionne pour détecter les pics des signaux sinusoïdaux avec un niveau de précision raisonnable. Soit je n'obtiens aucun pic détecté, soit j'obtiens un zillion de points le long de l'onde sinusoïdale détectée comme des pics.

Qu'est-ce qu'un bon algorithme en temps réel pour les signaux d'entrée qui ressemblent à une onde sinusoïdale et peuvent contenir du bruit aléatoire?


En tant que cas de test simple, considérons une onde sinusoïdale stationnaire qui a toujours la même fréquence et amplitude. (La fréquence et l'amplitude exactes n'ont pas d'importance; j'ai choisi arbitrairement une fréquence de 60 Hz, une amplitude de +/- 1 unité, à une fréquence d'échantillonnage de 8 KS/s.) Le code MATLAB suivant générera une telle sinusoïdale signal:

dt = 1/8000;
t  = (0:dt:(1-dt)/4)';
x  = sin(2*pi*60*t);

En utilisant l'algorithme développé et publié par Jean-Paul , je n'obtiens aucun pic détecté (à gauche) ou un zillion de "pics" détectés (à droite):

J'ai essayé à peu près toutes les combinaisons de valeurs pour ces 3 paramètres auxquelles je pouvais penser, en suivant les "règles de base" que Jean-Paul donne , mais je n'ai pas encore pu obtenir mon résultat attendu.


J'ai trouvé un algorithme alternatif, développé et publié par Eli Billauer , qui fait me donne les résultats que je veux - par exemple:

Même si l'algorithme d'Eli Billauer est beaucoup plus simple et a tendance à produire de manière fiable les résultats que je souhaite, il ne convient pas aux applications en temps réel.


Comme autre exemple de signal auquel j'aimerais appliquer un tel algorithme, considérons le cas de test donné par Eli Billauer pour son propre algorithme:

t = 0:0.001:10;
x = 0.3*sin(t) + sin(1.3*t) + 0.9*sin(4.2*t) + 0.02*randn(1, 10001);

Il s'agit d'un signal plus inhabituel (moins uniforme/régulier), avec une fréquence et une amplitude variables, mais toujours généralement sinusoïdal. Les pics sont clairement visibles à l'œil lorsqu'ils sont tracés, mais difficiles à identifier avec un algorithme.


Qu'est-ce qu'un bon algorithme temps réel pour identifier correctement les pics d'un signal d'entrée sinusoïdal? Je ne suis pas vraiment un expert en traitement du signal, il serait donc utile d'obtenir quelques règles empiriques qui prennent en compte les entrées sinusoïdales. Ou, peut-être que j'ai besoin de modifier par exemple L'algorithme de Jean-Paul lui-même pour fonctionner correctement sur des signaux sinusoïdaux. Si tel est le cas, quelles modifications seraient nécessaires et comment pourrais-je procéder?

6
Cody Gray

Pensez à utiliser findpeaks, c'est rapide, ce qui peut être important pour le temps réel. Vous devez filtrer le bruit haute fréquence pour améliorer la précision. ici, je lisse les données avec une fenêtre en mouvement.

t = 0:0.001:10;
x = 0.3*sin(t) + sin(1.3*t) + 0.9*sin(4.2*t) + 0.02*randn(1, 10001);
[~,iPeak0] = findpeaks(movmean(x,100),'MinPeakProminence',0.5);

Vous pouvez chronométrer le processus (0.0015sec)

f0 = @() findpeaks(movmean(x,100),'MinPeakProminence',0.5)
disp(timeit(f0,2))

Pour comparer, le traitement de la pente n'est qu'un peu plus rapide (0,00013sec), mais findpeaks a de nombreuses options utiles, telles que l'intervalle minimum entre les pics, etc.

iPeaks1 = derivePeaks(x);
f1 = @() derivePeaks(x)
disp(timeit(f1,1))

Où derivePeaks est:

function iPeak1 = derivePeaks(x)
xSmooth = movmean(x,100);
goingUp = find(diff(movmean(xSmooth,100)) > 0);
iPeak1 = unique(goingUp([1,find(diff(goingUp) > 100),end]));
iPeak1(iPeak1 == 1 | iPeak1 == length(iPeak1)) = [];
end
0
Yuval Harpaz