mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 13:20:57 +00:00
working towards an improved outlier detection which also captures testJumpyFixes properly
This commit is contained in:
1 parent
3d26b9a70b
commit
8f671b7010
2 files changed
+68
-50
No files matched your search
+36
-34
@@ -95,60 +95,62 @@ public class DynamicGPSFixMovingTrackImpl<ItemType> extends DynamicTrackImpl<Ite
|
||||
}
|
||||
|
||||
/**
|
||||
* In addition to the base class implementation, we additionally have the speed and bearing as measured by the
|
||||
* device. If the adjacent fixes are within the averaging interval defined by
|
||||
* {@link GPSFixTrackImpl#getMillisecondsOverWhichToAverageSpeed()}, we use the device-measured speed and compare it
|
||||
* with the speed computed based on the timestamp and distance between previous and next fix. If the latter speed
|
||||
* exceeds the measured speed by more than a factor of
|
||||
* In addition to the base class implementation, we may have the speed and bearing as measured by the device (the
|
||||
* special speed/bearing combination 0.0/0.0 is simply ignored). If the adjacent fixes are within the averaging
|
||||
* interval defined by {@link GPSFixTrackImpl#getMillisecondsOverWhichToAverageSpeed()}, we use the device-measured
|
||||
* speed and compare it with the speed computed based on the time stamp and distance between previous and next fix.
|
||||
* If the ratio between the higher and the lower of the two speeds exceeds
|
||||
* {@link #MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING}, the fix is considered invalid.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isValid(NavigableSet<GPSFixMoving> rawFixes, GPSFixMoving e) {
|
||||
assertReadLock();
|
||||
boolean result;
|
||||
final boolean isValid;
|
||||
if (e.isValidityCached()) {
|
||||
result = e.isValid();
|
||||
isValid = e.isValid();
|
||||
} else {
|
||||
boolean fixHasValidSogAndCog = (e.getSpeed().getMetersPerSecond() != 0.0 && e.getSpeed().getBearing().getDegrees() != 0.0);
|
||||
|
||||
GPSFixMoving previous = rawFixes.lower(e);
|
||||
GPSFixMoving next = rawFixes.higher(e);
|
||||
final boolean atLeastOnePreviousFixInRange = previous != null && e.getTimePoint().asMillis() - previous.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed();
|
||||
Speed speedToPrevious = null;
|
||||
if (previous != null && Math.abs(previous.getTimePoint().asMillis() - e.getTimePoint().asMillis()) <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
boolean foundValidPreviousFixInRange = false;
|
||||
while (previous != null && !foundValidPreviousFixInRange && e.getTimePoint().asMillis() - previous.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
speedToPrevious = previous.getPosition().getDistance(e.getPosition())
|
||||
.inTime(e.getTimePoint().asMillis() - previous.getTimePoint().asMillis());
|
||||
}
|
||||
Speed speedToNext = null;
|
||||
if (next != null && Math.abs(next.getTimePoint().asMillis() - e.getTimePoint().asMillis()) <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
speedToNext = e.getPosition().getDistance(next.getPosition())
|
||||
.inTime(next.getTimePoint().asMillis() - e.getTimePoint().asMillis());
|
||||
}
|
||||
final double speedToPreviousFactor;
|
||||
if (speedToPrevious != null) {
|
||||
final double speedToPreviousFactor;
|
||||
if (speedToPrevious.getMetersPerSecond() >= e.getSpeed().getMetersPerSecond()) {
|
||||
speedToPreviousFactor = speedToPrevious.getMetersPerSecond() / e.getSpeed().getMetersPerSecond();
|
||||
} else {
|
||||
speedToPreviousFactor = e.getSpeed().getMetersPerSecond() / speedToPrevious.getMetersPerSecond();
|
||||
}
|
||||
} else {
|
||||
speedToPreviousFactor = 0;
|
||||
foundValidPreviousFixInRange = speedToPrevious.compareTo(maxSpeedForSmoothing) <= 0
|
||||
&& (!fixHasValidSogAndCog || speedToPreviousFactor <= MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING);
|
||||
previous = rawFixes.lower(previous);
|
||||
}
|
||||
final double speedToNextFactor;
|
||||
if (speedToNext != null) {
|
||||
if (speedToNext.getMetersPerSecond() >= e.getSpeed().getMetersPerSecond()) {
|
||||
speedToNextFactor = speedToNext.getMetersPerSecond() / e.getSpeed().getMetersPerSecond();
|
||||
} else {
|
||||
speedToNextFactor = e.getSpeed().getMetersPerSecond() / speedToNext.getMetersPerSecond();
|
||||
boolean foundValidNextFixInRange = false;
|
||||
boolean atLeastOneNextFixInRange = false;
|
||||
if (!foundValidPreviousFixInRange) {
|
||||
GPSFixMoving next = rawFixes.higher(e);
|
||||
atLeastOneNextFixInRange = next != null && next.getTimePoint().asMillis() - e.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed();
|
||||
Speed speedToNext = null;
|
||||
while (next != null && !foundValidNextFixInRange && next.getTimePoint().asMillis() - e.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
speedToNext = e.getPosition().getDistance(next.getPosition())
|
||||
.inTime(next.getTimePoint().asMillis() - e.getTimePoint().asMillis());
|
||||
final double speedToNextFactor;
|
||||
if (speedToNext.getMetersPerSecond() >= e.getSpeed().getMetersPerSecond()) {
|
||||
speedToNextFactor = speedToNext.getMetersPerSecond() / e.getSpeed().getMetersPerSecond();
|
||||
} else {
|
||||
speedToNextFactor = e.getSpeed().getMetersPerSecond() / speedToNext.getMetersPerSecond();
|
||||
}
|
||||
foundValidNextFixInRange = speedToNext.compareTo(maxSpeedForSmoothing) <= 0
|
||||
&& (!fixHasValidSogAndCog || speedToNextFactor <= MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING);
|
||||
next = rawFixes.higher(next);
|
||||
}
|
||||
} else {
|
||||
speedToNextFactor = 0;
|
||||
}
|
||||
result = (!fixHasValidSogAndCog || ((speedToPrevious == null || speedToPreviousFactor <= MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING)
|
||||
&& (speedToNext == null || speedToNextFactor <= MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING)))
|
||||
&& (maxSpeedForSmoothing == null
|
||||
|| (speedToPrevious == null || speedToPrevious.compareTo(maxSpeedForSmoothing) <= 0) || (speedToNext == null || speedToNext
|
||||
.compareTo(maxSpeedForSmoothing) <= 0));
|
||||
e.cacheValidity(result);
|
||||
isValid = (!atLeastOnePreviousFixInRange || foundValidPreviousFixInRange) || (!atLeastOneNextFixInRange || foundValidNextFixInRange);
|
||||
e.cacheValidity(isValid);
|
||||
}
|
||||
return result;
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
+32
-16
@@ -794,37 +794,53 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* When redefining this method, make sure to redefine {@link #invalidateValidityAndDistanceCaches(GPSFix)} accordingly.
|
||||
* This implementation checks the immediate previous and next fix for <code>e</code>. Therefore, when
|
||||
* When redefining this method, make sure to redefine {@link #invalidateValidityAndDistanceCaches(GPSFix)}
|
||||
* accordingly. This implementation checks the immediate previous and next fix for <code>e</code>. Therefore, when
|
||||
* adding a fix, only immediately adjacent fix's validity caches need to be invalidated.
|
||||
* <p>
|
||||
*
|
||||
* The fix <code>e</code> is considered valid if at least one of its (not necessarily immediate) neighbors that is
|
||||
* within the range of {@link #getMillisecondsOverWhichToAverageSpeed()} is in reach with less than
|
||||
* {@link #maxSpeedForSmoothing}, or if there are no neighbors with the time range defined by
|
||||
* {@link #getMillisecondsOverWhichToAverageSpeed()}.
|
||||
*/
|
||||
protected boolean isValid(NavigableSet<FixType> rawFixes, FixType e) {
|
||||
assertReadLock();
|
||||
boolean result;
|
||||
boolean isValid;
|
||||
if (maxSpeedForSmoothing == null) {
|
||||
result = true;
|
||||
isValid = true;
|
||||
} else {
|
||||
if (e.isValidityCached()) {
|
||||
result = e.isValid();
|
||||
isValid = e.isValid();
|
||||
} else {
|
||||
FixType previous = rawFixes.lower(e);
|
||||
FixType next = rawFixes.higher(e);
|
||||
Speed speedToPrevious = Speed.NULL;
|
||||
if (previous != null) {
|
||||
final boolean atLeastOnePreviousFixInRange = previous != null && e.getTimePoint().asMillis() - previous.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed();
|
||||
Speed speedToPrevious = null;
|
||||
boolean foundValidPreviousFixInRange = false;
|
||||
while (previous != null && !foundValidPreviousFixInRange && e.getTimePoint().asMillis() - previous.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
speedToPrevious = previous.getPosition().getDistance(e.getPosition())
|
||||
.inTime(e.getTimePoint().asMillis() - previous.getTimePoint().asMillis());
|
||||
foundValidPreviousFixInRange = speedToPrevious.compareTo(maxSpeedForSmoothing) <= 0;
|
||||
previous = rawFixes.lower(previous);
|
||||
}
|
||||
Speed speedToNext = Speed.NULL;
|
||||
if (next != null) {
|
||||
speedToNext = e.getPosition().getDistance(next.getPosition())
|
||||
.inTime(next.getTimePoint().asMillis() - e.getTimePoint().asMillis());
|
||||
boolean foundValidNextFixInRange = false;
|
||||
boolean atLeastOneNextFixInRange = false;
|
||||
if (!foundValidPreviousFixInRange) {
|
||||
FixType next = rawFixes.higher(e);
|
||||
atLeastOneNextFixInRange = next != null && next.getTimePoint().asMillis() - e.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed();
|
||||
Speed speedToNext = null;
|
||||
while (next != null && !foundValidNextFixInRange && next.getTimePoint().asMillis() - e.getTimePoint().asMillis() <= getMillisecondsOverWhichToAverageSpeed()) {
|
||||
speedToNext = e.getPosition().getDistance(next.getPosition())
|
||||
.inTime(next.getTimePoint().asMillis() - e.getTimePoint().asMillis());
|
||||
foundValidNextFixInRange = speedToNext.compareTo(maxSpeedForSmoothing) <= 0;
|
||||
next = rawFixes.higher(next);
|
||||
}
|
||||
}
|
||||
result = ((previous == null || speedToPrevious.compareTo(maxSpeedForSmoothing) <= 0) || (next == null || speedToNext
|
||||
.compareTo(maxSpeedForSmoothing) <= 0));
|
||||
e.cacheValidity(result);
|
||||
isValid = (!atLeastOnePreviousFixInRange || foundValidPreviousFixInRange) || (!atLeastOneNextFixInRange || foundValidNextFixInRange);
|
||||
e.cacheValidity(isValid);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user