Add --max-range parameter. Use it for relative position limits, and to discard bad position results.

(cherry picked from commit 0d725508f78cb2fd7759efbb66b45b867d6f7722)
This commit is contained in:
Oliver Jowett 2015-01-13 20:03:34 +00:00
parent 8b56cd104f
commit fefce7b4bd
8 changed files with 95 additions and 8 deletions

View file

@ -2490,6 +2490,19 @@ int cprNFunction(double lat, int fflag) {
double cprDlonFunction(double lat, int fflag, int surface) {
return (surface ? 90.0 : 360.0) / cprNFunction(lat, fflag);
}
// Distance between points on a spherical earth.
// This has up to 0.5% error because the earth isn't actually spherical
// (but we don't use it in situations where that matters)
static double greatcircle(double lat0, double lon0, double lat1, double lon1)
{
lat0 = lat0 * M_PI / 180.0;
lon0 = lon0 * M_PI / 180.0;
lat1 = lat1 * M_PI / 180.0;
lon1 = lon1 * M_PI / 180.0;
return 6371e3 * acos(sin(lat0) * sin(lat1) + cos(lat0) * cos(lat1) * cos(fabs(lon0 - lon1)));
}
//
//=========================================================================
//
@ -2516,6 +2529,8 @@ int decodeCPR(struct aircraft *a, int fflag, int surface) {
double surface_rlat = MODES_USER_LATITUDE_DFLT;
double surface_rlon = MODES_USER_LONGITUDE_DFLT;
double rlat, rlon;
if (surface) {
// If we're on the ground, make sure we have a (likely) valid Lat/Lon
if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && (((int)(now - a->seenLatLon)) < Modes.interactive_display_ttl)) {
@ -2553,26 +2568,35 @@ int decodeCPR(struct aircraft *a, int fflag, int surface) {
int ni = cprNFunction(rlat1,1);
int m = (int) floor((((lon0 * (cprNLFunction(rlat1)-1)) -
(lon1 * cprNLFunction(rlat1))) / 131072.0) + 0.5);
a->lon = cprDlonFunction(rlat1, 1, surface) * (cprModInt(m, ni)+lon1/131072);
a->lat = rlat1;
rlon = cprDlonFunction(rlat1, 1, surface) * (cprModInt(m, ni)+lon1/131072);
rlat = rlat1;
} else { // Use even packet.
int ni = cprNFunction(rlat0,0);
int m = (int) floor((((lon0 * (cprNLFunction(rlat0)-1)) -
(lon1 * cprNLFunction(rlat0))) / 131072) + 0.5);
a->lon = cprDlonFunction(rlat0, 0, surface) * (cprModInt(m, ni)+lon0/131072);
a->lat = rlat0;
rlon = cprDlonFunction(rlat0, 0, surface) * (cprModInt(m, ni)+lon0/131072);
rlat = rlat0;
}
if (surface) {
// Pick the quadrant that's closest to the reference location -
// this is not necessarily the same quadrant that contains the
// reference location.
a->lon += floor( (surface_rlon - a->lon + 45) / 90 ) * 90; // if we are >45 degrees away, move towards the reference position
a->lon -= floor( (a->lon + 180) / 360 ) * 360; // normalize to (-180..+180)
} else if (a->lon > 180) {
a->lon -= 360;
rlon += floor( (surface_rlon - rlon + 45) / 90 ) * 90; // if we are >45 degrees away, move towards the reference position
rlon -= floor( (rlon + 180) / 360 ) * 360; // normalize to (-180..+180)
} else if (rlon > 180) {
rlon -= 360;
}
// check max range
if (Modes.maxRange > 0 && (Modes.bUserFlags & MODES_USER_LATLON_VALID)) {
double range = greatcircle(Modes.fUserLat, Modes.fUserLon, rlat, rlon);
if (range > Modes.maxRange)
return (-2); // we consider an out-of-range value to be bad data
}
a->lat = rlat;
a->lon = rlon;
a->seenLatLon = a->seen;
a->timestampLatLon = a->timestamp;
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK);
@ -2595,14 +2619,31 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) {
double lon;
double lonr, latr;
double rlon, rlat;
double range_limit = 0;
int j,m;
if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) { // Ok to try aircraft relative first
int elapsed = (int)(time(NULL) - a->seenLatLon);
latr = a->lat;
lonr = a->lon;
// impose a range limit based on 2000km/h speed
range_limit = 5e3 + (2000e3 * elapsed / 3600); // 5km + 2000km/h
} else if (Modes.bUserFlags & MODES_USER_LATLON_VALID) { // Try ground station relative next
latr = Modes.fUserLat;
lonr = Modes.fUserLon;
// The cell size is at least 360NM, giving a nominal
// max range of 180NM (half a cell).
//
// If the receiver range is more than half a cell
// then we must limit this range further to avoid
// ambiguity. (e.g. if we receive a position report
// at 200NM distance, this may resolve to a position
// at (200-360) = 160NM in the wrong direction)
if (Modes.maxRange > 1852*180)
range_limit = (1852*360) - Modes.maxRange;
} else {
return (-1); // Exit with error - can't do relative if we don't have ref.
}
@ -2648,6 +2689,20 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) {
return (-1); // Time to give up - Longitude error
}
// check range limit
if (range_limit > 0) {
double range = greatcircle(latr, lonr, rlat, rlon);
if (range > range_limit)
return (-1);
}
// check max range
if (Modes.maxRange > 0 && (Modes.bUserFlags & MODES_USER_LATLON_VALID)) {
double range = greatcircle(Modes.fUserLat, Modes.fUserLon, rlat, rlon);
if (range > Modes.maxRange)
return (-2); // we consider an out-of-range value to be bad data
}
a->lat = rlat;
a->lon = rlon;