J'analyse les données sur une carte SD un gros morceau à la fois sur un microcontrôleur. Ce sont des données d'accéléromètre donc elles oscillent constamment. À certains points, d'énormes oscillations se produisent (illustrées dans le graphique). J'ai besoin d'un algorithme pour pouvoir détecter ces grandes oscillations, et plus encore, déterminer la plage de données contenant ce pic.

J'ai quelques exemples de données:

Graphique global C'est le graphique global, il n'y a qu'un seul pic d'intérêt, le premier.

zoom avant Ici, il est un peu zoomé

oscillation Comme vous pouvez le voir, c'est une grande oscillation qui produit le pic.

Donc, tout algorithme qui peut parcourir un ensemble de données et déterminer la partie de données qui contient un pic par rapport à un certain seuil serait génial. Cet ensemble de données est d'environ 50 000 échantillons, chaque échantillon a une longueur de 32 bits. J'ai suffisamment de RAM pour pouvoir contenir autant de données.

Merci!

1
alexv9 20 juin 2019 à 21:39

3 réponses

Meilleure réponse

Pour le signal suivant:

enter image description here

Si vous prenez la valeur absolue du différentiel entre deux échantillons consécutifs, vous obtenez:

enter image description here

Ce n'est pas tout à fait suffisant pour distinguer sans ambiguïté des perturbations mineures «non soutenues». Mais si vous prenez alors une simple somme mobile (un intégrateur qui fuit) des abs-différentiels. Ici, une largeur de fenêtre de 4 échantillons différentiels a été utilisée:

enter image description here

La moyenne mobile introduit un décalage ou un déphasage, qui, dans les cas où les données sont stockées et le traitement n'est pas temps réel , peut facilement être compensé en soustrayant la moitié de la largeur de la fenêtre du timing:

enter image description here

Pour le traitement en temps réel, si le décalage est critique, un filtre IIR plus sophistiqué peut être approprié. Quoi qu'il en soit, un seuil clair peut être sélectionné à partir de ces données.

Dans le code pour l'ensemble de données ci-dessus:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

static int32_t dataset[] = { 0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,-10,-15,-5,20,25,50,-10,-20,-30,0,30,5,-5,
                             0,0,5,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,6,0,0,0,0,0,0,0} ;

#define DATA_LEN (sizeof(dataset)/sizeof(*dataset))
#define WINDOW_WIDTH 4
#define THRESHOLD 15 
int main()
{
    uint32_t window[WINDOW_WIDTH] = {0} ;
    int window_index = 0 ;
    int window_sum = 0 ;
    bool spike = false ;

    for( int s = 1; s < DATA_LEN ; s++ )
    {
        uint32_t diff = abs( dataset[s] - dataset[s-1] ) ;
        window_sum -= window[window_index] ;
        window[window_index] = diff ;
        window_index++ ;
        window_index %= WINDOW_WIDTH ;
        window_sum += diff ;

        if( !spike && window_sum >= THRESHOLD )
        {
            spike = true ;
            printf( "Spike START @ %d\n", s - WINDOW_WIDTH / 2 ) ;
        }
        else if( spike && window_sum < THRESHOLD )
        {
            spike = false ;
            printf( "Spike END @   %d\n", s - WINDOW_WIDTH / 2 ) ;
        }
    }

    return 0;
}

La sortie est:

Spike START @ 66
Spike END @   82

https://onlinegdb.com/ryEw69jJH

La comparaison des données d'origine avec le seuil de détection donne:

enter image description here

Pour vos données réelles, vous devrez sélectionner une largeur de fenêtre et un seuil appropriés pour obtenir le résultat souhaité, qui dépendront tous deux de la bande passante et de l'amplitude des perturbations que vous souhaitez détecter.

Vous devrez peut-être également vous protéger contre un débordement arithmétique si vos échantillons sont d'une ampleur suffisante. Ils doivent être inférieurs à 2 32 / largeur de fenêtre pour garantir l'absence de débordement dans l'intégrateur. Vous pouvez également utiliser virgule flottante ou uint64_t pour le type window, ou ajouter du code pour gérer la saturation .

3
Clifford 24 juin 2019 à 21:13

Vous pouvez regarder une analyse statistique. Calcul de l'écart type sur l'ensemble de données, puis vérification du moment où vos données sortent des limites.

Vous pouvez choisir de le faire de deux manières; soit vous utilisez une moyenne mobile sur un nombre fixe (relativement petit) d'échantillons, soit vous prenez la moyenne sur l'ensemble de l'ensemble de données. Comme je vois plusieurs pics dans votre ensemble, je suggérerais le premier. De cette façon, vous pouvez éventuellement arrêter le traitement (et continuer plus tard) chaque fois que vous trouvez un pic.

Pour votre objectif, vous n'avez pas vraiment besoin de calculer l'écart type sigma. Vous pouvez en fait le laisser au carré de sigma. Cela vous donnera une légère optimisation des performances sans avoir à calculer la racine carrée.

Un pseudo code:

// The data set.
int x[N];   

// The number of samples in your mean and std calculation.
int M <= N;  

// Simga at index i over the previous M samples.
int sigma_i = sqrt( sum( pow(x[i] - mean(x,M), 2) ) / M );

// Or the squared of sigma 
int sigma_squared_i = sum( pow(x[i] - mean(x,M), 2) ) / M;

L'inconvénient de cette méthode est que vous devez définir un seuil pour la valeur de sigma à laquelle vous déclenchez. Cependant, il est très sûr de dire que lorsque vous définissez le seuil à 4 ou 5 fois votre sigma moyen, vous aurez un système utilisable.

3
Bart 21 juin 2019 à 07:16

Géré pour obtenir un algorithme fonctionnel. En gros, déterminez la différence moyenne entre les points de données. Si mes données commencent à dépasser un certain multiple de cette valeur consécutivement, il est fort probable qu'un pic se produise.

0
alexv9 21 juin 2019 à 14:04