Données GPS fluides

145

Je travaille avec des données GPS, j'obtiens des valeurs toutes les secondes et j'affiche la position actuelle sur une carte. Le problème est que parfois (spécialement lorsque la précision est faible) les valeurs varient beaucoup, ce qui fait que la position actuelle «saute» entre des points distants de la carte.

Je me posais des questions sur une méthode assez simple pour éviter cela. Comme première idée, j'ai pensé à rejeter les valeurs avec une précision au-delà d'un certain seuil, mais je suppose qu'il existe d'autres meilleures façons de faire. Quelle est la manière habituelle dont les programmes effectuent cela?

Al.
la source
Je ressens les mauvais effets du "bruit GPS" en essayant de calculer les valeurs associées (dérivées) comme la vitesse et la pente, qui sont très discontinues spécialement pour les tracklogs à taux d'échantillonnage élevé (puisque le temps a une résolution entière [une seconde]).
heltonbiker
4
(aussi, si vous naviguez sur des routes principales, vous pouvez utiliser l'algorithme "snap to routes" à condition d'avoir un bon jeu de données de feuille de route [correct, précis]. Juste une pensée)
heltonbiker
Je suis confronté à ce problème pour une meilleure précision également.
ViruMax

Réponses:

80

Voici un simple filtre de Kalman qui pourrait être utilisé exactement dans cette situation. Cela vient d'un travail que j'ai effectué sur les appareils Android.

La théorie générale des filtres de Kalman concerne les estimations des vecteurs, la précision des estimations étant représentée par des matrices de covariance. Cependant, pour estimer l'emplacement sur les appareils Android, la théorie générale se réduit à un cas très simple. Les fournisseurs de localisation Android donnent l'emplacement sous forme de latitude et de longitude, avec une précision qui est spécifiée sous la forme d'un nombre unique mesuré en mètres. Cela signifie qu'au lieu d'une matrice de covariance, la précision du filtre de Kalman peut être mesurée par un seul nombre, même si l'emplacement dans le filtre de Kalman est mesuré par deux nombres. De plus, le fait que la latitude, la longitude et les mètres soient effectivement des unités différentes peut être ignoré, car si vous mettez des facteurs de mise à l'échelle dans le filtre de Kalman pour les convertir tous dans les mêmes unités,

Le code pourrait être amélioré, car il suppose que la meilleure estimation de l'emplacement actuel est le dernier emplacement connu, et si quelqu'un se déplace, il devrait être possible d'utiliser les capteurs d'Android pour produire une meilleure estimation. Le code a un seul paramètre libre Q, exprimé en mètres par seconde, qui décrit la vitesse à laquelle la précision diminue en l'absence de toute nouvelle estimation d'emplacement. Un paramètre Q plus élevé signifie que la précision diminue plus rapidement. Les filtres de Kalman fonctionnent généralement mieux lorsque la précision diminue un peu plus rapidement que ce à quoi on pourrait s'attendre, donc pour me promener avec un téléphone Android, je trouve que Q = 3 mètres par seconde fonctionne bien, même si je marche généralement plus lentement que cela. Mais si vous voyagez dans une voiture rapide, un nombre beaucoup plus important doit évidemment être utilisé.

public class KalmanLatLong {
    private final float MinAccuracy = 1;

    private float Q_metres_per_second;    
    private long TimeStamp_milliseconds;
    private double lat;
    private double lng;
    private float variance; // P matrix.  Negative means object uninitialised.  NB: units irrelevant, as long as same units used throughout

    public KalmanLatLong(float Q_metres_per_second) { this.Q_metres_per_second = Q_metres_per_second; variance = -1; }

    public long get_TimeStamp() { return TimeStamp_milliseconds; }
    public double get_lat() { return lat; }
    public double get_lng() { return lng; }
    public float get_accuracy() { return (float)Math.sqrt(variance); }

    public void SetState(double lat, double lng, float accuracy, long TimeStamp_milliseconds) {
        this.lat=lat; this.lng=lng; variance = accuracy * accuracy; this.TimeStamp_milliseconds=TimeStamp_milliseconds;
    }

    /// <summary>
    /// Kalman filter processing for lattitude and longitude
    /// </summary>
    /// <param name="lat_measurement_degrees">new measurement of lattidude</param>
    /// <param name="lng_measurement">new measurement of longitude</param>
    /// <param name="accuracy">measurement of 1 standard deviation error in metres</param>
    /// <param name="TimeStamp_milliseconds">time of measurement</param>
    /// <returns>new state</returns>
    public void Process(double lat_measurement, double lng_measurement, float accuracy, long TimeStamp_milliseconds) {
        if (accuracy < MinAccuracy) accuracy = MinAccuracy;
        if (variance < 0) {
            // if variance < 0, object is unitialised, so initialise with current values
            this.TimeStamp_milliseconds = TimeStamp_milliseconds;
            lat=lat_measurement; lng = lng_measurement; variance = accuracy*accuracy; 
        } else {
            // else apply Kalman filter methodology

            long TimeInc_milliseconds = TimeStamp_milliseconds - this.TimeStamp_milliseconds;
            if (TimeInc_milliseconds > 0) {
                // time has moved on, so the uncertainty in the current position increases
                variance += TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second / 1000;
                this.TimeStamp_milliseconds = TimeStamp_milliseconds;
                // TO DO: USE VELOCITY INFORMATION HERE TO GET A BETTER ESTIMATE OF CURRENT POSITION
            }

            // Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance)
            // NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng
            float K = variance / (variance + accuracy * accuracy);
            // apply K
            lat += K * (lat_measurement - lat);
            lng += K * (lng_measurement - lng);
            // new Covarariance  matrix is (IdentityMatrix - K) * Covarariance 
            variance = (1 - K) * variance;
        }
    }
}
Stochastiquement
la source
1
Le calcul de la variance ne devrait-il pas être: variance + = TimeInc_milliseconds * TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second / 1000000
Horacio
4
@Horacio, je sais pourquoi tu penses ça, mais non! Mathématiquement, l'incertitude est ici modélisée par un processus de Wiener (voir en.wikipedia.org/wiki/Wiener_process ) et avec un processus de Wiener la variance croît linéairement avec le temps. La variable Q_metres_per_secondcorrespond à la variable sigmade la section "Processus associés" de cet article de Wikipédia. Q_metres_per_secondest un écart type et il est mesuré en mètres, donc les mètres et non les mètres / secondes sont ses unités. Il correspond à l'écart type de la distribution après 1 seconde.
Stochastiquement
3
J'ai essayé cette approche et le code, mais cela a fini par raccourcir trop la distance totale. Rendu trop imprécis.
Andreas Rudolph
1
@ user2999943 oui, utilisez le code pour traiter les coordonnées que vous obtenez de onLocationChanged ().
Stochastiquement le
2
@Koray si vous ne disposez pas d'informations sur la précision, vous ne pouvez pas utiliser de filtre Kalman. C'est tout à fait fondamental pour ce que le filtre de Kalman essaie de faire.
Stochastiquement
75

Ce que vous recherchez s'appelle un filtre de Kalman . Il est fréquemment utilisé pour lisser les données de navigation . Ce n'est pas nécessairement anodin, et vous pouvez faire beaucoup de réglages, mais c'est une approche très standard et fonctionne bien. Il existe une bibliothèque KFilter disponible qui est une implémentation C ++.

Ma prochaine solution de rechange serait l' ajustement des moindres carrés . Un filtre de Kalman lissera les données en tenant compte des vitesses, alors qu'une approche d'ajustement des moindres carrés utilisera simplement les informations de position. Pourtant, il est nettement plus simple à mettre en œuvre et à comprendre. Il semble que la bibliothèque scientifique GNU puisse en avoir une implémentation.

Chris Arguin
la source
1
Merci Chris. Oui, j'ai lu sur Kalman en faisant des recherches, mais c'est certainement un peu au-delà de mes connaissances en mathématiques. Connaissez-vous un exemple de code facile à lire (et à comprendre!), Ou mieux encore, une implémentation disponible? (C / C ++ / Java)
Al.
1
@Al Malheureusement, ma seule exposition avec les filtres Kalman est le travail, donc j'ai un code merveilleusement élégant que je ne peux pas vous montrer.
Chris Arguin
Pas de problème :-) J'ai essayé de chercher mais pour une raison quelconque, il semble que ce truc de Kalman soit de la magie noire. Beaucoup de pages de théorie, mais peu ou pas de code. Merci d'essayer les autres méthodes.
Al.
2
kalman.sourceforge.net/index.php voici l'implémentation C ++ du filtre Kalman.
Rostyslav Druzhchenko
1
@ChrisArguin Vous êtes les bienvenus. Faites-moi savoir si le résultat est bon s'il vous plaît.
Rostyslav Druzhchenko
11

Cela pourrait arriver un peu tard ...

J'ai écrit ce KalmanLocationManager pour Android, qui englobe les deux fournisseurs de localisation les plus courants, le réseau et le GPS, kalman-filtre les données et fournit des mises à jour à un LocationListener(comme les deux «vrais» fournisseurs).

Je l'utilise principalement pour "interpoler" entre les lectures - pour recevoir des mises à jour (prédictions de position) toutes les 100 millis par exemple (au lieu de la fréquence GPS maximale d'une seconde), ce qui me donne une meilleure fréquence d'images lors de l'animation de ma position.

En fait, il utilise trois filtres kalman, activés pour chaque dimension: latitude, longitude et altitude. Ils sont indépendants, de toute façon.

Cela rend le calcul matriciel beaucoup plus facile: au lieu d'utiliser une matrice de transition d'état 6x6, j'utilise 3 matrices 2x2 différentes. En fait, dans le code, je n'utilise pas du tout de matrices. Résolu toutes les équations et toutes les valeurs sont des primitives (double).

Le code source fonctionne et il y a une activité de démonstration. Désolé pour le manque de javadoc à certains endroits, je vais me rattraper.

Villoren
la source
1
J'ai essayé d'utiliser votre code lib, j'ai obtenu des résultats indésirables, je ne suis pas sûr si je fais quelque chose de mal ... (Ci-dessous l'url de l'image, le bleu est le chemin des emplacements filtrés, l'orange les emplacements bruts) app.box. com / s / w3uvaz007glp2utvgznmh8vlggvaiifk
umesh
Les pics que vous voyez `` croître '' par rapport à la moyenne (ligne orange) ressemblent à des mises à jour du fournisseur de réseau. Pouvez-vous essayer de tracer les mises à jour brutes du réseau et du GPS? Peut-être que vous seriez mieux sans mise à jour du réseau, en fonction de ce que vous essayez de réaliser. Btw, d'où proviennent ces mises à jour orange brutes?
villoren
1
les points orange proviennent du fournisseur de GPS et les bleus de Kalman, j'ai tracé les journaux sur la carte
umesh
Pourriez-vous m'envoyer ces données dans un format texte? Chaque mise à jour d'emplacement a le champ Location.getProvider () défini. Un seul fichier avec tous les Location.toString ().
villoren le
9

Vous ne devez pas calculer la vitesse à partir du changement de position par heure. Le GPS peut avoir des positions inexactes, mais il a une vitesse précise (supérieure à 5 km / h). Utilisez donc la vitesse du tampon de localisation GPS. Et de plus, vous ne devriez pas faire cela avec bien sûr, même si cela fonctionne la plupart du temps.

Les positions GPS, telles que livrées, sont déjà filtrées Kalman, vous ne pouvez probablement pas vous améliorer, en post-traitement généralement vous n'avez pas les mêmes informations que la puce GPS.

Vous pouvez le lisser, mais cela introduit également des erreurs.

Assurez-vous simplement que vous supprimez les positions lorsque l'appareil est immobile, cela supprime les positions de saut, que certains appareils / configurations ne suppriment pas.

AlexWien
la source
5
Pourriez-vous fournir quelques références à ce sujet s'il vous plaît?
ivyleavedtoadflax
1
Il y a beaucoup d'informations et beaucoup d'expérience professionnelle dans ces phrases, pour quelle phrase voulez-vous exactement une référence? pour la vitesse: recherchez l'effet doppler et le GPS. Kalman interne? Il s'agit de connaissances de base sur le GPS, chaque article ou livre décrivant le fonctionnement interne d'une puce GPS. smootig-errors: toujours le lissage introduit des erreurs. rester immobile? Essaye le.
AlexWien
2
Le fait de «sauter» à l'arrêt n'est pas la seule source d'erreur. Il y a aussi des réflexions de signaux (par exemple des montagnes) où la position saute. Mes puces GPS (par exemple Garmin Dakota 20, SonyEricsson Neo) n'ont pas filtré cela ... Et ce qui est vraiment une blague, c'est la valeur d'altitude des signaux GPS lorsqu'ils ne sont pas combinés avec la pression barométrique. Ces valeurs ne sont pas filtrées ou je ne veux pas voir les valeurs non filtrées.
hgoebl
1
@AlexWien GPS calcule la distance d'un point à la fois à une tolérance vous donnant une sphère d'épaisseur, une coque centrée autour d'un satellite. Vous êtes quelque part dans ce volume shell. L'intersection de trois de ces volumes de coque vous donne un volume de position, dont le centroïde est votre position calculée. Si vous avez un ensemble de positions signalées et que vous savez que le capteur est au repos, le calcul du centroïde coupe effectivement beaucoup plus de coques, améliorant ainsi la précision. L'erreur dans ce cas est réduite .
Peter Wone le
6
"Les positions GPS, telles que livrées, sont déjà filtrées par Kalman, vous ne pouvez probablement pas vous améliorer". Si vous pouvez pointer vers une source qui le confirme pour les smartphones modernes (par exemple), ce serait très utile. Je n'en vois pas la preuve moi-même. Même le simple filtrage de Kalman des emplacements bruts d'un appareil suggère fortement que ce n'est pas vrai. Les emplacements bruts dansent de manière erratique, tandis que les emplacements filtrés sont le plus souvent proches de l'emplacement réel (connu).
sobri
6

J'utilise habituellement les accéléromètres. Un changement soudain de position sur une courte période implique une forte accélération. Si cela n'est pas reflété dans la télémétrie de l'accéléromètre, c'est presque certainement dû à un changement dans les "trois meilleurs" satellites utilisés pour calculer la position (que j'appelle la téléportation GPS).

Lorsqu'un actif est au repos et sautille en raison de la téléportation GPS, si vous calculez progressivement le centre de gravité, vous intersectez effectivement un ensemble de coques de plus en plus grand, améliorant ainsi la précision.

Pour ce faire lorsque l'actif n'est pas au repos, vous devez estimer sa prochaine position et son orientation probables en fonction de la vitesse, du cap et des données d'accélération linéaire et rotationnelle (si vous avez des gyroscopes). C'est plus ou moins ce que fait le fameux filtre K. Vous pouvez obtenir le tout en matériel pour environ 150 $ sur un AHRS contenant tout sauf le module GPS, et avec une prise pour en connecter un. Il a son propre processeur et le filtrage Kalman à bord; les résultats sont stables et assez bons. Le guidage inertiel est très résistant à la gigue mais dérive avec le temps. Le GPS est sujet à la gigue mais ne dérive pas avec le temps, ils ont pratiquement été faits pour se compenser.

Peter Wone
la source
4

Une méthode qui utilise moins de mathématiques / théorie consiste à échantillonner 2, 5, 7 ou 10 points de données à la fois et à déterminer ceux qui sont des valeurs aberrantes. Une mesure moins précise d'une valeur aberrante qu'un filtre de Kalman consiste à utiliser l' algorithme suivant pour prendre toutes les distances par paire entre les points et rejeter celle qui est la plus éloignée des autres. En général, ces valeurs sont remplacées par la valeur la plus proche de la valeur aberrante que vous remplacez

Par exemple

Lissage à cinq points d'échantillonnage A, B, C, D, E

ATOTAL = SOMME des distances AB AC AD AE

BTOTAL = SOMME des distances AB BC BD BE

CTOTAL = SOMME des distances AC BC CD CE

DTOTAL = SOMME des distances DA DB DC DE

ETOTAL = SOMME des distances EA EB EC DE

Si BTOTAL est le plus grand, vous remplaceriez le point B par D si BD = min {AB, BC, BD, BE}

Ce lissage détermine les valeurs aberrantes et peut être augmenté en utilisant le point médian de BD au lieu du point D pour lisser la ligne de position. Votre kilométrage peut varier et des solutions plus rigoureuses mathématiquement existent.

ojblass
la source
Merci, je vais essayer aussi. Notez que je souhaite lisser la position actuelle, car c'est celle qui est affichée et celle utilisée pour récupérer certaines données. Je ne suis pas intéressé par les points passés. Mon idée originale utilisait des moyens pondérés, mais je dois encore voir ce qui est le mieux.
Al.
1
Al, cela semble être une forme de moyenne pondérée. Vous devrez utiliser des points "passés" si vous souhaitez effectuer un lissage, car le système doit avoir plus que la position actuelle afin de savoir où lisser également. Si votre GPS prend des points de données une fois par seconde et que votre utilisateur regarde l'écran une fois toutes les cinq secondes, vous pouvez utiliser 5 points de données sans qu'il s'en aperçoive! Une moyenne mobile ne serait également retardée que d'un dp.
Karl
4

En ce qui concerne l'ajustement des moindres carrés, voici quelques autres choses à expérimenter:

  1. Ce n'est pas parce qu'il est ajusté aux moindres carrés qu'il doit être linéaire. Vous pouvez ajuster une courbe quadratique aux données par les moindres carrés, cela conviendrait alors à un scénario dans lequel l'utilisateur accélère. (Notez que par ajustement des moindres carrés, je veux dire utiliser les coordonnées comme variable dépendante et le temps comme variable indépendante.)

  2. Vous pouvez également essayer de pondérer les points de données en fonction de la précision rapportée. Lorsque la précision est faible, ces points de données sont inférieurs.

  3. Une autre chose que vous voudrez peut-être essayer est plutôt que d'afficher un seul point, si la précision est faible, affichez un cercle ou quelque chose indiquant la plage dans laquelle l'utilisateur pourrait être basé sur la précision rapportée. (C'est ce que fait l'application Google Maps intégrée à l'iPhone.)

Alex319
la source
3

Vous pouvez également utiliser une spline. Introduisez les valeurs que vous avez et interpolez les points entre vos points connus. Lier cela avec un ajustement des moindres carrés, une moyenne mobile ou un filtre de kalman (comme mentionné dans d'autres réponses) vous donne la possibilité de calculer les points entre vos points "connus".

Être capable d'interpoler les valeurs entre vos connus vous donne une belle transition en douceur et une / raisonnable / approximation de quelles données seraient présentes si vous aviez une plus haute fidélité. http://en.wikipedia.org/wiki/Spline_interpolation

Différentes splines ont des caractéristiques différentes. Ceux que j'ai vu les plus couramment utilisés sont les splines Akima et Cubic.

Un autre algorithme à considérer est l'algorithme de simplification de ligne Ramer-Douglas-Peucker, il est assez couramment utilisé dans la simplification des données GPS. ( http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm )

Aidos
la source
3

Pour en revenir aux filtres Kalman ... J'ai trouvé une implémentation C pour un filtre Kalman pour les données GPS ici: http://github.com/lacker/ikalman Je ne l'ai pas encore essayé, mais cela semble prometteur.

KaratéSnowMachine
la source
0

Mappé sur CoffeeScript si quelqu'un est intéressé. ** modifier -> désolé d'utiliser backbone aussi, mais vous voyez l'idée.

Modifié légèrement pour accepter une balise avec des attributs

{latitude: item.lat, longitude: item.lng, date: nouvelle Date (item.effective_at), précision: item.gps_accuracy}

MIN_ACCURACY = 1

# mapped from http://stackoverflow.com/questions/1134579/smooth-gps-data

class v.Map.BeaconFilter

  constructor: ->
    _.extend(this, Backbone.Events)

  process: (decay,beacon) ->

    accuracy     = Math.max beacon.accuracy, MIN_ACCURACY

    unless @variance?
      # if variance nil, inititalise some values
      @variance     = accuracy * accuracy
      @timestamp_ms = beacon.date.getTime();
      @lat          = beacon.latitude
      @lng          = beacon.longitude

    else

      @timestamp_ms = beacon.date.getTime() - @timestamp_ms

      if @timestamp_ms > 0
        # time has moved on, so the uncertainty in the current position increases
        @variance += @timestamp_ms * decay * decay / 1000;
        @timestamp_ms = beacon.date.getTime();

      # Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance)
      # NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng
      _k  = @variance / (@variance + accuracy * accuracy)
      @lat = _k * (beacon.latitude  - @lat)
      @lng = _k * (beacon.longitude - @lng)

      @variance = (1 - _k) * @variance

    [@lat,@lng]
lucygenik
la source
J'ai essayé de modifier cela, mais il y a une faute de frappe dans les dernières lignes où @latet @lngsont définis. Devrait être +=plutôt que=
jdixon04
0

J'ai transformé le code Java de @Stochastically en Kotlin

class KalmanLatLong
{
    private val MinAccuracy: Float = 1f

    private var Q_metres_per_second: Float = 0f
    private var TimeStamp_milliseconds: Long = 0
    private var lat: Double = 0.toDouble()
    private var lng: Double = 0.toDouble()
    private var variance: Float =
        0.toFloat() // P matrix.  Negative means object uninitialised.  NB: units irrelevant, as long as same units used throughout

    fun KalmanLatLong(Q_metres_per_second: Float)
    {
        this.Q_metres_per_second = Q_metres_per_second
        variance = -1f
    }

    fun get_TimeStamp(): Long { return TimeStamp_milliseconds }
    fun get_lat(): Double { return lat }
    fun get_lng(): Double { return lng }
    fun get_accuracy(): Float { return Math.sqrt(variance.toDouble()).toFloat() }

    fun SetState(lat: Double, lng: Double, accuracy: Float, TimeStamp_milliseconds: Long)
    {
        this.lat = lat
        this.lng = lng
        variance = accuracy * accuracy
        this.TimeStamp_milliseconds = TimeStamp_milliseconds
    }

    /// <summary>
    /// Kalman filter processing for lattitude and longitude
    /// /programming/1134579/smooth-gps-data/15657798#15657798
    /// </summary>
    /// <param name="lat_measurement_degrees">new measurement of lattidude</param>
    /// <param name="lng_measurement">new measurement of longitude</param>
    /// <param name="accuracy">measurement of 1 standard deviation error in metres</param>
    /// <param name="TimeStamp_milliseconds">time of measurement</param>
    /// <returns>new state</returns>
    fun Process(lat_measurement: Double, lng_measurement: Double, accuracy: Float, TimeStamp_milliseconds: Long)
    {
        var accuracy = accuracy
        if (accuracy < MinAccuracy) accuracy = MinAccuracy

        if (variance < 0)
        {
            // if variance < 0, object is unitialised, so initialise with current values
            this.TimeStamp_milliseconds = TimeStamp_milliseconds
            lat = lat_measurement
            lng = lng_measurement
            variance = accuracy * accuracy
        }
        else
        {
            // else apply Kalman filter methodology

            val TimeInc_milliseconds = TimeStamp_milliseconds - this.TimeStamp_milliseconds

            if (TimeInc_milliseconds > 0)
            {
                // time has moved on, so the uncertainty in the current position increases
                variance += TimeInc_milliseconds.toFloat() * Q_metres_per_second * Q_metres_per_second / 1000
                this.TimeStamp_milliseconds = TimeStamp_milliseconds
                // TO DO: USE VELOCITY INFORMATION HERE TO GET A BETTER ESTIMATE OF CURRENT POSITION
            }

            // Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance)
            // NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng
            val K = variance / (variance + accuracy * accuracy)
            // apply K
            lat += K * (lat_measurement - lat)
            lng += K * (lng_measurement - lng)
            // new Covarariance  matrix is (IdentityMatrix - K) * Covarariance
            variance = (1 - K) * variance
        }
    }
}
inspire_coding
la source
0

Voici une implémentation Javascript de l'implémentation Java de @ Stochastically pour tous ceux qui en ont besoin:

class GPSKalmanFilter {
  constructor (decay = 3) {
    this.decay = decay
    this.variance = -1
    this.minAccuracy = 1
  }

  process (lat, lng, accuracy, timestampInMs) {
    if (accuracy < this.minAccuracy) accuracy = this.minAccuracy

    if (this.variance < 0) {
      this.timestampInMs = timestampInMs
      this.lat = lat
      this.lng = lng
      this.variance = accuracy * accuracy
    } else {
      const timeIncMs = timestampInMs - this.timestampInMs

      if (timeIncMs > 0) {
        this.variance += (timeIncMs * this.decay * this.decay) / 1000
        this.timestampInMs = timestampInMs
      }

      const _k = this.variance / (this.variance + (accuracy * accuracy))
      this.lat += _k * (lat - this.lat)
      this.lng += _k * (lng - this.lng)

      this.variance = (1 - _k) * this.variance
    }

    return [this.lng, this.lat]
  }
}

Exemple d'utilisation:

   const kalmanFilter = new GPSKalmanFilter()
   const updatedCoords = []

    for (let index = 0; index < coords.length; index++) {
      const { lat, lng, accuracy, timestampInMs } = coords[index]
      updatedCoords[index] = kalmanFilter.process(lat, lng, accuracy, timestampInMs)
    }
jdixon04
la source