Aquí hay un filtro simple de Kalman que podría usarse exactamente para esta situación. Vino de un trabajo que hice en dispositivos Android.
La teoría general del filtro de Kalman se trata de estimaciones para vectores, con la precisión de las estimaciones representadas por matrices de covarianza. Sin embargo, para estimar la ubicación en dispositivos Android, la teoría general se reduce a un caso muy simple. Los proveedores de ubicación de Android dan la ubicación como latitud y longitud, junto con una precisión que se especifica como un solo número medido en metros. Esto significa que, en lugar de una matriz de covarianza, la precisión en el filtro de Kalman se puede medir con un solo número, aunque la ubicación en el filtro de Kalman se mide con dos números. También se puede ignorar el hecho de que la latitud, la longitud y los metros son efectivamente todas las unidades diferentes, porque si coloca factores de escala en el filtro de Kalman para convertirlos a todos en las mismas unidades,
El código podría mejorarse, ya que supone que la mejor estimación de la ubicación actual es la última ubicación conocida, y si alguien se está moviendo, debería ser posible usar los sensores de Android para producir una mejor estimación. El código tiene un único parámetro libre Q, expresado en metros por segundo, que describe la rapidez con que decae la precisión en ausencia de nuevas estimaciones de ubicación. Un parámetro Q más alto significa que la precisión disminuye más rápido. Los filtros Kalman generalmente funcionan mejor cuando la precisión disminuye un poco más rápido de lo que cabría esperar, por lo que para caminar con un teléfono Android encuentro que Q = 3 metros por segundo funciona bien, aunque generalmente camino más lento que eso. Pero si viaja en un automóvil rápido, obviamente debería usarse un número mucho mayor.
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;
}
}
}