added test cases for confidence-based suppressing of fixes near mark passings and ancient fixes

This commit is contained in:
Axel Uhl
2012-02-02 21:39:50 +01:00
parent 7d25df76e7
commit 37f6e62c7d
5 changed files with 63 additions and 23 deletions
@@ -102,12 +102,11 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
*/
@Test
public void testWindEstimationCacheInvalidationAfterLegTypeChange() throws NoWindException {
MillisecondsTimePoint fixTime = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
TimePoint fixTime = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
TimePoint checkTime = new MillisecondsTimePoint(fixTime.asMillis()+60000); // one minute later
initRace(2, new int[] { 1, 1 }, fixTime);
getTrackedRace().setRaceIsKnownToStartUpwind(false); // use only WEB wind to determine leg type
TimePoint now = getTrackedRace()
.getMarkPassingsInOrder(getTrackedRace().getRace().getCourse().getFirstWaypoint()).iterator().next()
.getTimePoint();
TimePoint now = checkTime;
setBearingForCompetitor(competitors.get(0), now, 320);
setBearingForCompetitor(competitors.get(1), now, 50);
TrackedLeg firstLeg = getTrackedRace().getTrackedLeg(getTrackedRace().getRace().getCourse().getLegs().iterator().next());
@@ -123,7 +122,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
}
}
};
Wind estimatedWindDirection = track.getEstimatedWind(/* position */ null, fixTime);
Wind estimatedWindDirection = track.getEstimatedWind(/* position */ null, checkTime);
assertNotNull(estimatedWindDirection);
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
assertFalse(cachedFixes.isEmpty());
@@ -132,14 +131,14 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
Iterator<Waypoint> waypointsIter = getTrackedRace().getRace().getCourse().getWaypoints().iterator();
Waypoint leewardMark = waypointsIter.next();
Waypoint windwardMark = waypointsIter.next();
Position leewardGatePosition = getTrackedRace().getApproximatePosition(leewardMark, fixTime);
Position leewardGatePosition = getTrackedRace().getApproximatePosition(leewardMark, checkTime);
Distance d = new NauticalMileDistance(1);
Wind wind = getTrackedRace().getWind(null, fixTime, WindSource.TRACK_BASED_ESTIMATION);
Wind wind = getTrackedRace().getWind(null, checkTime, WindSource.TRACK_BASED_ESTIMATION);
Position newWindwardMarkPosition = leewardGatePosition.translateGreatCircle(wind.getBearing(), d);
getTrackedRace().getOrCreateTrack(windwardMark.getBuoys().iterator().next()).addGPSFix(
new GPSFixImpl(newWindwardMarkPosition, fixTime));
new GPSFixImpl(newWindwardMarkPosition, checkTime));
assertEquals(LegType.DOWNWIND, firstLeg.getLegType(fixTime));
Wind estimatedWindDirectionDownwind = track.getEstimatedWind(/* position */ null, fixTime);
Wind estimatedWindDirectionDownwind = track.getEstimatedWind(/* position */ null, checkTime);
assertNotNull(estimatedWindDirectionDownwind);
assertEquals(5., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.00000001);
}
@@ -147,12 +146,11 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
@Test
public void testWindEstimationCaching() {
MillisecondsTimePoint fixTime = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
TimePoint checkTime = new MillisecondsTimePoint(fixTime.asMillis()+60000); // one minute later
initRace(2, new int[] { 1, 1 }, fixTime);
TimePoint now = getTrackedRace()
.getMarkPassingsInOrder(getTrackedRace().getRace().getCourse().getFirstWaypoint()).iterator().next()
.getTimePoint();
setBearingForCompetitor(competitors.get(0), now, 320);
setBearingForCompetitor(competitors.get(1), now, 50);
TimePoint now = checkTime;
setBearingForCompetitor(competitors.get(0), checkTime, 320);
setBearingForCompetitor(competitors.get(1), checkTime, 50);
final Map<TimePoint, Wind> cachedFixes = new HashMap<TimePoint, Wind>();
TrackBasedEstimationWindTrackImpl track = new TrackBasedEstimationWindTrackImpl(
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000) {
@@ -164,21 +162,21 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
}
}
};
Wind estimatedWindDirection = track.getEstimatedWind(/* position */ null, fixTime);
Wind estimatedWindDirection = track.getEstimatedWind(/* position */ null, checkTime);
assertNotNull(estimatedWindDirection);
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
assertFalse(cachedFixes.isEmpty());
assertEquals(185., cachedFixes.values().iterator().next().getBearing().getDegrees(), 0.00000001);
// now clear set of cached fixes, ask again and ensure nothing is cached again:
cachedFixes.clear();
Wind estimatedWindDirectionCached = track.getEstimatedWind(/* position */ null, fixTime);
Wind estimatedWindDirectionCached = track.getEstimatedWind(/* position */ null, checkTime);
assertTrue(cachedFixes.isEmpty());
assertNotNull(estimatedWindDirectionCached);
assertEquals(185., estimatedWindDirectionCached.getBearing().getDegrees(), 0.00000001);
// now add a GPS fix and make sure the cache is invalidated
now = MillisecondsTimePoint.now();
setBearingForCompetitor(competitors.get(0), now, 330);
Wind estimatedWindDirectionNew = track.getEstimatedWind(/* position */ null, fixTime);
Wind estimatedWindDirectionNew = track.getEstimatedWind(/* position */ null, checkTime);
assertFalse(cachedFixes.isEmpty());
assertNotNull(estimatedWindDirectionNew);
assertTrue("Expected estimated wind direction to now be greater than 185 degrees but was "
@@ -196,6 +194,29 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
}
@Test
public void testWindEstimationForSimpleTracksWithOneAncientFixToBeSuppressedByLowConfidence() throws NoWindException {
initRace(3, new int[] { 1, 1, 1 }, new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime()));
MillisecondsTimePoint now = MillisecondsTimePoint.now();
setBearingForCompetitor(competitors.get(0), now, 320);
setBearingForCompetitor(competitors.get(1), now, 50);
setBearingForCompetitor(competitors.get(2), new MillisecondsTimePoint(0), 100); // this shouldn't disturb the estimation because it's too old
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(/* position */ null, now);
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
}
@Test
public void testWindEstimationForSimpleTracksWithOneFixNearMarkPassingToBeSuppressedByLowConfidence() throws NoWindException {
TimePoint markPassingTimePoint = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
initRace(3, new int[] { 1, 1, 1 }, markPassingTimePoint);
MillisecondsTimePoint now = MillisecondsTimePoint.now();
setBearingForCompetitor(competitors.get(0), now, 320);
setBearingForCompetitor(competitors.get(1), now, 50);
setBearingForCompetitor(competitors.get(2), markPassingTimePoint, 100); // this shouldn't disturb the estimation because it's too old
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(/* position */ null, now);
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
}
@Test
public void testWindEstimationForTwoBoatsOnSameTack() throws NoWindException {
initRace(2, new int[] { 1, 1 }, new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime()));
@@ -45,7 +45,7 @@ public class WindEstimationOnStoredTracksTest extends StoredTrackBasedTestWithTr
public void testZeroConfidenceLeadsToNullBearingAverage() {
BearingWithConfidenceCluster<Void> cluster = new BearingWithConfidenceCluster<Void>(null);
cluster.add(new BearingWithConfidenceImpl<Void>(new DegreeBearingImpl(355), /* confidence */ 0., null));
assertNull(cluster.getAverage(null).getObject());
assertNull(cluster.getAverage(null));
}
@Test
@@ -116,8 +116,13 @@ public class BearingWithConfidenceCluster<RelativeTo> {
return bearings.size();
}
/**
* Adds the <code>bearing</code> if its {@link BearingWithConfidence#getConfidence() confidence} is greater than 0.0
*/
public void add(BearingWithConfidence<RelativeTo> bearing) {
bearings.add(bearing);
if (bearing.getConfidence() > 0) {
bearings.add(bearing);
}
}
/**
@@ -651,6 +651,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public Wind getEstimatedWindDirection(Position position, TimePoint timePoint) {
DummyMarkPassingWithTimePointOnly dummyMarkPassingForNow = new DummyMarkPassingWithTimePointOnly(timePoint);
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed());
@@ -671,13 +672,26 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
if (legType != LegType.REACHING) {
GPSFixTrack<Competitor, GPSFixMoving> track = getTrack(competitor);
// TODO bug #167 could be fixed here by excluding competitors that are x seconds before/after a mark passing
if (!track.hasDirectionChange(timePoint, getManeuverDegreeAngleThreshold())) {
// reduce confidence around mark passings:
NavigableSet<MarkPassing> markPassings = getMarkPassings(competitor);
NavigableSet<MarkPassing> prevMarkPassing = markPassings.headSet(dummyMarkPassingForNow, /* inclusive */ true);
NavigableSet<MarkPassing> nextMarkPassing = markPassings.tailSet(dummyMarkPassingForNow, /* inclusive */ true);
double markPassingProximityConfidenceReduction = 1.0;
if (prevMarkPassing != null && !prevMarkPassing.isEmpty()) {
markPassingProximityConfidenceReduction *= Math.max(0.0,
1.0-weigher.getConfidence(prevMarkPassing.last().getTimePoint(), timePoint));
}
if (nextMarkPassing != null && !nextMarkPassing.isEmpty()) {
markPassingProximityConfidenceReduction *= Math.max(0.0,
1.0-weigher.getConfidence(nextMarkPassing.first().getTimePoint(), timePoint));
}
SpeedWithBearingWithConfidence<TimePoint> estimatedSpeedWithConfidence = track.getEstimatedSpeed(timePoint,
weigher);
if (estimatedSpeedWithConfidence != null) {
BearingWithConfidence<TimePoint> bearing = new BearingWithConfidenceImpl<TimePoint>(
estimatedSpeedWithConfidence.getObject().getBearing(), estimatedSpeedWithConfidence.getConfidence(),
estimatedSpeedWithConfidence.getObject() == null ? null : estimatedSpeedWithConfidence.getObject().getBearing(),
markPassingProximityConfidenceReduction*estimatedSpeedWithConfidence.getConfidence(),
estimatedSpeedWithConfidence.getRelativeTo());
BearingWithConfidenceCluster<TimePoint> bearingClusterForLegType = bearings.get(legType);
bearingClusterForLegType.add(bearing);
@@ -1,5 +1,5 @@
#Thu Feb 02 12:04:27 CET 2012
#Thu Feb 02 18:41:06 CET 2012
eclipse.preferences.version=1
entryPointModules=
filesCopiedToWebInfLib=gwt-servlet.jar
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDUxMm1dXT48L3ZtLWFyZ3M+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDEwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48L2d3dC1jb21waWxlLXNldHRpbmdzPg\=\=