mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-28 08:26:44 +00:00
added test cases for confidence-based suppressing of fixes near mark passings and ancient fixes
This commit is contained in:
+38
-17
@@ -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()));
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-2
@@ -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\=\=
|
||||
|
||||
Reference in New Issue
Block a user