İşte tam olarak bu durum için kullanılabilecek basit bir Kalman filtresi. Android cihazlarda yaptığım bazı çalışmalardan geldi.
Genel Kalman filtre teorisi, kovaryans matrisleriyle temsil edilen tahminlerin doğruluğu ile, vektörlerin tahminleriyle ilgilidir. Bununla birlikte, Android cihazlarda konumu tahmin etmek için genel teori çok basit bir duruma indirgenir. Android konum sağlayıcıları, konumu, metre cinsinden ölçülen tek bir sayı olarak belirtilen doğrulukla birlikte enlem ve boylam olarak verir. Bu, bir kovaryans matrisi yerine Kalman filtresindeki doğruluğun, Kalman filtresindeki konum iki sayı ile ölçülmesine rağmen tek bir sayı ile ölçülebileceği anlamına gelir. Ayrıca enlem, boylam ve metrelerin etkili bir şekilde tüm farklı birimler olduğu gerçeği göz ardı edilebilir, çünkü Kalman filtresine ölçekleme faktörleri koyarsanız hepsini aynı birimlere dönüştürürseniz,
Kod iyileştirilebilir, çünkü mevcut konumun en iyi tahmininin bilinen son konum olduğunu varsayar ve eğer biri hareket ediyorsa, daha iyi bir tahmin üretmek için Android sensörlerini kullanmak mümkün olmalıdır. Kodun, saniyede metre olarak ifade edilen ve yeni konum tahmini olmadığında doğruluğun ne kadar hızlı azaldığını açıklayan tek bir Q parametresi vardır. Daha yüksek bir Q parametresi, doğruluğun daha hızlı azaldığı anlamına gelir. Kalman filtreleri, doğruluk beklenenden biraz daha hızlı azaldığında genellikle daha iyi çalışır, bu nedenle bir Android telefonla dolaşmak için, genellikle daha yavaş yürümeme rağmen, Q = saniyede 3 metrenin iyi çalıştığını görüyorum. Ancak hızlı bir arabada seyahat ediyorsanız, tabii ki çok daha büyük bir sayı kullanılmalıdır.
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;
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;
}
public void Process(double lat_measurement, double lng_measurement, float accuracy, long TimeStamp_milliseconds) {
if (accuracy < MinAccuracy) accuracy = MinAccuracy;
if (variance < 0) {
this.TimeStamp_milliseconds = TimeStamp_milliseconds;
lat=lat_measurement; lng = lng_measurement; variance = accuracy*accuracy;
} else {
long TimeInc_milliseconds = TimeStamp_milliseconds - this.TimeStamp_milliseconds;
if (TimeInc_milliseconds > 0) {
variance += TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second / 1000;
this.TimeStamp_milliseconds = TimeStamp_milliseconds;
}
float K = variance / (variance + accuracy * accuracy);
lat += K * (lat_measurement - lat);
lng += K * (lng_measurement - lng);
variance = (1 - K) * variance;
}
}
}