부드러운 GPS 데이터


145

GPS 데이터로 작업하고 있으며 매 초마다 값을 가져오고지도에 현재 위치를 표시합니다. 문제는 때때로 (특히 정확도가 낮을 ​​때) 값이 많이 달라져 현재 위치가지도의 먼 지점 사이에서 "점프"하도록하는 것입니다.

이것을 피할 수있는 쉬운 방법이 궁금합니다. 첫 번째 아이디어로 특정 임계 값을 초과하여 정확하게 값을 버리는 것에 대해 생각했지만 더 좋은 방법이 있다고 생각합니다. 프로그램이 이것을 수행하는 일반적인 방법은 무엇입니까?


고속 및 슬로프와 같은 관련 (유도) 값을 계산하려고 할 때 "GPS 노이즈"의 나쁜 영향을 느낍니다. 이는 높은 샘플링 속도 트랙 로그 (시간이 정수 [1 초] 해상도이므로)에 대해 매우 불 연속적입니다.
heltonbiker

4
(또한, 주요 도로를 탐색하는 경우 "올 바르고 정확한"로드맵 데이터 세트가있는 경우 "도로에 스냅"알고리즘을 사용할 수 있습니다.)
heltonbiker

최고의 정확성을 위해이 문제에 직면하고 있습니다.
ViruMax

답변:


80

이 상황에 정확히 사용할 수있는 간단한 칼만 필터가 있습니다. Android 기기에서 수행 한 작업에서 비롯된 것입니다.

일반적인 칼만 필터 이론은 공분산 행렬로 표시되는 추정치의 정확도와 함께 벡터에 대한 추정치에 관한 것입니다. 그러나 Android 기기의 위치를 ​​추정하기 위해 일반적인 이론은 매우 간단한 경우로 줄어 듭니다. Android 위치 제공 업체는 위치를 위도와 경도로 미터 단위로 측정 한 단일 숫자로 지정된 정확도와 함께 제공합니다. 즉, 칼만 필터의 위치가 두 개의 숫자로 측정 되더라도 공분산 행렬 대신 칼만 필터의 정확도를 단일 숫자로 측정 할 수 있습니다. 또한 위도, 경도 및 미터가 서로 다른 모든 단위라는 사실은 무시할 수 있습니다. 스케일링 계수를 Kalman 필터에 넣어 모두 동일한 단위로 변환하면,

코드는 현재 위치의 최고 추정치가 마지막으로 알려진 위치라고 가정하기 때문에 개선 될 수 있으며, 누군가가 이동하는 경우 Android 센서를 사용하여 더 나은 추정치를 생성 할 수 있어야합니다. 이 코드에는 초당 미터 단위로 표현되는 단일 자유 매개 변수 Q가 있으며, 새로운 위치 추정치가 없을 때 정확도가 얼마나 빨리 저하되는지를 설명합니다. Q 파라미터가 높을수록 정확도가 더 빨리 감쇠합니다. 칼만 필터는 일반적으로 정확도가 예상보다 약간 빨리 쇠퇴 할 때 더 잘 작동하므로 Android 전화로 걸을 때 일반적으로 그 속도보다 느리게 걷는 경우에도 초당 Q = 3 미터가 잘 작동한다는 것을 알았습니다. 그러나 빠른 자동차로 여행하는 경우 훨씬 더 많은 수를 사용해야합니다.

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;
        }
    }
}

1
분산 계산해야하지 : 분산 + = TimeInc_milliseconds * TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second / 1000000
오라

4
@Horacio, 나는 당신이 왜 그렇게 생각하는지 안다! 수학적으로, 여기서 불확실성은 Wiener 프로세스 ( en.wikipedia.org/wiki/Wiener_process 참조 )와 Wiener 프로세스에서 시간에 따라 선형으로 증가합니다. 변수는 Q_metres_per_second해당 sigmaWikipedia 기사의 "관련 프로세스"섹션 에있는 변수 에 해당합니다 . Q_metres_per_second표준 편차이며 미터 단위로 측정되므로 미터 / 초가 아닌 미터가 단위입니다. 1 초가 경과 한 후 분포의 표준 편차에 해당합니다.
Stochastically

3
이 접근 방식과 코드를 시도했지만 총 거리가 너무 짧아졌습니다. 너무 부정확하게 만들었습니다.
Andreas Rudolph

1
@ user2999943 예, 코드를 사용하여 onLocationChanged ()에서 얻은 좌표를 처리하십시오.
Stochastically

2
@Koray 정확도 정보가 없으면 Kalman 필터를 사용할 수 없습니다. Kalman 필터가 수행하려는 작업의 핵심입니다.
Stochastically

75

찾고있는 것을 Kalman Filter 라고합니다 . 탐색 데이터매끄럽게 하는 데 자주 사용됩니다 . 반드시 사소한 것은 아니며 많은 조정이 가능하지만 매우 표준적인 접근 방식이며 잘 작동합니다. 있습니다 KFilter 라이브러리 는 C ++ 구현 가능합니다.

내 다음 폴백은 최소 제곱에 적합 합니다. 칼만 필터는 속도를 고려하여 데이터를 부드럽게하는 반면 최소 자승법은 위치 정보 만 사용합니다. 그럼에도 불구하고 구현하고 이해하는 것이 훨씬 간단합니다. GNU Scientific Library가 이것을 구현 한 것으로 보입니다 .


1
고마워 크리스. 네, 검색하면서 칼만에 대해 읽었지만 수학 지식을 약간 넘어서는 것입니다. 쉽게 읽을 수 있고 이해하기 쉬운 샘플 코드를 알고 있습니까? 아니면 더 나은 구현 방법이 있습니까? (C / C ++ / Java)
Al.

1
@Al 불행히도 Kalman 필터에 대한 유일한 노출은 작업을 통한 것이므로 보여줄 수없는 훌륭하고 우아한 코드가 있습니다.
Chris Arguin

문제 없습니다 :-) 찾고 있었지만 어떤 이유로 든이 칼만은 흑 마법 인 것 같습니다. 이론 페이지는 많지만 코드는 거의 없습니다.
Al.

2
kalman.sourceforge.net/index.php 는 Kalman 필터의 C ++ 구현입니다.
Rostyslav Druzhchenko

1
@ChrisArguin 천만에요. 결과가 좋은지 알려주세요.
Rostyslav Druzhchenko

11

조금 늦을 수도 있습니다 ...

필자는 Android와 KalmanLocationManager 를 작성 했는데 ,이 두 곳은 가장 일반적인 위치 제공 업체 인 네트워크와 GPS를 감싸고 데이터를 필터링하고 LocationListener( '실제'제공 업체와 같은) 업데이트를 제공합니다 .

나는 주로 판독 사이에 "보간"하기 위해 사용합니다-예를 들어 100 밀리 초마다 업데이트 (위치 예측)를 수신합니다 (예 : 최대 gps 속도 대신 1 초). 내 위치를 애니메이션 할 때 더 나은 프레임 속도를 제공합니다.

실제로 각 차원마다 위도, 경도 및 고도의 세 가지 칼만 필터를 사용합니다. 어쨌든 그들은 독립적입니다.

이것은 6x6 상태 전이 행렬 하나를 사용하는 대신 3 개의 다른 2x2 행렬을 사용하여 행렬 수학을 훨씬 쉽게 만듭니다. 실제로 코드에서는 행렬을 전혀 사용하지 않습니다. 모든 방정식을 풀고 모든 값은 프리미티브 (이중)입니다.

소스 코드가 작동하고 있으며 데모 활동이 있습니다. 어떤 곳에서는 javadoc이 없어서 유감입니다.


1
나는 당신의 lib 코드를 사용하려고했는데, 원하지 않는 결과를 얻었습니다. 내가 잘못하고 있는지 확실하지 않습니다 ... (이미지 URL 아래에 파란색이 필터링 된 위치의 경로, 주황색은 원시 위치입니다) app.box. com / s / w3uvaz007glp2utvgznmh8vlggvaiifk
umesh

평균 (주황색 선)에서 '성장'하는 스파이크는 네트워크 공급자 업데이트처럼 보입니다. 원시 네트워크 및 GPS 업데이트를 모두 플로팅 할 수 있습니까? 달성하려는 목표에 따라 네트워크 업데이트가없는 것이 더 나을 것입니다. Btw, 원시 오렌지 업데이트는 어디서 구할 수 있습니까?
villoren

1
주황색 포인트는 GPS 제공 업체에서, 파란색은 칼만 (Kalman)에서,지도에 로그를 표시했습니다
umesh

그 데이터를 텍스트 형식으로 보내 주시겠습니까? 각 위치 업데이트에는 Location.getProvider () 필드가 설정되어 있습니다. 모든 Location.toString ()이있는 하나의 파일
villoren

9

시간당 위치 변경으로 속도를 계산해서는 안됩니다. GPS의 위치가 정확하지 않을 수 있지만 정확한 속도 (5km / h 이상)가 있습니다. 따라서 GPS 위치 스탬프의 속도를 사용하십시오. 또한 대부분의 경우 작동하지만 물론 그렇게해서는 안됩니다.

배송 된 GPS 위치는 이미 Kalman으로 필터링되었으므로 후 처리 과정에서 일반적으로 GPS 칩과 동일한 정보가없는 경우 개선 할 수 없습니다.

부드럽게 할 수 있지만 오류가 발생합니다.

장치가 정지 상태 일 때 위치를 제거하고 점프 위치를 제거하고 일부 장치 / 구성이 제거되지 않도록하십시오.


5
이에 대한 참고 자료를 제공해 주시겠습니까?
ivyleavedtoadflax

1
그 문장에는 많은 정보와 많은 전문적인 경험이 있습니다. 어떤 문장을 정확하게 참조 하시겠습니까? 속도 : 도플러 효과 및 GPS를 검색합니다. 내부 칼만? 이것은 기본 GPS 지식으로, GPS 칩 내부 작동 방식을 설명하는 모든 문서 또는 서적입니다. smootig-errors : 항상 스무딩 오류가 발생합니다. 가만히 서있다? 사용해보십시오.
AlexWien

2
여전히 서있을 때 "약탈"이 유일한 오류 원인은 아닙니다. 위치가 이동하는 신호 반사 (예 : 산)가 있습니다. 내 GPS 칩 (예 : Garmin Dakota 20, SonyEricsson Neo)이이를 걸러 내지 못했습니다 ... 실제로 농담은 기압과 결합되지 않은 GPS 신호의 고도 값입니다. 이 값은 필터링되지 않았거나 필터링되지 않은 값을보고 싶지 않습니다.
hgoebl

1
@AlexWien GPS는 한 번에 한 지점에서 공차까지의 거리를 계산 하여 위성을 중심으로 한 껍질을 가진 두께의 구를 제공합니다 . 이 쉘 볼륨의 어딘가에 있습니다. 이 셸 볼륨 중 3 개의 교차점에 위치 볼륨이 표시되는데, 그 중심은 계산 된 위치입니다. 보고 된 위치 세트가 있고 센서가 정지 상태임을 알고 있으면 중심을 계산하면 훨씬 더 많은 쉘을 효과적으로 교차시켜 정밀도가 향상됩니다. 이 경우 오류가 줄어 듭니다 .
Peter Wone 2012

6
"제공된 GPS 위치는 이미 칼만 필터링되었으므로 개선 할 수 없습니다." 예를 들어 최신 스마트 폰에서이를 확인하는 소스를 가리킬 수 있다면 매우 유용합니다. 나 자신의 증거를 볼 수 없습니다. 장치의 원시 위치에 대한 간단한 칼만 필터링조차도 장치가 사실이 아니라는 것을 강력하게 암시합니다. 필터링되지 않은 위치는 대부분 실제 (알려진) 위치에 가깝습니다.
sobri

6

나는 보통 가속도계를 사용합니다. 단기간에 갑작스런 위치 변화는 높은 가속도를 의미합니다. 이것이 가속도계 원격 측정에 반영되지 않으면 위치를 계산하는 데 사용되는 "최고의 3 개"위성이 변경 되었기 때문일 것입니다 (GPS 텔레 포팅이라고 함).

GPS 텔레 포팅으로 인해 자산이 정지되고 도약 할 때 중심을 점진적으로 계산하면 더 큰 쉘 세트를 효과적으로 교차시켜 정밀도를 향상시킬 수 있습니다.

자산이 정지되어 있지 않을 때이를 수행하려면 속도, 방향 및 선형 및 회전 (자이로가있는 경우) 가속도 데이터를 기반으로 다음 위치와 방향을 추정해야합니다. 이것은 유명한 K 필터의 기능입니다. GPS 모듈을 제외한 모든 것을 포함하는 AHRS와 하나를 연결하는 잭으로 하드웨어에서 약 150 달러에 구입할 수 있습니다. 자체 CPU 및 Kalman 필터링이 내장되어 있습니다. 결과는 안정적이고 꽤 좋습니다. 관성 가이던스는 지터에 대한 내성이 강하지 만 시간이지나면서 표류합니다. GPS는 지터가 발생하기 쉽지만 시간이 흐르면서 표류하지는 않으며 실제로 서로를 보상하기 위해 만들어졌습니다.


4

더 적은 수학 / 이론을 사용하는 한 가지 방법은 한 번에 2, 5, 7, 10 개의 데이터 포인트를 샘플링하고 이상치 인 것을 결정하는 것입니다. 칼만 필터보다 특이점을 덜 정확하게 측정하려면 다음 알고리즘 을 사용하여 점 사이의 모든 쌍의 현명한 거리를 취하고 다른 것보다 가장 먼 거리를 버리십시오. 일반적으로 이러한 값은 대체하려는 외부 값에 가장 가까운 값으로 바뀝니다.

예를 들어

5 개의 샘플 포인트 A, B, C, D, E에서 스무딩

ATOTAL = 거리의 합 AB AC AD AE

BTOTAL = 거리의 합 AB BC BD BE

CTOTAL = 거리의 합 AC BC CD CE

DTOTAL = 거리의 합 DA DB DC DE

ETOTAL = 거리의 합 EA EB EC DE

BTOTAL이 가장 큰 경우 BD = min {AB, BC, BD, BE} 인 경우 B 지점을 D로 바꿉니다.

이 평활화는 특이 치를 결정하며 점 D 대신 BD의 중간 점을 사용하여 위치 선을 평활화하여 보강 할 수 있습니다. 마일리지는 다를 수 있으며보다 수학적으로 엄격한 솔루션이 존재합니다.


고마워요. 현재 위치가 표시되고 일부는 데이터를 검색하는 데 사용되므로 현재 위치를 부드럽게하고 싶습니다. 나는 과거 포인트에 관심이 없습니다. 내 원래 아이디어는 가중 수단을 사용했지만 여전히 가장 좋은 것을보아야합니다.
Al.

1
Al, 이것은 가중 수단의 한 형태 인 것 같습니다. 스무딩을 수행하려면 스무딩을 수행하려면 시스템이 현재 위치보다 더 많은 위치를 가져야하므로 스무딩을 수행하려면 "과거"포인트를 사용해야합니다. GPS가 초당 1 회 데이터 포인트를 가져오고 사용자가 5 초마다 한 번씩 화면을 보는 경우, 알리지 않고 5 개의 데이터 포인트를 사용할 수 있습니다! 이동 평균은 1dp만큼만 지연됩니다.
Karl

4

최소 자승법에 따라 실험해야 할 몇 가지 사항이 있습니다.

  1. 최소 제곱 맞춤이라고해서 반드시 선형이어야한다는 의미는 아닙니다. 2 차 곡선을 데이터에 최소 제곱합 할 수 있으며, 이는 사용자가 가속하는 시나리오에 적합합니다. (적어도 제곱에 적합하다는 것은 좌표를 종속 변수로 사용하고 시간을 독립 변수로 사용한다는 것을 의미합니다.)

  2. 보고 된 정확도를 기준으로 데이터 포인트에 가중치를 부여 할 수도 있습니다. 정확도가 낮 으면 데이터 포인트가 낮아집니다.

  3. 정확도가 낮은 경우 원 또는 사용자가보고 된 정확도를 기반으로 할 수있는 범위를 나타내는 것이 표시되는 경우 단일 지점을 표시하는 것이 아니라 시도 할 수도 있습니다. (이것은 iPhone의 내장 Google Maps 응용 프로그램의 기능입니다.)


3

스플라인을 사용할 수도 있습니다. 가지고있는 값을 입력하고 알려진 점 사이에 점을 보간하십시오. 이것을 최소 제곱 적합, 이동 평균 또는 칼만 필터 (다른 답변에서 언급 한 바와 같이)와 연결하면 "알려진"점 사이의 점을 계산할 수 있습니다.

알려진 값 사이의 값을 보간 할 수 있으면 충실도가 높으면 어떤 데이터가 존재할지에 대한 부드러운 전환과 / 합리적인 / 근사치를 얻을 수 있습니다. http://en.wikipedia.org/wiki/Spline_interpolation

스플라인마다 특성이 다릅니다. 내가 가장 일반적으로 사용하는 것은 Akima와 Cubic 스플라인입니다.

고려해야 할 또 다른 알고리즘은 Ramer-Douglas-Peucker 라인 단순화 알고리즘이며 GPS 데이터 단순화에 일반적으로 사용됩니다. ( http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm )



0

관심있는 사람이 있으면 CoffeeScript에 매핑됩니다. ** 편집-> 백본을 사용하여 죄송하지만 아이디어를 얻습니다.

아트 리브가있는 비콘을 받도록 약간 수정 됨

{위도 : item.lat, 경도 : item.lng, 날짜 : 새로운 날짜 (item.effective_at), 정확도 : 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]

이 편집하려고했으나 마지막 줄에 오타있다 @lat@lng설정은. 해야 +=보다는=
jdixon04

0

Java 코드를 @Stochastically에서 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
        }
    }
}

0

다음은 @Stochastically의 Java 구현이 필요한 사람을위한 Javascript 구현입니다.

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]
  }
}

사용 예 :

   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)
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.