Вот простой фильтр Калмана, который может быть использован именно для этой ситуации. Это было связано с некоторыми работами, которые я делал на устройствах Android.
Общая теория фильтра Калмана касается оценок для векторов с точностью оценок, представленных ковариационными матрицами. Однако для оценки местоположения на устройствах Android общая теория сводится к очень простому случаю. Поставщики местоположения Android предоставляют местоположение в виде широты и долготы вместе с точностью, которая определяется как единое число, измеренное в метрах. Это означает, что вместо ковариационной матрицы точность фильтра Калмана может быть измерена одним числом, хотя местоположение в калмановском фильтре измеряется двумя числами. Также можно игнорировать тот факт, что широта, долгота и метры фактически все разные единицы могут быть проигнорированы, потому что если вы поместите коэффициенты масштабирования в фильтр Калмана, чтобы преобразовать их все в одни и те же единицы, то эти коэффициенты масштабирования в конечном итоге будут отменены при преобразовании результатов обратно в исходные единицы.
Код может быть улучшен, так как он предполагает, что наилучшая оценка текущего местоположения - это последнее известное местоположение, и, если кто-то движется, должно быть возможно использовать датчики Android для получения более точной оценки. Код имеет единственный свободный параметр Q, выраженный в метрах в секунду, который описывает, как быстро точность уменьшается при отсутствии каких-либо новых оценок местоположения. Более высокий параметр Q означает, что точность уменьшается быстрее. Фильтры Kalman в целом работают лучше, когда точность затухает немного быстрее, чем можно было бы ожидать, поэтому для прогулки по телефону с 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;
}
}
}
Я чувствую плохие эффекты «GPS шума» при попытке вычислить связанные (производные) значения, как скорость и наклон, которые очень прерывистые специально для Tracklogs высокой частоты дискретизации (так как время есть целое число [одна секунда]). – heltonbiker
(также, если вы путешествуете по основным дорогам, вы можете использовать алгоритм «привязать к дорогам», если у вас есть хороший [правильный, точный] набор данных дорожной карты. Просто мысль) – heltonbiker
Я столкнулся с этой проблемой и для лучшей точности. – ViruMax