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

@ -52,6 +52,11 @@ AGGRESSIVE=
LAT= LAT=
LON= LON=
# If set, provides the absolute maximum receiver range used to
# filter bad position reports, and to determine when local position
# decoding is safe to use. Specify this in nautical miles (NM).
MAX_RANGE=
# #
# Networking options # Networking options
# #

View file

@ -30,6 +30,7 @@ if [ -e $CONFIGFILE ]; then
db_set_yn $NAME/decode-aggressive "$AGGRESSIVE" db_set_yn $NAME/decode-aggressive "$AGGRESSIVE"
db_set $NAME/decode-lat "$LAT" db_set $NAME/decode-lat "$LAT"
db_set $NAME/decode-lon "$LON" db_set $NAME/decode-lon "$LON"
db_set $NAME/decode-max-range "$MAX_RANGE"
db_set $NAME/net-http-port "$HTTP_PORT" db_set $NAME/net-http-port "$HTTP_PORT"
db_set $NAME/net-ri-port "$RAW_INPUT_PORT" db_set $NAME/net-ri-port "$RAW_INPUT_PORT"
@ -178,6 +179,7 @@ db_go || true; db_get $NAME/auto-start; if [ "$RET" = "true" ]; then
db_input low $NAME/decode-fix-crc || true db_input low $NAME/decode-fix-crc || true
db_input low $NAME/decode-aggressive || true db_input low $NAME/decode-aggressive || true
db_input_verify medium $NAME/decode-max-range is_number || true
db_input_verify medium $NAME/decode-lat is_number_or_empty || true db_input_verify medium $NAME/decode-lat is_number_or_empty || true
db_go || true; db_get $NAME/decode-lat; if [ -n "$RET" ]; then db_go || true; db_get $NAME/decode-lat; if [ -n "$RET" ]; then

View file

@ -42,6 +42,7 @@ SCRIPTNAME=/etc/init.d/$NAME
[ -z "$FATSV_OUTPUT_PORT" ] && FATSV_OUTPUT_PORT=0 [ -z "$FATSV_OUTPUT_PORT" ] && FATSV_OUTPUT_PORT=0
[ -z "$NET_BUFFER" ] && NET_BUFFER=0 [ -z "$NET_BUFFER" ] && NET_BUFFER=0
[ -z "$JSON_INTERVAL" ] && JSON_INTERVAL=0 [ -z "$JSON_INTERVAL" ] && JSON_INTERVAL=0
[ -z "$MAX_RANGE" ] && MAX_RANGE=300
# receiver: # receiver:
case "x$DEVICE" in case "x$DEVICE" in
@ -63,6 +64,7 @@ if [ "x$PHASE_ENHANCE" = "xyes" ]; then ARGS="$ARGS --phase-enhance"; fi
if [ "x$AGGRESSIVE" = "xyes" ]; then ARGS="$ARGS --aggressive"; fi if [ "x$AGGRESSIVE" = "xyes" ]; then ARGS="$ARGS --aggressive"; fi
if [ -n "$LAT" ]; then ARGS="$ARGS --lat $LAT"; fi if [ -n "$LAT" ]; then ARGS="$ARGS --lat $LAT"; fi
if [ -n "$LON" ]; then ARGS="$ARGS --lon $LON"; fi if [ -n "$LON" ]; then ARGS="$ARGS --lon $LON"; fi
ARGS="$ARGS --max-range $MAX_RANGE"; fi
# net: # net:

View file

@ -69,6 +69,7 @@ case "$1" in
subvar_yn decode-aggressive AGGRESSIVE subvar_yn decode-aggressive AGGRESSIVE
subvar decode-lat LAT subvar decode-lat LAT
subvar decode-lon LON subvar decode-lon LON
subvar decode-max-range MAX_RANGE
subvar net-http-port HTTP_PORT subvar net-http-port HTTP_PORT
subvar net-ri-port RAW_INPUT_PORT subvar net-ri-port RAW_INPUT_PORT
subvar net-ro-port RAW_OUTPUT_PORT subvar net-ro-port RAW_OUTPUT_PORT

View file

@ -102,6 +102,23 @@ Description: Longitude of receiver, in decimal degrees:
Type: string Type: string
Default: Default:
Template: dump1090-mutability/decode-max-range
Description: Absolute maximum range of receiver, in nautical miles:
If the maximum range of the receiver is provided, dump1090 can filter
out impossible position reports that are due to aircraft that transmit
bad data.
.
Additionally, if the maximum range is larger than 180NM, when local
position decoding is used (when insufficient position messages
have been received for global position decoding), it is limited to
only those positions that would unambiguously decode to a single
position within the given receiver range.
.
This range should be the absolute maximum range - any position data
from further away will be entirely discarded!
Type: string
Default: 300
Template: dump1090-mutability/net-http-port Template: dump1090-mutability/net-http-port
Description: Port for internal webserver (0 disables): Description: Port for internal webserver (0 disables):
dump1090 can provide an internal webserver that serves a basic "virtual dump1090 can provide an internal webserver that serves a basic "virtual

View file

@ -87,6 +87,7 @@ void modesInitConfig(void) {
Modes.fUserLon = MODES_USER_LONGITUDE_DFLT; Modes.fUserLon = MODES_USER_LONGITUDE_DFLT;
Modes.json_interval = 1; Modes.json_interval = 1;
Modes.json_location_accuracy = 1; Modes.json_location_accuracy = 1;
Modes.maxRange = 1852 * 300; // 300NM default max range
} }
// //
//========================================================================= //=========================================================================
@ -460,6 +461,7 @@ void showHelp(void) {
"--net-buffer <n> TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)\n" "--net-buffer <n> TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)\n"
"--lat <latitude> Reference/receiver latitude for surface posn (opt)\n" "--lat <latitude> Reference/receiver latitude for surface posn (opt)\n"
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n" "--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
"--max-range <distance> Absolute maximum range for position decoding (in nm, default: 300)\n"
"--fix Enable single-bits error correction using CRC\n" "--fix Enable single-bits error correction using CRC\n"
"--no-fix Disable single-bits error correction using CRC\n" "--no-fix Disable single-bits error correction using CRC\n"
"--no-crc-check Disable messages with broken CRC (discouraged)\n" "--no-crc-check Disable messages with broken CRC (discouraged)\n"
@ -822,6 +824,8 @@ int main(int argc, char **argv) {
Modes.fUserLat = atof(argv[++j]); Modes.fUserLat = atof(argv[++j]);
} else if (!strcmp(argv[j],"--lon") && more) { } else if (!strcmp(argv[j],"--lon") && more) {
Modes.fUserLon = atof(argv[++j]); Modes.fUserLon = atof(argv[++j]);
} else if (!strcmp(argv[j],"--max-range") && more) {
Modes.maxRange = atof(argv[++j]) * 1852.0; // convert to metres
} else if (!strcmp(argv[j],"--debug") && more) { } else if (!strcmp(argv[j],"--debug") && more) {
char *f = argv[++j]; char *f = argv[++j];
while(*f) { while(*f) {

View file

@ -367,6 +367,7 @@ struct { // Internal state
double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location
double fUserLon; // Users receiver/antenna lat/lon needed for initial surface location double fUserLon; // Users receiver/antenna lat/lon needed for initial surface location
int bUserFlags; // Flags relating to the user details int bUserFlags; // Flags relating to the user details
double maxRange; // Absolute maximum decoding range, in *metres*
// Interactive mode // Interactive mode
struct aircraft *aircrafts; struct aircraft *aircrafts;

View file

@ -2490,6 +2490,19 @@ int cprNFunction(double lat, int fflag) {
double cprDlonFunction(double lat, int fflag, int surface) { double cprDlonFunction(double lat, int fflag, int surface) {
return (surface ? 90.0 : 360.0) / cprNFunction(lat, fflag); 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_rlat = MODES_USER_LATITUDE_DFLT;
double surface_rlon = MODES_USER_LONGITUDE_DFLT; double surface_rlon = MODES_USER_LONGITUDE_DFLT;
double rlat, rlon;
if (surface) { if (surface) {
// If we're on the ground, make sure we have a (likely) valid Lat/Lon // 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)) { 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 ni = cprNFunction(rlat1,1);
int m = (int) floor((((lon0 * (cprNLFunction(rlat1)-1)) - int m = (int) floor((((lon0 * (cprNLFunction(rlat1)-1)) -
(lon1 * cprNLFunction(rlat1))) / 131072.0) + 0.5); (lon1 * cprNLFunction(rlat1))) / 131072.0) + 0.5);
a->lon = cprDlonFunction(rlat1, 1, surface) * (cprModInt(m, ni)+lon1/131072); rlon = cprDlonFunction(rlat1, 1, surface) * (cprModInt(m, ni)+lon1/131072);
a->lat = rlat1; rlat = rlat1;
} else { // Use even packet. } else { // Use even packet.
int ni = cprNFunction(rlat0,0); int ni = cprNFunction(rlat0,0);
int m = (int) floor((((lon0 * (cprNLFunction(rlat0)-1)) - int m = (int) floor((((lon0 * (cprNLFunction(rlat0)-1)) -
(lon1 * cprNLFunction(rlat0))) / 131072) + 0.5); (lon1 * cprNLFunction(rlat0))) / 131072) + 0.5);
a->lon = cprDlonFunction(rlat0, 0, surface) * (cprModInt(m, ni)+lon0/131072); rlon = cprDlonFunction(rlat0, 0, surface) * (cprModInt(m, ni)+lon0/131072);
a->lat = rlat0; rlat = rlat0;
} }
if (surface) { if (surface) {
// Pick the quadrant that's closest to the reference location - // Pick the quadrant that's closest to the reference location -
// this is not necessarily the same quadrant that contains the // this is not necessarily the same quadrant that contains the
// reference location. // reference location.
a->lon += floor( (surface_rlon - a->lon + 45) / 90 ) * 90; // if we are >45 degrees away, move towards the reference position rlon += floor( (surface_rlon - rlon + 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) rlon -= floor( (rlon + 180) / 360 ) * 360; // normalize to (-180..+180)
} else if (a->lon > 180) { } else if (rlon > 180) {
a->lon -= 360; 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->seenLatLon = a->seen;
a->timestampLatLon = a->timestamp; a->timestampLatLon = a->timestamp;
a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK); 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 lon;
double lonr, latr; double lonr, latr;
double rlon, rlat; double rlon, rlat;
double range_limit = 0;
int j,m; int j,m;
if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) { // Ok to try aircraft relative first if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) { // Ok to try aircraft relative first
int elapsed = (int)(time(NULL) - a->seenLatLon);
latr = a->lat; latr = a->lat;
lonr = a->lon; 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 } else if (Modes.bUserFlags & MODES_USER_LATLON_VALID) { // Try ground station relative next
latr = Modes.fUserLat; latr = Modes.fUserLat;
lonr = Modes.fUserLon; 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 { } else {
return (-1); // Exit with error - can't do relative if we don't have ref. 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 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->lat = rlat;
a->lon = rlon; a->lon = rlon;