web-dev-qa-db-fra.com

Lissage des valeurs dans le temps: moyenne mobile ou quelque chose de mieux?

Je code quelque chose au moment où je prends un tas de valeurs au fil du temps à partir d'une boussole matérielle. Cette boussole est très précise et se met à jour très souvent, de sorte que si elle tremble légèrement, je me retrouve avec la valeur étrange qui est follement incohérente avec ses voisins. Je veux lisser ces valeurs.

Après avoir fait un peu de lecture, il semblerait que ce que je veux, c'est un filtre passe-haut, un filtre passe-bas ou une moyenne mobile. Moyenne mobile avec laquelle je peux descendre, il suffit de garder un historique des 5 dernières valeurs ou autre chose, et d'utiliser la moyenne de ces valeurs en aval dans mon code où je n'utilisais autrefois que la valeur la plus récente.

Cela devrait, je pense, adoucir ces secousses, mais il me semble que c'est probablement assez inefficace, et c'est probablement l'un de ces problèmes connus des programmeurs appropriés pour lesquels il existe une solution Clever Math vraiment soignée.

Je suis, cependant, un de ces horribles programmeurs autodidactes sans la moindre éducation formelle dans quoi que ce soit même vaguement lié à CompSci ou Math. Lire un peu suggère que cela peut être un filtre passe-haut ou passe-bas, mais je ne trouve rien qui explique en termes compréhensibles pour un hack comme moi quel serait l'effet de ces algorithmes sur un tableau de valeurs, et encore moins comment les mathématiques fonctionnent. La réponse donnée ici , par exemple, répond techniquement à ma question, mais uniquement en termes compréhensibles pour ceux qui sauraient probablement déjà comment résoudre le problème.

Ce serait en effet une personne très charmante et intelligente qui pourrait expliquer le genre de problème et comment les solutions fonctionnent, en termes compréhensibles pour un diplômé en arts.

46
Henry Cooke

Si votre moyenne mobile doit être longue pour obtenir le lissage requis et que vous n'avez pas vraiment besoin d'une forme particulière de noyau, alors vous feriez mieux si vous utilisez une moyenne mobile en décomposition exponentielle:

a(i+1) = tiny*data(i+1) + (1.0-tiny)*a(i)

où vous choisissez tiny pour être une constante appropriée (par exemple, si vous choisissez tiny = 1-1/N, elle aura la même quantité de moyenne qu'une fenêtre de taille N, mais répartie différemment sur les points plus anciens).

Quoi qu'il en soit, puisque la prochaine valeur de la moyenne mobile ne dépend que de la précédente et de vos données, vous n'avez pas besoin de garder une file d'attente ou quoi que ce soit. Et vous pouvez penser à cela comme faisant quelque chose comme: "Eh bien, j'ai un nouveau point, mais je n'y crois pas vraiment, donc je vais garder 80% de mon ancienne estimation de la mesure, et seulement faites confiance à ce nouveau point de données à 20% ". C'est à peu près la même chose que de dire: "Eh bien, je ne fais confiance qu'à ce nouveau point à 20%, et j'utiliserai 4 autres points que j'ai confiance en le même montant", sauf qu'au lieu de prendre explicitement les 4 autres points, vous êtes en supposant que la moyenne que vous avez faite la dernière fois était raisonnable afin que vous puissiez utiliser votre travail précédent.

38
Rex Kerr

Si vous essayez de supprimer la valeur impaire occasionnelle, un filtre passe-bas est la meilleure des trois options que vous avez identifiées. Les filtres passe-bas permettent des changements à basse vitesse tels que ceux provoqués par la rotation manuelle d'une boussole, tout en rejetant les changements à grande vitesse tels que ceux causés par des bosses sur la route, par exemple.

Une moyenne mobile ne sera probablement pas suffisante, car les effets d'un seul "blip" dans vos données affecteront plusieurs valeurs ultérieures, selon la taille de votre fenêtre de moyenne mobile.

Si les valeurs impaires sont facilement détectées, vous pouvez même être mieux avec un algorithme de suppression des pépins qui les ignore complètement:

if (abs(thisValue - averageOfLast10Values) > someThreshold)
{
    thisValue = averageOfLast10Values;
}

Voici un graphique guick pour illustrer:

graph comparison

Le premier graphique est le signal d'entrée, avec un petit problème désagréable. Le deuxième graphique montre l'effet d'une moyenne mobile de 10 échantillons. Le graphique final est une combinaison de la moyenne à 10 échantillons et de l'algorithme de détection de glitch simple illustré ci-dessus. Lorsque le problème est détecté, la moyenne de 10 échantillons est utilisée à la place de la valeur réelle.

58
e.James

Moyenne mobile avec laquelle je peux descendre ... mais il me semble que c'est probablement assez inefficace.

Il n'y a vraiment aucune raison qu'une moyenne mobile soit inefficace. Vous conservez le nombre de points de données que vous souhaitez dans un tampon (comme une file d'attente circulaire). Sur chaque nouveau point de données, vous popez la valeur la plus ancienne et la soustrayez d'une somme, appuyez sur la plus récente et l'ajoutez à la somme. Ainsi, chaque nouveau point de données ne comporte vraiment qu'un pop/push, un ajout et une soustraction. Votre moyenne mobile est toujours cette somme mobile divisée par le nombre de valeurs dans votre tampon.

Cela devient pe plus compliqué si vous recevez des données simultanément à partir de plusieurs threads, mais puisque vos données proviennent d'un périphérique matériel qui me semble très douteux.

Oh et aussi: d'horribles programmeurs autodidactes s'unissent! ;)

6
Dan Tao

Une moyenne mobile en décroissance exponentielle peut être calculée "à la main" avec uniquement la tendance si vous utilisez les valeurs appropriées. Voir http://www.fourmilab.ch/hackdiet/e4/ pour une idée sur la façon de le faire rapidement avec un stylo et du papier si vous recherchez une "moyenne mobile lissée exponentiellement avec un lissage de 10% ". Mais puisque vous avez un ordinateur, vous voudrez probablement faire un décalage binaire plutôt qu'un décalage décimal;)

De cette façon, tout ce dont vous avez besoin est une variable pour votre valeur actuelle et une pour la moyenne. La moyenne suivante peut alors être calculée à partir de cela.

2
Daren Thomas

il existe une technique appelée porte de plage qui fonctionne bien avec les échantillons parasites de faible occurrence. en supposant l'utilisation de l'une des techniques de filtrage mentionnées ci-dessus (moyenne mobile, exponentielle), une fois que vous avez un historique "suffisant" (une constante de temps), vous pouvez tester le nouvel échantillon de données entrantes pour le caractère raisonnable, avant il est ajouté au calcul.

une certaine connaissance du taux de variation raisonnable maximal du signal est requise. l'échantillon brut est comparé à la valeur lissée la plus récente, et si la valeur absolue de cette différence est supérieure à la plage autorisée, cet échantillon est rejeté (ou remplacé par une heuristique, par exemple une prédiction basée sur la pente; différentiel ou le valeur de prédiction "tendance" du double lissage exponentiel)

1
tom jennings