Aqui está um filtro Kalman simples que pode ser usado exatamente nessa situação. Veio de algum trabalho que fiz em dispositivos Android.
A teoria geral dos filtros de Kalman trata de estimativas para vetores, com a precisão das estimativas representadas por matrizes de covariância. No entanto, para estimar a localização em dispositivos Android, a teoria geral se reduz a um caso muito simples. Os fornecedores de localização Android fornecem a localização como latitude e longitude, juntamente com uma precisão especificada como um número único medido em metros. Isso significa que, em vez de uma matriz de covariância, a precisão no filtro Kalman pode ser medida por um único número, mesmo que a localização no filtro Kalman seja medida por dois números. Além disso, o fato de latitude, longitude e metros serem efetivamente todas as unidades diferentes pode ser ignorado, porque se você colocar fatores de escala no filtro Kalman para convertê-los em unidades iguais,
O código pode ser aprimorado, pois assume que a melhor estimativa da localização atual é a última localização conhecida e, se alguém estiver em movimento, deve ser possível usar os sensores do Android para produzir uma estimativa melhor. O código possui um único parâmetro livre Q, expresso em metros por segundo, que descreve a rapidez com que a precisão diminui na ausência de novas estimativas de localização. Um parâmetro Q mais alto significa que a precisão diminui mais rapidamente. Os filtros Kalman geralmente funcionam melhor quando a precisão diminui um pouco mais rapidamente do que se poderia esperar, então, para andar com um telefone Android, acho que Q = 3 metros por segundo funciona bem, mesmo que eu geralmente ande mais devagar do que isso. Mas se estiver viajando em um carro veloz, obviamente deverá ser usado um número muito maior.
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;
}
}
}