Dữ liệu GPS mượt mà


145

Tôi đang làm việc với dữ liệu GPS, nhận giá trị mỗi giây và hiển thị vị trí hiện tại trên bản đồ. Vấn đề là đôi khi (đặc biệt khi độ chính xác thấp) các giá trị thay đổi rất nhiều, khiến vị trí hiện tại bị "nhảy" giữa các điểm xa trên bản đồ.

Tôi đã tự hỏi về một số phương pháp đủ dễ dàng để tránh điều này. Là một ý tưởng đầu tiên, tôi nghĩ về việc loại bỏ các giá trị với độ chính xác vượt quá ngưỡng nhất định, nhưng tôi đoán có một số cách khác tốt hơn để làm. Các chương trình thông thường thực hiện điều này là gì?


Tôi cảm thấy những tác động xấu của "nhiễu GPS" khi cố gắng tính các giá trị liên quan (đạo hàm) như tốc độ và độ dốc, rất không liên tục đặc biệt đối với các tracklog tốc độ mẫu cao (vì thời gian có độ phân giải [một giây]).
heltonbiker

4
(ngoài ra, nếu bạn đang điều hướng qua các con đường chính, bạn có thể sử dụng thuật toán "snap to road" với điều kiện bạn có một bộ dữ liệu lộ trình [chính xác, chính xác]. Chỉ cần suy nghĩ)
heltonbiker

Tôi cũng đang đối mặt với vấn đề này để có độ chính xác tốt nhất.
ViruMax

Câu trả lời:


80

Đây là một bộ lọc Kalman đơn giản có thể được sử dụng cho chính xác tình huống này. Nó đến từ một số công việc tôi đã làm trên các thiết bị Android.

Lý thuyết bộ lọc Kalman chung là tất cả về các ước tính cho vectơ, với độ chính xác của các ước tính được biểu thị bằng ma trận hiệp phương sai. Tuy nhiên, để ước tính vị trí trên các thiết bị Android, lý thuyết chung giảm xuống một trường hợp rất đơn giản. Các nhà cung cấp vị trí Android cung cấp vị trí dưới dạng vĩ độ và kinh độ, cùng với độ chính xác được chỉ định là một số duy nhất được đo bằng mét. Điều này có nghĩa là thay vì ma trận hiệp phương sai, độ chính xác trong bộ lọc Kalman có thể được đo bằng một số duy nhất, mặc dù vị trí trong bộ lọc Kalman được đo bằng hai số. Ngoài ra, thực tế là vĩ độ, kinh độ và mét có thể bị bỏ qua một cách hiệu quả, bởi vì nếu bạn đặt các yếu tố tỷ lệ vào bộ lọc Kalman để chuyển đổi tất cả chúng thành cùng một đơn vị,

Mã có thể được cải thiện, vì nó giả định rằng ước tính tốt nhất về vị trí hiện tại là vị trí được biết đến cuối cùng và nếu ai đó đang di chuyển, có thể sử dụng cảm biến của Android để đưa ra ước tính tốt hơn. Mã này có một tham số miễn phí duy nhất Q, được biểu thị bằng mét trên giây, mô tả mức độ chính xác phân rã nhanh chóng khi không có bất kỳ ước tính vị trí mới nào. Tham số Q cao hơn có nghĩa là độ chính xác phân rã nhanh hơn. Các bộ lọc Kalman thường hoạt động tốt hơn khi độ chính xác phân rã nhanh hơn một chút so với mong đợi, vì vậy để đi bộ với điện thoại Android tôi thấy rằng Q = 3 mét mỗi giây hoạt động tốt, mặc dù tôi thường đi chậm hơn thế. Nhưng nếu đi trong một chiếc xe nhanh, một số lượng lớn hơn nhiều rõ ràng nên được sử dụng.

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
Không nên tính toán phương sai là: variance + = TimeInc_milliseconds * TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second / 1000000
Horacio

4
@Horacio, tôi biết tại sao bạn nghĩ vậy, nhưng không! Về mặt toán học, sự không chắc chắn ở đây đang được mô hình hóa bằng quy trình Wiener (xem en.wikipedia.org/wiki/Wiener_ process ) và với quy trình Wiener, phương sai tăng theo tuyến tính theo thời gian. Biến Q_metres_per_secondtương ứng với biến sigmatrong phần "Các quy trình liên quan" trong bài viết Wikipedia đó. Q_metres_per_secondlà độ lệch chuẩn và được đo bằng mét, vì vậy mét và không phải mét / giây là đơn vị của nó. Nó tương ứng với độ lệch chuẩn của phân phối sau 1 giây đã trôi qua.
ngẫu nhiên

3
Tôi đã thử cách tiếp cận này và mã, nhưng cuối cùng nó rút ngắn tổng khoảng cách quá nhiều. Làm cho nó quá thiếu chính xác.
Andreas Rudolph

1
@ user2999943 có, sử dụng mã để xử lý tọa độ mà bạn nhận được từ onLocationChanged ().
Stochastically

2
@Koray nếu bạn không có thông tin chính xác thì bạn không thể sử dụng bộ lọc Kalman. Nó hoàn toàn cơ bản với những gì bộ lọc Kalman đang cố gắng thực hiện.
Stochastically

75

Những gì bạn đang tìm kiếm được gọi là Bộ lọc Kalman . Nó thường được sử dụng để làm mịn dữ liệu điều hướng . Nó không nhất thiết là tầm thường, và có rất nhiều điều chỉnh bạn có thể làm, nhưng đó là một cách tiếp cận rất chuẩn và hoạt động tốt. Có thư viện KFilter có sẵn là triển khai C ++.

Dự phòng tiếp theo của tôi sẽ là hình vuông nhỏ nhất phù hợp . Một bộ lọc Kalman sẽ làm mịn dữ liệu lấy vận tốc, trong khi phương pháp phù hợp với bình phương tối thiểu sẽ chỉ sử dụng thông tin vị trí. Tuy nhiên, nó chắc chắn là đơn giản hơn để thực hiện và hiểu. Có vẻ như Thư viện Khoa học GNU có thể thực hiện việc này.


1
Cảm ơn Chris. Vâng, tôi đã đọc về Kalman trong khi thực hiện một số tìm kiếm, nhưng chắc chắn nó hơi vượt quá kiến ​​thức toán học của tôi. Bạn có biết bất kỳ mã mẫu nào dễ đọc (và hiểu!), Hoặc tốt hơn, một số triển khai có sẵn không? (C / C ++ / Java)
Al.

1
@Al Thật không may, lần tiếp xúc duy nhất của tôi với các bộ lọc Kalman là thông qua công việc, vì vậy tôi có một số mã thanh lịch tuyệt vời mà tôi không thể chỉ cho bạn.
Chris Arguin

Không có vấn đề gì :-) Tôi đã cố gắng tìm kiếm nhưng vì một số lý do có vẻ như thứ Kalman này là ma thuật đen. Rất nhiều trang lý thuyết nhưng ít mã không có .. Cảm ơn, sẽ thử các phương pháp khác.
Al.

2
kalman.sourceforge.net/index.php ở đây là C ++ thực hiện bộ lọc Kalman.
Rostyslav Druzhunn

1
@ChrisArguin Bạn được chào đón. Hãy cho tôi biết nếu kết quả là tốt xin vui lòng.
Rostyslav Druzhunn

11

Điều này có thể đến muộn một chút ...

Tôi đã viết KalmanLocationManager cho Android này, nó bao bọc hai nhà cung cấp vị trí phổ biến nhất là Mạng và GPS, kalman lọc dữ liệu và cung cấp các bản cập nhật choLocationListener (như hai nhà cung cấp 'thực').

Tôi sử dụng nó chủ yếu để "nội suy" giữa các lần đọc - để nhận cập nhật (dự đoán vị trí) cứ sau 100 mili giây (thay vì tốc độ gps tối đa trong một giây), giúp tôi có tốc độ khung hình tốt hơn khi hoạt hình vị trí của mình.

Trên thực tế, nó sử dụng ba bộ lọc kalman, cho mỗi chiều: vĩ độ, kinh độ và độ cao. Dù sao họ cũng độc lập.

Điều này làm cho phép toán ma trận dễ dàng hơn nhiều: thay vì sử dụng một ma trận chuyển tiếp trạng thái 6x6, tôi sử dụng 3 ma trận 2x2 khác nhau. Thực tế trong mã, tôi không sử dụng ma trận nào cả. Đã giải quyết tất cả các phương trình và tất cả các giá trị là nguyên thủy (nhân đôi).

Mã nguồn đang hoạt động và có một hoạt động demo. Xin lỗi vì thiếu javadoc ở một số nơi, tôi sẽ theo kịp.


1
Tôi đã thử sử dụng mã lib của bạn, tôi nhận được một số kết quả không mong muốn, tôi không chắc mình có làm gì sai không ... (Dưới đây là url hình ảnh, màu xanh là đường dẫn của vị trí được lọc, màu cam là vị trí thô) app.box. com / s / w3uvaz007glp2utvgznmh8vlggvaiifk
umesh

Các đột biến bạn đang thấy 'đang phát triển' từ giá trị trung bình (đường màu cam) trông giống như các cập nhật của nhà cung cấp mạng. Bạn có thể thử vẽ sơ đồ cập nhật cả mạng thô và gps không? Có lẽ bạn sẽ tốt hơn nếu không có cập nhật mạng, tùy thuộc vào những gì bạn đang cố gắng đạt được. Btw, bạn nhận được những cập nhật cam thô từ đâu?
dân làng

1
điểm màu cam là từ nhà cung cấp gps và màu xanh là từ Kalman, tôi đã vẽ các bản ghi trên bản đồ
umesh

Bạn có thể gửi cho tôi dữ liệu đó ở một số định dạng văn bản? Mỗi bản cập nhật vị trí có trường trường Location.getProvider (). Chỉ cần một tệp với tất cả Location.toString ().
dân làng

9

Bạn không nên tính tốc độ từ thay đổi vị trí mỗi lần. GPS có thể có vị trí không chính xác, nhưng nó có tốc độ chính xác (trên 5km / h). Vì vậy, sử dụng tốc độ từ tem vị trí GPS. Và hơn nữa bạn không nên làm điều đó với khóa học, mặc dù nó hoạt động hầu hết thời gian.

Các vị trí GPS, như đã phân phối, đã được Kalman lọc, có lẽ bạn không thể cải thiện, trong quá trình hậu xử lý, thông thường bạn không có cùng thông tin như chip GPS.

Bạn có thể làm mịn nó, nhưng điều này cũng giới thiệu lỗi.

Chỉ cần đảm bảo rằng bạn loại bỏ các vị trí khi thiết bị đứng yên, điều này sẽ loại bỏ các vị trí nhảy, mà một số thiết bị / Cấu hình không loại bỏ.


5
Bạn có thể cung cấp một số tài liệu tham khảo cho điều này xin vui lòng?
ivyleavedtoadflax

1
Có rất nhiều thông tin và nhiều kinh nghiệm chuyên môn trong câu đó, câu nào chính xác bạn muốn tham khảo? để biết tốc độ: tìm kiếm hiệu ứng doppler và GPS. Kalman nội bộ? Đây là kiến ​​thức cơ bản về GPS, mỗi tờ giấy hoặc sách mô tả cách thức hoạt động của chip GPS. smootig-lỗi: bao giờ làm mịn giới thiệu erros. đứng yên? Hãy thử nó.
AlexWien

2
"Nhảy lung tung" khi đứng yên không phải là nguồn lỗi duy nhất. Ngoài ra còn có các tín hiệu phản xạ (ví dụ từ các ngọn núi) nơi vị trí nhảy xung quanh. Các chip GPS của tôi (ví dụ: Garmin Dakota 20, SonyElahoma Neo) đã không lọc được điều này ... Và điều thực sự gây cười là giá trị độ cao của tín hiệu GPS khi không kết hợp với áp suất khí quyển. Các giá trị này không được lọc hoặc tôi không muốn xem các giá trị chưa được lọc.
hgoebl

1
@AlexWien GPS tính khoảng cách từ một điểm tại một điểm cho phép dung sai cho bạn một quả cầu có độ dày, vỏ nằm ở giữa vệ tinh. Bạn đang ở đâu đó trong khối lượng vỏ này. Giao điểm của ba trong số các khối này cung cấp cho bạn một khối lượng vị trí, trọng tâm là vị trí tính toán của bạn. Nếu bạn có một tập hợp các vị trí được báo cáo và bạn biết cảm biến đang ở trạng thái nghỉ, tính toán trung tâm có hiệu quả giao cắt nhiều vỏ hơn, cải thiện độ chính xác. Lỗi trong trường hợp này là giảm .
Peter Wone

6
"Vị trí GPS, như đã phân phối, đã được lọc Kalman, có lẽ bạn không thể cải thiện". Nếu bạn có thể chỉ ra một nguồn xác nhận điều này cho điện thoại thông minh hiện đại (ví dụ), điều đó sẽ rất hữu ích. Tôi không thể nhìn thấy bằng chứng của nó. Ngay cả việc lọc Kalman đơn giản về các vị trí thô của thiết bị cũng cho thấy điều đó không đúng. Các vị trí thô nhảy xung quanh thất thường, trong khi các vị trí được lọc thường giữ gần vị trí thực (đã biết).
sobri

6

Tôi thường sử dụng gia tốc kế. Một sự thay đổi vị trí đột ngột trong một thời gian ngắn ngụ ý gia tốc cao. Nếu điều này không được phản ánh trong đo từ xa gia tốc thì gần như chắc chắn là do sự thay đổi của các vệ tinh "ba tốt nhất" được sử dụng để tính toán vị trí (mà tôi gọi là dịch chuyển tức thời GPS).

Khi một tài sản đang ở trạng thái nghỉ và nhảy về do dịch chuyển tức thời GPS, nếu bạn tính toán dần dần trọng tâm, bạn đang giao nhau một cách hiệu quả với một bộ vỏ lớn hơn và lớn hơn, cải thiện độ chính xác.

Để làm điều này khi tài sản không ở trạng thái nghỉ, bạn phải ước tính vị trí và hướng tiếp theo có khả năng của nó dựa trên tốc độ, tiêu đề và dữ liệu gia tốc tuyến tính và quay (nếu bạn có con quay). Đây ít nhiều là những gì bộ lọc K nổi tiếng làm. Bạn có thể có được toàn bộ phần cứng với giá khoảng 150 đô la trên AHRS chứa mọi thứ trừ mô-đun GPS và có giắc cắm để kết nối. Nó có CPU và bộ lọc Kalman riêng trên tàu; kết quả ổn định và khá tốt. Hướng dẫn quán tính có khả năng chống jitter cao nhưng trôi theo thời gian. GPS dễ bị giật nhưng không trôi theo thời gian, chúng thực tế được tạo ra để bù trừ cho nhau.


4

Một phương pháp sử dụng ít toán / lý thuyết là lấy mẫu 2, 5, 7 hoặc 10 điểm dữ liệu tại một thời điểm và xác định những điểm đó là ngoại lệ. Một biện pháp ít chính xác hơn về ngoại lệ so với Bộ lọc Kalman là sử dụng thuật toán sau để lấy tất cả các khoảng cách khôn ngoan giữa các điểm và loại bỏ điểm xa nhất so với các điểm khác. Thông thường, các giá trị đó được thay thế bằng giá trị gần nhất với giá trị bên ngoài mà bạn đang thay thế

Ví dụ

Làm mịn tại năm điểm mẫu A, B, C, D, E

ATOTAL = SUM khoảng cách AB AC AD AE

BTOTAL = SUM khoảng cách AB BC BD BE

CTOTAL = SUM khoảng cách AC BC CD CE

DTOTAL = SUM khoảng cách DA DB DC DE

ETOTAL = SUM khoảng cách EA EB EC DE

Nếu BTOTAL lớn nhất, bạn sẽ thay thế điểm B bằng D nếu BD = min {AB, BC, BD, BE}

Việc làm mịn này xác định các ngoại lệ và có thể được tăng cường bằng cách sử dụng điểm giữa của BD thay vì điểm D để làm mịn đường vị trí. Số dặm của bạn có thể thay đổi và tồn tại nhiều giải pháp nghiêm ngặt hơn về mặt toán học.


Cảm ơn, tôi cũng sẽ cho nó một shot. Lưu ý rằng tôi muốn làm mịn vị trí hiện tại, vì đó là vị trí đang được hiển thị và vị trí được sử dụng để truy xuất một số dữ liệu. Tôi không quan tâm đến những điểm trong quá khứ. Ý tưởng ban đầu của tôi là sử dụng các phương tiện có trọng số, nhưng tôi vẫn phải xem những gì tốt nhất.
Al.

1
Al, đây dường như là một hình thức của phương tiện có trọng số. Bạn sẽ cần sử dụng các điểm "quá khứ" nếu bạn muốn thực hiện bất kỳ việc làm mịn nào, bởi vì hệ thống cần phải có nhiều hơn vị trí hiện tại để biết nơi cần làm mịn quá. Nếu GPS của bạn đang lấy dữ liệu một lần mỗi giây và người dùng của bạn nhìn vào màn hình một lần trong năm giây, bạn có thể sử dụng 5 điểm dữ liệu mà không cần chú ý! Một trung bình di chuyển sẽ chỉ bị trì hoãn bởi một dp cũng.
Karl

4

Đối với hình vuông nhỏ nhất phù hợp, đây là một vài điều khác để thử nghiệm:

  1. Chỉ vì nó phù hợp với hình vuông nhỏ nhất không có nghĩa là nó phải tuyến tính. Bạn có thể tối thiểu - bình phương - vừa với một đường cong bậc hai với dữ liệu, sau đó điều này sẽ phù hợp với một kịch bản mà người dùng đang tăng tốc. (Lưu ý rằng theo bình phương tối thiểu phù hợp với ý tôi là sử dụng tọa độ làm biến phụ thuộc và thời gian làm biến độc lập.)

  2. Bạn cũng có thể thử tính trọng số của các điểm dữ liệu dựa trên độ chính xác được báo cáo. Khi độ chính xác thấp, các điểm dữ liệu sẽ thấp hơn.

  3. Một điều khác bạn có thể muốn thử là thay vì hiển thị một điểm duy nhất, nếu độ chính xác thấp hiển thị một vòng tròn hoặc thứ gì đó cho biết phạm vi mà người dùng có thể dựa trên độ chính xác được báo cáo. (Đây là những gì ứng dụng Google Maps tích hợp của iPhone thực hiện.)


3

Bạn cũng có thể sử dụng một spline. Cung cấp các giá trị bạn có và nội suy các điểm giữa các điểm bạn đã biết. Liên kết này với bộ lọc nhỏ nhất, bình phương di chuyển hoặc bộ lọc kalman (như đã đề cập trong các câu trả lời khác) cho bạn khả năng tính toán các điểm nằm giữa các điểm "đã biết" của bạn.

Việc có thể nội suy các giá trị giữa các mức đã biết của bạn mang lại cho bạn sự chuyển tiếp suôn sẻ và / hợp lý / gần đúng về dữ liệu nào sẽ có nếu bạn có độ chính xác cao hơn. http://en.wikipedia.org/wiki/Spline_interpolation

Splines khác nhau có đặc điểm khác nhau. Thứ mà tôi thấy thường được sử dụng nhất là Akima và các khối vuông.

Một thuật toán khác cần xem xét là thuật toán đơn giản hóa dòng Ramer-Douglas-Peucker, nó được sử dụng khá phổ biến trong việc đơn giản hóa dữ liệu GPS. ( http://en.wikipedia.org/wiki/Ramer-Doumund-Peucker_alacticm )



0

Đã ánh xạ tới CoffeeScript nếu có ai quan tâm. ** chỉnh sửa -> xin lỗi bằng cách sử dụng xương sống quá, nhưng bạn có ý tưởng.

Sửa đổi một chút để chấp nhận đèn hiệu với attribs

{vĩ độ: item.lat, kinh độ: item.lng, ngày: ngày mới (item.effective_at), độ chính xác: 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]

Đã cố gắng chỉnh sửa điều này, nhưng có một lỗi đánh máy ở những dòng cuối cùng @lat@lngđược đặt. Nên +=thay vì=
jdixon04

0

Tôi đã chuyển đổi mã Java từ @Stochastically sang 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

Đây là một triển khai Javascript của triển khai Java của @ Stochastically cho bất kỳ ai cần nó:

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

Ví dụ sử dụng:

   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)
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.