From 8f671b7010a1b11644e6bcad4832c11c852935d4 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 15 Aug 2013 12:43:55 +0200 Subject: [PATCH] working towards an improved outlier detection which also captures testJumpyFixes properly --- .../impl/DynamicGPSFixMovingTrackImpl.java | 70 ++++++++++--------- .../domain/tracking/impl/GPSFixTrackImpl.java | 48 ++++++++----- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java index 77a8c2ab4c5..08656764476 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java @@ -95,60 +95,62 @@ public class DynamicGPSFixMovingTrackImpl extends DynamicTrackImpl 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; } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java index 174eda0e009..0fd44723bae 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java @@ -794,37 +794,53 @@ public class GPSFixTrackImpl extends TrackImpl } /** - * When redefining this method, make sure to redefine {@link #invalidateValidityAndDistanceCaches(GPSFix)} accordingly. - * This implementation checks the immediate previous and next fix for e. Therefore, when + * When redefining this method, make sure to redefine {@link #invalidateValidityAndDistanceCaches(GPSFix)} + * accordingly. This implementation checks the immediate previous and next fix for e. Therefore, when * adding a fix, only immediately adjacent fix's validity caches need to be invalidated. + *

+ * + * The fix e 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 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; } /**