En développant un jeu, vous pourriez trouver des valeurs trop bruyantes pour vos besoins. Le cas habituel est une entrée utilisateur analogique (souris, clavier tactile ou joystick), mais le bruit peut également provenir des systèmes de jeu, comme la physique ou les comportements de pilotage, où des solutions approximatives ou des changements non contigus génèrent du bruit. Dans ce tutoriel, vous apprendrez un moyen simple d'atténuer ces valeurs bruitées. Les exemples de code sont en C #, mais ils sont faciles à adapter à tout autre langage..
Le moyen le plus simple de lisser la valeur variable consiste à prendre un certain nombre d'échantillons passés et à les calculer en moyenne. Nous utiliserons un nombre constant d'échantillons, de sorte qu'un tableau de taille fixe constitue un choix naturel et efficace pour les stocker. Ensuite, pour éviter de décaler ce tableau, nous allons utiliser une astuce: la structure de données "ring buffer".
Commençons par définir les données à stocker dans notre classe d'utilitaires:
classe publique SlidingAverage float [] buffer; somme forfaitaire; int lastIndex; public SlidingAverage (int num_samples, float initial_value) buffer = new float [num_samples]; lastIndex = 0; reset (valeur_initial);
Nous avons ici notre tampon d’échantillons, la somme des échantillons et le dernier index utilisé dans le tableau. Le constructeur alloue le tableau de tampons, définit lastIndex
à zéro, et appelle le réinitialiser()
méthode:
public void reset (valeur float) sum = valeur * buffer.Length; pour (int i = 0; iIci, nous remplissons le tampon avec la valeur initiale spécifiée et définissons la somme en conséquence. Cette méthode peut être utilisée à tout moment pour redémarrer le lissage afin d'éviter les effets de mémoire des échantillons précédents..
Maintenant, la méthode principale: insérer une nouvelle valeur dans notre mémoire tampon circulaire:
pushValue public void (valeur float) sum- = buffer [lastIndex]; // soustrait l'échantillon le plus ancien de la somme somme + = valeur; // ajoute le nouvel exemple de tampon [lastIndex] = value; // stocke le nouvel échantillon // avance l'index et le retourne à lastIndex + = 1; if (lastIndex> = buffer.Length) lastIndex = 0;Ici, nous écrasons l’échantillon le plus ancien à
lastIndex
avec le nouveau, mais avant cela, nous ajustons la somme en soustrayant l'ancien échantillon et en ajoutant le nouveau.Ensuite, on avance
lastIndex
afin qu'il pointe vers le prochain échantillon (qui est maintenant le plus ancien). Mais si on avance justelastIndex
nous allons manquer de tableau en un rien de temps, donc quand il sort du tableau, nous l'enroulons à zéro.Voilà pourquoi c'est un bague tampon. Cela revient essentiellement à déplacer le tableau et à ajouter le nouvel échantillon, mais beaucoup plus rapidement, car au lieu de copier les valeurs en mémoire, nous revenons à l'index..
Maintenant, il ne manque plus que la valeur lissée:
public float getSmoothedValue () return sum / buffer.Length;C'est tout; nous divisons simplement la somme par le nombre d'échantillons pour obtenir la moyenne. Si nous ne stockions pas la somme, nous devions la calculer ici à partir des échantillons.
Résultats
Jetons un coup d'oeil aux résultats:
La ligne noire est le signal d'origine (onde sinusoïdale avec un peu de bruit), la ligne blanche est lissée avec deux échantillons et la ligne rouge est lissée avec quatre échantillons..Comme vous le voyez, même quelques échantillons le rendent nettement plus lisse, mais plus nous utilisons d’échantillons, plus il est en retard sur le signal original. C'est prévu, car nous n'utilisons que des échantillons antérieurs dans le cas en temps réel. Si vous post-traitement, vous pouvez décaler les valeurs lissées dans le temps pour éviter le décalage.
Conclusion
Vous avez maintenant une classe d'utilitaires simple qui peut être utilisée pour lisser les valeurs entrantes bruyantes, qu'il s'agisse d'une entrée utilisateur, d'un suivi d'objet ou d'un indicateur de vitesse..
On peut encore l’améliorer en ajoutant des poids à l’échantillon (nous avons utilisé une simple moyenne à constante
1 / N
poids), mais c’est un sujet important, le traitement du signal numérique, et il vaut mieux laisser à un futur tutoriel!