(Ceci est en Python, et le code serait génial, mais je suis surtout intéressé par l'algorithme.)Trouver une série de motifs dans un flux de données
Je suis la surveillance d'un flux audio (PyAudio) et à la recherche d'une série de 5 pops (voir en bas pour une visualisation). Je suis en train de lire() le flux et d'obtenir la valeur RMS pour le bloc que je viens de lire (similaire à this question). Mon problème est que je ne cherche pas un seul événement, mais plutôt une série d'événements (pops) qui ont quelques caractéristiques mais qui ne sont pas aussi booléens que je le voudrais. Quel est le moyen le plus simple (et performant) pour détecter ces cinq pops?
La fonction RMS me donne un cours d'eau comme ceci:
0.000580998485254, 0.00045098391298, 0.00751436443973, 0.002733730043, 0.00160775708652, 0.000847808804511
Il semble un peu plus utile si je compléterai (un flux similaire) pour vous:
0.001, 0.001, 0.018, 0.007, 0.003, 0.001, 0.001
Vous pouvez voir la pop à l'article 3, et sans doute comme il calme dans l'article 4, et peut-être la queue était pendant une fraction de l'article 5.
Je veux détecter 5 de ceux d'affilée.
Mon approche naïve est de: a) définir ce qu'est un pop: Le RMS du bloc est supérieur à .002. Pour au moins 2 blocs mais pas plus de 4 blocs. Commencé par le silence et se termine par le silence. En outre, je suis tenté de définir ce qu'est le silence (pour ignorer les blocs pas très forts mais pas tout à fait silencieux, mais je ne suis pas sûr que cela ait plus de sens que de considérer que pop est booléen). B) Ensuite, ayez une machine à états qui garde la trace d'un tas de variables et qui a un tas d'instructions if. Comme:
while True:
is_pop = isRMSAmplitudeLoudEnoughToBeAPop(stream.read())
if is_pop:
if state == 'pop':
#continuation of a pop (or maybe this continuation means
#that it's too long to be a pop
if num_pop_blocks <= MAX_POP_RECORDS:
num_pop_blocks += 1
else:
# too long to be a pop
state = 'waiting'
num_sequential_pops = 0
else if state == 'silence':
#possible beginning of a pop
state = 'pop'
num_pop_blocks += 1
num_silence_blocks = 0
else:
#silence
if state = 'pop':
#we just transitioned from pop to silence
num_sequential_pops += 1
if num_sequential_pops == 5:
# we did it
state = 'waiting'
num_sequential_pops = 0
num_silence_blocks = 0
fivePopsCallback()
else if state = 'silence':
if num_silence_blocks >= MAX_SILENCE_BLOCKS:
#now we're just waiting
state = 'waiting'
num_silence_blocks = 0
num_sequential_pops = 0
Ce code n'est pas du tout complète (et peut-être un bug ou deux), mais illustre ma ligne de pensée. C'est certainement plus complexe que je ne le voudrais, et c'est pourquoi je demande des suggestions.
Dans tous les cas, est-ce que je garderais un état de combien de temps le pop a pris (même avec SMA ce n'est pas un pop s'il dure 3 secondes). Et pour mesurer combien de temps la pop a pris, j'ai besoin de suivre le nombre d'images depuis le début, et si nous sommes actuellement dans un état pop ou non pop? Et aussi # de pops dans le passé? Ou est-ce que le SMA résoudrait cela d'une manière que je ne vois pas? –
Il m'est difficile d'aller plus loin sans une vision des données et de leurs transformations. Si c'était moi, j'obtiendrais un échantillon de vos données d'entrée avec plusieurs occurrences des phénomènes curieux; écrire une fonction pour représenter graphiquement les données; appliquer différents lissages, algorithmes de détection de bruit, etc. montre l'original + lissé + pop-détection + 5-dans-une-rangée-détection sur un nouveau graphique; Puis ajustez jusqu'à ce que cela corresponde à vos besoins. Une fois cela fait, lancez-le sur un nouveau, plus grand, échantillon de vos données et assurez-vous qu'il fonctionne pour cela avant de l'utiliser sérieusement :-) – Paddy3118
Ma difficulté n'était pas la transformation (RMS ou simple moyenne mobile ou tout ce qui semble suffisant pour cela cas d'utilisation), mais la détection réelle d'un pop, puis la détection de plusieurs pops dans une rangée. Je posterai mon code. Merci pour votre réponse. –