java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseChangeBasedTrackApproximationTest.java
... ...
@@ -37,7 +37,7 @@ public class CourseChangeBasedTrackApproximationTest {
37 37
final CompetitorWithBoat competitor = TrackBasedTest.createCompetitorWithBoat("Someone");
38 38
track = new DynamicGPSFixMovingTrackImpl<Competitor>(competitor,
39 39
/* millisecondsOverWhichToAverage */5000, /* lossless compaction */true);
40
- approximation = new CourseChangeBasedTrackApproximation(track, competitor.getBoat().getBoatClass());
40
+ approximation = new CourseChangeBasedTrackApproximation(track, competitor.getBoat().getBoatClass(), /* logFixes */ false);
41 41
}
42 42
43 43
@Test
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseChangeBasedTrackApproximationWithTracTracDataTest.java
... ...
@@ -8,7 +8,7 @@ import java.net.MalformedURLException;
8 8
import java.net.URI;
9 9
import java.net.URISyntaxException;
10 10
import java.net.URL;
11
-import java.util.Random;
11
+import java.util.Iterator;
12 12
13 13
import org.junit.jupiter.api.BeforeEach;
14 14
import org.junit.jupiter.api.Test;
... ...
@@ -44,7 +44,9 @@ public class CourseChangeBasedTrackApproximationWithTracTracDataTest extends Onl
44 44
assertFalse(Util.isEmpty(getTrackedRace().getRace().getCompetitors()));
45 45
do {
46 46
competitors = getTrackedRace().getRace().getCompetitors();
47
- sampleCompetitor = (CompetitorWithBoat) Util.get(competitors, new Random().nextInt(Util.size(competitors)));
47
+ sampleCompetitor = (CompetitorWithBoat) Util.first(Util.filter(competitors, c->c.getName().equals("Anton"))); // TODO "Anton" was offending for fixes indexed 71-73 (0-based)
48
+ short TODO;
49
+// sampleCompetitor = (CompetitorWithBoat) Util.get(competitors, new Random().nextInt(Util.size(competitors)));
48 50
sampleTrack = getTrackedRace().getTrack(sampleCompetitor);
49 51
} while (sampleTrack.isEmpty());
50 52
}
... ...
@@ -68,9 +70,10 @@ public class CourseChangeBasedTrackApproximationWithTracTracDataTest extends Onl
68 70
final DynamicGPSFixTrack<Competitor, GPSFixMoving> trackCopy = new DynamicGPSFixMovingTrackImpl<Competitor>(
69 71
sampleCompetitor,
70 72
/* millisecondsOverWhichToAverage */ boatClass.getApproximateManeuverDurationInMilliseconds());
71
- final CourseChangeBasedTrackApproximation earlyInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass());
73
+ final CourseChangeBasedTrackApproximation earlyInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass(), /* logFixes */ true);
72 74
final TimePoint from = sampleTrack.getFirstRawFix().getTimePoint();
73 75
final TimePoint to = sampleTrack.getLastRawFix().getTimePoint();
76
+ System.out.println("approxId,fixTimeMillis,validityCached,speedCached,COG,SOG");
74 77
sampleTrack.lockForRead();
75 78
try {
76 79
for (final GPSFixMoving fix : sampleTrack.getRawFixes()) {
... ...
@@ -79,10 +82,19 @@ public class CourseChangeBasedTrackApproximationWithTracTracDataTest extends Onl
79 82
} finally {
80 83
sampleTrack.unlockAfterRead();
81 84
}
82
- final CourseChangeBasedTrackApproximation lateInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass());
85
+ final CourseChangeBasedTrackApproximation lateInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass(), /* logFixes */ true);
83 86
assertEquals(earlyInitApproximation.getNumberOfFixesAdded(), lateInitApproximation.getNumberOfFixesAdded(), "Number of fixes added to approximators differs");
84 87
final Iterable<GPSFixMoving> earlyInitResult = earlyInitApproximation.approximate(from, to);
85 88
final Iterable<GPSFixMoving> lateInitResult = lateInitApproximation.approximate(from, to);
89
+ final Iterator<GPSFixMoving> earlyIter = earlyInitResult.iterator();
90
+ final Iterator<GPSFixMoving> lateIter = lateInitResult.iterator();
91
+ int i=0;
92
+ while (earlyIter.hasNext() && lateIter.hasNext()) {
93
+ final GPSFixMoving earlyFix = earlyIter.next();
94
+ final GPSFixMoving lateFix = lateIter.next();
95
+ assertEquals(earlyFix.getTimePoint(), lateFix.getTimePoint(), "Time points of approximation fixes differ at index "+i+" for competitor "+sampleCompetitor.getName());
96
+ i++;
97
+ }
86 98
assertEquals(Util.size(earlyInitResult), Util.size(lateInitResult), "Different numbers of approximation points for competitor "+sampleCompetitor.getName());
87 99
assertEquals(Util.asSet(earlyInitResult), Util.asSet(lateInitResult));
88 100
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CourseChangeBasedTrackApproximation.java
... ...
@@ -135,7 +135,15 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
135 135
private final double maneuverAngleInDegreesThreshold;
136 136
private Duration windowDuration;
137 137
138
- FixWindow() {
138
+ /**
139
+ * For debugging purposes, this flag can be set to {@code true} through the constructor, which will then log all
140
+ * fixes' values about estimated COG/SOG when moving from the {@link #queueOfNewFixes} into the {@link #window}.
141
+ * This is particularly helpful to analyze the influence of seeing or not seeing newer fixes on the track.
142
+ */
143
+ private final boolean logFixes;
144
+
145
+ FixWindow(boolean logFixes) {
146
+ this.logFixes = logFixes;
139 147
this.window = new LinkedList<>();
140 148
this.queueOfNewFixes = new LinkedList<>();
141 149
this.speedForFixesInWindow = new LinkedList<>();
... ...
@@ -237,11 +245,18 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
237 245
}
238 246
return result;
239 247
}
240
-
248
+
241 249
private GPSFixMoving addOldEnoughFix(GPSFixMoving next) {
242 250
assert window.isEmpty() || !next.getTimePoint().before(window.peekFirst().getTimePoint());
243 251
final GPSFixMoving result;
244 252
final SpeedWithBearing nextSpeed = next.isEstimatedSpeedCached() ? next.getCachedEstimatedSpeed() : track.getEstimatedSpeed(next.getTimePoint());
253
+ if (logFixes) {
254
+ // CSV logging: approxId, fixIndex, fixTimeMillis, validityCached, speedCached, COG, SOG
255
+ System.out.println(System.identityHashCode(this) + "," + next.getTimePoint().asMillis() + ","
256
+ + next.isValidityCached() + "," + next.isEstimatedSpeedCached() + ","
257
+ + (nextSpeed == null ? "null" : nextSpeed.getBearing().getDegrees()) + ","
258
+ + (nextSpeed == null ? "null" : nextSpeed.getKnots()));
259
+ }
245 260
if (nextSpeed != null) {
246 261
numberOfFixesAdded++;
247 262
int insertPosition = window.size();
... ...
@@ -398,15 +413,15 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
398 413
}
399 414
}
400 415
401
- public CourseChangeBasedTrackApproximation(GPSFixTrack<Competitor, GPSFixMoving> track, BoatClass boatClass) {
416
+ public CourseChangeBasedTrackApproximation(GPSFixTrack<Competitor, GPSFixMoving> track, BoatClass boatClass, boolean logFixes) {
402 417
this.track = track;
403 418
this.boatClass = boatClass;
404
- this.fixWindow = new FixWindow();
419
+ this.fixWindow = new FixWindow(logFixes);
405 420
this.maneuverCandidates = new TreeSet<>(TimedComparator.INSTANCE);
406 421
track.addListener(this);
407 422
addAllFixesOfTrack();
408 423
}
409
-
424
+
410 425
/**
411 426
* Defined only in order to make it {@code synchronized} so that data will be written to the output stream
412 427
* consistently.
... ...
@@ -459,7 +474,7 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
459 474
if (fixWindow.isAtOrAfterFirst(fix.getTimePoint())) {
460 475
addFix(fix);
461 476
} else {
462
- final FixWindow outOfOrderWindow = new FixWindow();
477
+ final FixWindow outOfOrderWindow = new FixWindow(/* logFixes */ false);
463 478
final Duration maximumWindowLength = outOfOrderWindow.getMaximumWindowLength();
464 479
// fix is an out-of-order delivery; construct a new FixWindow and analyze the track around the new fix.
465 480
// A time range around the fix is constructed that will be re-scanned. The time range covers at least
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java
... ...
@@ -631,11 +631,15 @@ public abstract class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends
631 631
ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
632 632
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
633 633
getMillisecondsOverWhichToAverageSpeed() / 2, /* minimumConfidence */ 0.00000001)); // half confidence if half averaging interval apart
634
- result = estimatedSpeed == null ? null : estimatedSpeed.getObject();
635 634
if (estimatedSpeed != null) {
636 635
if (ceil != null && ceil.getTimePoint().equals(at)) {
637
- ceil.cacheEstimatedSpeed(result);
636
+ ceil.cacheEstimatedSpeed(estimatedSpeed.getObject());
637
+ result = ceil.getCachedEstimatedSpeed(); // this way, should the fix apply compaction, we will still return consistent (compacted) results
638
+ } else {
639
+ result = estimatedSpeed.getObject();
638 640
}
641
+ } else {
642
+ result = null;
639 643
}
640 644
}
641 645
if (logger.isLoggable(Level.FINEST) && (estimatedSpeedCacheHits + estimatedSpeedCacheMisses) % 1000 == 0) {
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
... ...
@@ -585,7 +585,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
585 585
markPassingsForCompetitor.put(competitor, new ConcurrentSkipListSet<MarkPassing>(MarkPassingByTimeComparator.INSTANCE));
586 586
final DynamicGPSFixMovingTrackImpl<Competitor> track = new DynamicGPSFixMovingTrackImpl<Competitor>(competitor, millisecondsOverWhichToAverageSpeed);
587 587
tracks.put(competitor, track);
588
- maneuverApproximators.put(competitor, new CourseChangeBasedTrackApproximation(track, race.getBoatOfCompetitor(competitor).getBoatClass()));
588
+ maneuverApproximators.put(competitor, new CourseChangeBasedTrackApproximation(track, race.getBoatOfCompetitor(competitor).getBoatClass(), /* logFixes */ false));
589 589
}
590 590
markPassingsForWaypoint = new ConcurrentHashMap<Waypoint, NavigableSet<MarkPassing>>();
591 591
for (Waypoint waypoint : race.getCourse().getWaypoints()) {