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:
parent
8b56cd104f
commit
fefce7b4bd
5
debian/config-template
vendored
5
debian/config-template
vendored
|
@ -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
|
||||||
#
|
#
|
||||||
|
|
2
debian/dump1090-mutability.config
vendored
2
debian/dump1090-mutability.config
vendored
|
@ -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
|
||||||
|
|
2
debian/dump1090-mutability.init
vendored
2
debian/dump1090-mutability.init
vendored
|
@ -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:
|
||||||
|
|
||||||
|
|
1
debian/dump1090-mutability.postinst
vendored
1
debian/dump1090-mutability.postinst
vendored
|
@ -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
|
||||||
|
|
17
debian/dump1090-mutability.templates
vendored
17
debian/dump1090-mutability.templates
vendored
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
71
mode_s.c
71
mode_s.c
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue