Speed check improvements. Entirely invalidate position messages that look wrong.
This commit is contained in:
parent
44302bb199
commit
7cc9438b2d
93
track.c
93
track.c
|
@ -130,7 +130,7 @@ static double greatcircle(double lat0, double lon0, double lat1, double lon1)
|
||||||
|
|
||||||
// return true if it's OK for the aircraft to have travelled from its last known position
|
// return true if it's OK for the aircraft to have travelled from its last known position
|
||||||
// to a new position at (lat,lon,surface) at a time of now.
|
// to a new position at (lat,lon,surface) at a time of now.
|
||||||
static int speed_check(struct aircraft *a, double lat, double lon, uint64_t now, int surface)
|
static int speed_check(struct aircraft *a, struct modesMessage *mm, double lat, double lon, uint64_t now, int surface)
|
||||||
{
|
{
|
||||||
uint64_t elapsed;
|
uint64_t elapsed;
|
||||||
double distance;
|
double distance;
|
||||||
|
@ -143,24 +143,28 @@ static int speed_check(struct aircraft *a, double lat, double lon, uint64_t now,
|
||||||
|
|
||||||
elapsed = now - a->seenLatLon;
|
elapsed = now - a->seenLatLon;
|
||||||
|
|
||||||
|
if ((mm->bFlags & MODES_ACFLAGS_SPEED_VALID) && (a->bFlags & MODES_ACFLAGS_SPEED_VALID))
|
||||||
|
speed = (mm->velocity + a->speed) / 2;
|
||||||
|
else if (mm->bFlags & MODES_ACFLAGS_SPEED_VALID)
|
||||||
|
speed = mm->velocity;
|
||||||
|
else if (a->bFlags & MODES_ACFLAGS_SPEED_VALID)
|
||||||
|
speed = a->speed;
|
||||||
|
else
|
||||||
|
speed = surface ? 100 : 600; // guess
|
||||||
|
|
||||||
// Work out a reasonable speed to use:
|
// Work out a reasonable speed to use:
|
||||||
// current speed + 50%
|
// current speed + 1/3
|
||||||
// surface speed min 30kt, max 150kt
|
// surface speed min 20kt, max 150kt
|
||||||
// airborne speed min 300kt, no max
|
// airborne speed min 200kt, no max
|
||||||
if ((a->bFlags & MODES_ACFLAGS_SPEED_VALID)) {
|
speed = speed * 4 / 3;
|
||||||
speed = a->speed * 3 / 2;
|
|
||||||
if (surface) {
|
if (surface) {
|
||||||
if (speed < 30)
|
if (speed < 20)
|
||||||
speed = 30;
|
speed = 20;
|
||||||
if (speed > 150)
|
if (speed > 150)
|
||||||
speed = 150;
|
speed = 150;
|
||||||
} else {
|
} else {
|
||||||
if (speed < 300)
|
if (speed < 200)
|
||||||
speed = 300;
|
speed = 200;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Guess.
|
|
||||||
speed = surface ? 150 : 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 100m (surface) or 500m (airborne) base distance to allow for minor errors,
|
// 100m (surface) or 500m (airborne) base distance to allow for minor errors,
|
||||||
|
@ -181,9 +185,11 @@ static int speed_check(struct aircraft *a, double lat, double lon, uint64_t now,
|
||||||
return inrange;
|
return inrange;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doGlobalCPR(struct aircraft *a, int fflag, int surface, uint64_t now, double *lat, double *lon, unsigned *nuc)
|
static int doGlobalCPR(struct aircraft *a, struct modesMessage *mm, uint64_t now, double *lat, double *lon, unsigned *nuc)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
int fflag = (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) != 0;
|
||||||
|
int surface = (mm->bFlags & MODES_ACFLAGS_AOG) != 0;
|
||||||
|
|
||||||
*nuc = (a->even_cprnuc < a->odd_cprnuc ? a->even_cprnuc : a->odd_cprnuc); // worst of the two positions
|
*nuc = (a->even_cprnuc < a->odd_cprnuc ? a->even_cprnuc : a->odd_cprnuc); // worst of the two positions
|
||||||
|
|
||||||
|
@ -236,7 +242,7 @@ static int doGlobalCPR(struct aircraft *a, int fflag, int surface, uint64_t now,
|
||||||
}
|
}
|
||||||
|
|
||||||
// check speed limit
|
// check speed limit
|
||||||
if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && a->pos_nuc >= *nuc && !speed_check(a, *lat, *lon, now, surface)) {
|
if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && a->pos_nuc >= *nuc && !speed_check(a, mm, *lat, *lon, now, surface)) {
|
||||||
Modes.stats_current.cpr_global_speed_checks++;
|
Modes.stats_current.cpr_global_speed_checks++;
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
@ -244,15 +250,17 @@ static int doGlobalCPR(struct aircraft *a, int fflag, int surface, uint64_t now,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doLocalCPR(struct aircraft *a, int fflag, int surface, uint64_t now, double *lat, double *lon, unsigned *nuc)
|
static int doLocalCPR(struct aircraft *a, struct modesMessage *mm, uint64_t now, double *lat, double *lon, unsigned *nuc)
|
||||||
{
|
{
|
||||||
// relative CPR
|
// relative CPR
|
||||||
// find reference location
|
// find reference location
|
||||||
double reflat, reflon;
|
double reflat, reflon;
|
||||||
double range_limit = 0;
|
double range_limit = 0;
|
||||||
int result;
|
int result;
|
||||||
|
int fflag = (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) != 0;
|
||||||
|
int surface = (mm->bFlags & MODES_ACFLAGS_AOG) != 0;
|
||||||
|
|
||||||
*nuc = (fflag ? a->odd_cprnuc : a->even_cprnuc);
|
*nuc = mm->nuc_p;
|
||||||
|
|
||||||
if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) {
|
if (a->bFlags & MODES_ACFLAGS_LATLON_REL_OK) {
|
||||||
reflat = a->lat;
|
reflat = a->lat;
|
||||||
|
@ -286,8 +294,8 @@ static int doLocalCPR(struct aircraft *a, int fflag, int surface, uint64_t now,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = decodeCPRrelative(reflat, reflon,
|
result = decodeCPRrelative(reflat, reflon,
|
||||||
fflag ? a->odd_cprlat : a->even_cprlat,
|
mm->raw_latitude,
|
||||||
fflag ? a->odd_cprlon : a->even_cprlon,
|
mm->raw_longitude,
|
||||||
fflag, surface,
|
fflag, surface,
|
||||||
lat, lon);
|
lat, lon);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
|
@ -297,17 +305,13 @@ static int doLocalCPR(struct aircraft *a, int fflag, int surface, uint64_t now,
|
||||||
if (range_limit > 0) {
|
if (range_limit > 0) {
|
||||||
double range = greatcircle(reflat, reflon, *lat, *lon);
|
double range = greatcircle(reflat, reflon, *lat, *lon);
|
||||||
if (range > range_limit) {
|
if (range > range_limit) {
|
||||||
#ifdef DEBUG_CPR_CHECKS
|
|
||||||
fprintf(stderr, "Local position ambiguous: %06x: %.3f,%.3f -> %.3f,%.3f, max range %.1fkm, actual %.1fkm\n",
|
|
||||||
a->addr, reflat, reflon, *lat, *lon, range_limit/1000.0, range/1000.0);
|
|
||||||
#endif
|
|
||||||
Modes.stats_current.cpr_local_range_checks++;
|
Modes.stats_current.cpr_local_range_checks++;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check speed limit
|
// check speed limit
|
||||||
if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && a->pos_nuc >= *nuc && !speed_check(a, *lat, *lon, now, surface)) {
|
if ((a->bFlags & MODES_ACFLAGS_LATLON_VALID) && a->pos_nuc >= *nuc && !speed_check(a, mm, *lat, *lon, now, surface)) {
|
||||||
Modes.stats_current.cpr_local_speed_checks++;
|
Modes.stats_current.cpr_local_speed_checks++;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -348,17 +352,26 @@ static void updatePosition(struct aircraft *a, struct modesMessage *mm, uint64_t
|
||||||
|
|
||||||
// If we have enough recent data, try global CPR
|
// If we have enough recent data, try global CPR
|
||||||
if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID && abs((int)(a->even_cprtime - a->odd_cprtime)) <= max_elapsed) {
|
if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID && abs((int)(a->even_cprtime - a->odd_cprtime)) <= max_elapsed) {
|
||||||
location_result = doGlobalCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG), now,
|
location_result = doGlobalCPR(a, mm, now, &new_lat, &new_lon, &new_nuc);
|
||||||
&new_lat, &new_lon, &new_nuc);
|
|
||||||
|
|
||||||
if (location_result == -2) {
|
if (location_result == -2) {
|
||||||
// Global CPR failed because an airborne position produced implausible results.
|
// Global CPR failed because the position produced implausible results.
|
||||||
// This is bad data. Discard both odd and even messages and wait for a fresh pair.
|
// This is bad data. Discard both odd and even messages and wait for a fresh pair.
|
||||||
// Also disable aircraft-relative positions until we have a new good position (but don't discard the
|
// Also disable aircraft-relative positions until we have a new good position (but don't discard the
|
||||||
// recorded position itself)
|
// recorded position itself)
|
||||||
Modes.stats_current.cpr_global_bad++;
|
Modes.stats_current.cpr_global_bad++;
|
||||||
mm->bFlags &= ~(MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LLODD_VALID | MODES_ACFLAGS_LLEVEN_VALID);
|
|
||||||
a->bFlags &= ~(MODES_ACFLAGS_LATLON_REL_OK | MODES_ACFLAGS_LLODD_VALID | MODES_ACFLAGS_LLEVEN_VALID);
|
a->bFlags &= ~(MODES_ACFLAGS_LATLON_REL_OK | MODES_ACFLAGS_LLODD_VALID | MODES_ACFLAGS_LLEVEN_VALID);
|
||||||
|
|
||||||
|
// Also discard the current message's data as it is suspect - we don't want
|
||||||
|
// to update any of the aircraft state from this.
|
||||||
|
mm->bFlags &= ~(MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LLODD_VALID | MODES_ACFLAGS_LLEVEN_VALID |
|
||||||
|
MODES_ACFLAGS_ALTITUDE_VALID |
|
||||||
|
MODES_ACFLAGS_SPEED_VALID |
|
||||||
|
MODES_ACFLAGS_HEADING_VALID |
|
||||||
|
MODES_ACFLAGS_NSEWSPD_VALID |
|
||||||
|
MODES_ACFLAGS_VERTRATE_VALID |
|
||||||
|
MODES_ACFLAGS_AOG_VALID |
|
||||||
|
MODES_ACFLAGS_AOG);
|
||||||
return;
|
return;
|
||||||
} else if (location_result == -1) {
|
} else if (location_result == -1) {
|
||||||
// No local reference for surface position available, or the two messages crossed a zone.
|
// No local reference for surface position available, or the two messages crossed a zone.
|
||||||
|
@ -371,7 +384,7 @@ static void updatePosition(struct aircraft *a, struct modesMessage *mm, uint64_t
|
||||||
|
|
||||||
// Otherwise try relative CPR.
|
// Otherwise try relative CPR.
|
||||||
if (location_result == -1) {
|
if (location_result == -1) {
|
||||||
location_result = doLocalCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG), now, &new_lat, &new_lon, &new_nuc);
|
location_result = doLocalCPR(a, mm, now, &new_lat, &new_lon, &new_nuc);
|
||||||
|
|
||||||
if (location_result == -1) {
|
if (location_result == -1) {
|
||||||
Modes.stats_current.cpr_local_skipped++;
|
Modes.stats_current.cpr_local_skipped++;
|
||||||
|
@ -420,6 +433,16 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
a->seen = now;
|
a->seen = now;
|
||||||
a->messages++;
|
a->messages++;
|
||||||
|
|
||||||
|
// if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags
|
||||||
|
if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) {
|
||||||
|
a->bFlags &= ~(MODES_ACFLAGS_LLBOTH_VALID | MODES_ACFLAGS_AOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've got a new cprlat or cprlon
|
||||||
|
if (mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID) {
|
||||||
|
updatePosition(a, mm, now);
|
||||||
|
}
|
||||||
|
|
||||||
// If a (new) CALLSIGN has been received, copy it to the aircraft structure
|
// If a (new) CALLSIGN has been received, copy it to the aircraft structure
|
||||||
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {
|
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {
|
||||||
memcpy(a->flight, mm->flight, sizeof(a->flight));
|
memcpy(a->flight, mm->flight, sizeof(a->flight));
|
||||||
|
@ -463,16 +486,6 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
|
||||||
a->vert_rate = mm->vert_rate;
|
a->vert_rate = mm->vert_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags
|
|
||||||
if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) {
|
|
||||||
a->bFlags &= ~(MODES_ACFLAGS_LLBOTH_VALID | MODES_ACFLAGS_AOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we've got a new cprlat or cprlon
|
|
||||||
if (mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID) {
|
|
||||||
updatePosition(a, mm, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the aircrafts a->bFlags to reflect the newly received mm->bFlags;
|
// Update the aircrafts a->bFlags to reflect the newly received mm->bFlags;
|
||||||
a->bFlags |= mm->bFlags;
|
a->bFlags |= mm->bFlags;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue