Saturday 21 January 2017

Déplacement Moyenne File D'Attente

J'essaie de calculer la moyenne mobile d'un signal. La valeur du signal (un double) est mise à jour au hasard. Je cherche un moyen efficace de calculer sa moyenne pondérée en fonction du temps sur une fenêtre temporelle, en temps réel. Je pouvais le faire moi-même, mais c'est plus difficile que je pensais. La plupart des ressources que j'ai trouvées sur Internet sont le calcul de la moyenne mobile du signal périodique, mais les mises à jour de la mine au hasard. Est-ce que quelqu'un sait de bonnes ressources pour cela L'astuce est la suivante: Vous obtenez des mises à jour au hasard fois via la mise à jour vide (temps int, valeur flottante). Cependant, vous devez aussi suivre quand une mise à jour tombe de la fenêtre de temps, de sorte que vous définissez une alarme qui a appelé à l'heure N qui supprime la mise à jour précédente d'être jamais considéré à nouveau dans le calcul. Si cela se produit en temps réel, vous pouvez demander au système d'exploitation de faire un appel à une méthode void dropoffoldestupdate (int time) à appeler au moment N Si c'est une simulation, vous ne pouvez pas obtenir d'aide du système d'exploitation et vous devez Le faire manuellement. Dans une simulation, on appellerait des méthodes avec le temps fourni comme argument (qui ne correspond pas au temps réel). Cependant, une hypothèse raisonnable est que les appels sont garantis pour être tels que les arguments de temps sont en augmentation. Dans ce cas, vous devez conserver une liste triée des valeurs d'heure d'alarme et pour chaque mise à jour et appel de lecture vous vérifiez si l'argument de temps est supérieur à la tête de la liste d'alarmes. Bien qu'il soit plus important, vous effectuez le traitement d'alarme (déposez la mise à jour la plus ancienne), retirez la tête et vérifiez à nouveau jusqu'à ce que toutes les alarmes avant le moment donné soient traitées. Ensuite, effectuez l'appel de mise à jour. J'ai jusqu'à présent supposé qu'il est évident ce que vous feriez pour le calcul réel, mais je vais élaborer juste au cas où. Je suppose que vous avez une méthode float read (int time) que vous utilisez pour lire les valeurs. L'objectif est de rendre cet appel aussi efficace que possible. Donc, vous ne calculez pas la moyenne mobile chaque fois que la méthode de lecture est appelée. Au lieu de cela vous précomputer la valeur à partir de la dernière mise à jour ou la dernière alarme et ajuster cette valeur par un couple d'opérations en virgule flottante pour tenir compte du passage du temps depuis la dernière mise à jour. (C'est-à-dire un nombre constant d'opérations sauf pour le traitement peut-être d'une liste d'alarmes). Espérons que cela est clair - ce devrait être un algorithme assez simple et très efficace. Optimisation supplémentaire. L'un des problèmes restants est si un grand nombre de mises à jour se produisent dans la fenêtre de temps, puis il ya une longue période pour laquelle il n'y a ni lectures ni mises à jour, puis une lecture ou une mise à jour arrive. Dans ce cas, l'algorithme ci-dessus sera inefficace dans la mise à jour incrémentielle de la valeur de chacune des mises à jour qui est en baisse. Cela n'est pas nécessaire car nous ne nous soucions de la dernière mise à jour au-delà de la fenêtre de temps si il ya un moyen de déposer efficacement toutes les mises à jour plus anciennes, il serait utile. Pour ce faire, nous pouvons modifier l'algorithme pour faire une recherche binaire de mises à jour pour trouver la mise à jour la plus récente avant la fenêtre de temps. S'il ya relativement peu de mises à jour qui doivent être supprimées, il est possible de mettre à jour progressivement la valeur de chaque mise à jour abandonnée. Mais s'il ya beaucoup de mises à jour qui doivent être supprimées, alors on peut recalculer la valeur à partir de zéro après avoir abandonné les anciennes mises à jour. Annexe sur le calcul incrémental: Je devrais préciser ce que je veux dire par le calcul incrémental ci-dessus dans la phrase de tordre cette valeur par un couple d'opérations en virgule flottante pour tenir compte du passage du temps depuis la dernière mise à jour. Calcul initial non incrémentiel: itérer ensuite sur les dates d'actualisation en fonction de l'augmentation du temps: movingaverage (sum lastupdate timesincelastupdate) windowlength. Maintenant, si exactement une mise à jour tombe de la fenêtre mais pas de nouvelles mises à jour arriver, ajuster la somme comme: (note c'est priorupdate qui a son horodatage modifié au début de la dernière fenêtre début). Et si exactement une mise à jour entre dans la fenêtre, mais qu'aucune nouvelle mise à jour ne s'arrête, ajustez la somme comme: Comme cela devrait être évident, il s'agit d'un schéma approximatif mais nous espérons qu'il vous montrera comment vous pouvez maintenir la moyenne telle que c'est O (1) Sur une base amortie. Mais remarquez une optimisation supplémentaire dans le paragraphe précédent. Notez également les problèmes de stabilité mentionnés dans une réponse plus ancienne, ce qui signifie que des erreurs de virgule flottante peuvent s'accumuler sur un grand nombre d'opérations incrémentielles telles qu'il ya une divergence par rapport au résultat du calcul complet qui est significatif pour l'application. Si une approximation est OK et theres un temps minimum entre les échantillons, vous pouvez essayer de super-échantillonnage. Avoir un tableau qui représente des intervalles de temps régulièrement espacés qui sont plus courts que le minimum, et à chaque période de temps stocker le dernier échantillon qui a été reçu. Plus l'intervalle est court, plus la moyenne sera proche de la valeur réelle. La période ne doit pas être supérieure à la moitié du minimum ou il est possible de manquer un échantillon. Répondre Dec 15 11 at 18:12 réponse Dec 15 11 at 22:38 Merci pour la réponse. Une amélioration qui serait nécessaire pour quotcachequot la valeur de la moyenne totale donc nous don39t boucle tout le temps. En outre, il peut être un point mineur, mais ne serait-il pas plus efficace d'utiliser un deque ou une liste pour stocker la valeur, puisque nous supposons que la mise à jour viendra dans le bon ordre. L'insertion serait plus rapide que dans la carte. Ndash Arthur Dec 16 11 at 8:55 Oui, vous pouvez mettre en cache la valeur de somme. Soustrayez les valeurs des échantillons que vous effacez, ajoutez les valeurs des échantillons que vous insérez. Aussi, oui, un dequeltpairltSample, Dategtgt pourrait être plus efficace. J'ai choisi la carte pour la lisibilité, et la facilité d'invoquer map :: upperbound. Comme toujours, écrire le code correct en premier, puis profil et mesurer les changements incrémentiels. Ndash Rob Dec 16 11 at 15:00 Note: Apparemment, ce n'est pas la façon d'aborder cela. Laissant ici pour référence sur ce qui ne va pas avec cette approche. Vérifiez les commentaires. MISE À JOUR - basé sur Olis commentaire. Pas sûr de l'instabilité dont il parle cependant. Utilisez une carte triée des heures d'arrivée en fonction des valeurs. À l'arrivée d'une valeur ajouter l'heure d'arrivée à la carte triée avec sa valeur et mettre à jour la moyenne mobile. Avertissement c'est pseudo-code: Là. Pas complètement étoffé mais vous obtenez l'idée. Choses à noter. Comme je l'ai dit le code ci-dessus est pseudo. Vous aurez besoin de choisir une carte appropriée. Ne supprimez pas les paires pendant l'itération car vous invalidez l'itérateur et vous devrez recommencer. Voir Olis commentaire ci-dessous aussi. Répondre Dec 15 11 at 12:22 Ce doesn39t travail: il doesn39t prendre en compte quelle proportion de la fenêtre de longueur chaque valeur existe pour. En outre, cette approche d'addition et de soustraction est seulement stable pour les types d'entiers, pas les flotteurs. Ndash Oliver Charlesworth Dec 15 11 at 12:29 OliCharlesworth - désolé j'ai manqué quelques points clés dans la description (double et pondéré en temps). Je vais mettre à jour. Merci. Ndash Dennis Dec 15 11 at 12:33 La pondération de temps est encore un autre problème. Mais ce n'est pas ce dont je parle. Je faisais allusion au fait que quand une nouvelle valeur entre d'abord dans la fenêtre de temps, sa contribution à la moyenne est minime. Sa contribution continue d'augmenter jusqu'à l'entrée d'une nouvelle valeur. Ndash Oliver Charlesworth Dec 15 11 at 12: 35Si la performance de ce code est critique, alors il pourrait être judicieux d'éviter les allocations de tas pour Candle s. Je pense que la façon la plus raisonnable de faire cela serait de faire Candle dans une structure. Bien que les types de valeurs mutables soient mauvais. Donc je refondrais aussi Candle pour être immuable. Cela signifie également que la mise en œuvre de newestCandle devrait changer, probablement dans une paire de champs doubles (ou, alternativement, une classe mutable et réinitialisable séparée). Je ne vois aucun autre problème potentiel de performance dans votre code. Mais quand il s'agit de performance, vous devriez toujours compter sur le profilage, et non pas votre intuition (ou quelqu'un d'autre). Aussi, je n'aime pas certains noms de vos méthodes. Plus précisément: ValueUpdated. Les noms de méthode doivent généralement être sous la forme faire quelque chose, pas quelque chose s'est passé. Je pense donc qu'un meilleur nom serait UpdateValue. Ajouter. Modifier. Ce sont les deux opérations fondamentales de votre MovingAverage et je pense que ces noms n'expriment pas bien le sens. Je les appellerais quelque chose comme MoveAndSetCurrent et SetCurrent. respectivement. Bien que cette appellation indique que les opérations fondamentales doivent plutôt être Move et SetCurrent.


No comments:

Post a Comment