mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-30 17:36:40 +00:00
use confidences when splitting a bearing cluster
This commit is contained in:
1 parent
cc55bdd422
commit
354013be1a
5 files changed
+54
-17
No files matched your search
+1
-1
@@ -23,7 +23,7 @@ public class ConfidenceBasedAveragerFactoryImpl implements ConfidenceFactory {
|
||||
|
||||
@Override
|
||||
public Weigher<TimePoint> createLinearTimeDifferenceWeigher(long halfConfidenceAfterMilliseconds) {
|
||||
return new LinearTimeDifferenceWeigher(halfConfidenceAfterMilliseconds);
|
||||
return new HyperbolicTimeDifferenceWeigher(halfConfidenceAfterMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@ package com.sap.sailing.domain.confidence.impl;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.confidence.Weigher;
|
||||
|
||||
public class LinearTimeDifferenceWeigher implements Weigher<TimePoint> {
|
||||
public class HyperbolicTimeDifferenceWeigher implements Weigher<TimePoint> {
|
||||
private final long halfConfidenceAfterMilliseconds;
|
||||
|
||||
public LinearTimeDifferenceWeigher(long halfConfidenceAfterMilliseconds) {
|
||||
public HyperbolicTimeDifferenceWeigher(long halfConfidenceAfterMilliseconds) {
|
||||
this.halfConfidenceAfterMilliseconds = halfConfidenceAfterMilliseconds;
|
||||
}
|
||||
|
||||
+16
-3
@@ -92,15 +92,22 @@ public class BearingWithConfidenceCluster<RelativeTo> {
|
||||
return (BearingWithConfidenceCluster<RelativeTo>[]) new BearingWithConfidenceCluster<?>[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* To avoid that a bearing with low confidence decides about the clustering, the difference between two bearings
|
||||
* is scaled by their confidences. This scaled distance is then maximized for those bearings at least
|
||||
* <code>minimumDegreeDifferenceBetweenTacks</code> degrees apart.
|
||||
*/
|
||||
private Pair<BearingWithConfidence<RelativeTo>, BearingWithConfidence<RelativeTo>> getExtremeBearings(double minimumDegreeDifferenceBetweenTacks) {
|
||||
assert bearings.size() >= 2;
|
||||
double maxAbsDegDiff = minimumDegreeDifferenceBetweenTacks;
|
||||
double maxAbsDegDiff = 0;
|
||||
Pair<BearingWithConfidence<RelativeTo>, BearingWithConfidence<RelativeTo>> result = null;
|
||||
for (int i=0; i<bearings.size(); i++) {
|
||||
for (int j=i+1; j<bearings.size(); j++) {
|
||||
if (Math.abs(bearings.get(i).getObject().getDifferenceTo(bearings.get(j).getObject()).getDegrees()) >= maxAbsDegDiff) {
|
||||
final double confidenceScaledDifference = getConfidenceScaledDifference(bearings.get(i), bearings.get(j));
|
||||
if (Math.abs(bearings.get(i).getObject().getDifferenceTo(bearings.get(j).getObject()).getDegrees()) >= minimumDegreeDifferenceBetweenTacks
|
||||
&& confidenceScaledDifference > maxAbsDegDiff) {
|
||||
result = new Pair<BearingWithConfidence<RelativeTo>, BearingWithConfidence<RelativeTo>>(bearings.get(i), bearings.get(j));
|
||||
maxAbsDegDiff = Math.abs(bearings.get(i).getObject().getDifferenceTo(bearings.get(j).getObject()).getDegrees());
|
||||
maxAbsDegDiff = confidenceScaledDifference;
|
||||
assert Math.abs(bearings.get(i).getObject().getDifferenceTo(bearings.get(j).getObject()).getDegrees()) <= 180.;
|
||||
}
|
||||
}
|
||||
@@ -108,6 +115,12 @@ public class BearingWithConfidenceCluster<RelativeTo> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private double getConfidenceScaledDifference(BearingWithConfidence<RelativeTo> bearingWithConfidence1,
|
||||
BearingWithConfidence<RelativeTo> bearingWithConfidence2) {
|
||||
return bearingWithConfidence1.getObject().getDifferenceTo(bearingWithConfidence2.getObject()).getDegrees() *
|
||||
bearingWithConfidence1.getConfidence() * bearingWithConfidence2.getConfidence();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return bearings.isEmpty();
|
||||
}
|
||||
|
||||
+3
-2
@@ -57,7 +57,7 @@ import com.sap.sailing.domain.confidence.ConfidenceBasedAverager;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceFactory;
|
||||
import com.sap.sailing.domain.confidence.HasConfidence;
|
||||
import com.sap.sailing.domain.confidence.Weigher;
|
||||
import com.sap.sailing.domain.confidence.impl.LinearTimeDifferenceWeigher;
|
||||
import com.sap.sailing.domain.confidence.impl.HyperbolicTimeDifferenceWeigher;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
@@ -191,6 +191,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
windTracks.put(trackBasedWindSource, windStore.getWindTrack(trackedEvent, this, trackBasedWindSource, millisecondsOverWhichToAverageWind));
|
||||
WindSource webWindSource = new WindSourceImpl(WindSourceType.WEB);
|
||||
windTracks.put(webWindSource, windStore.getWindTrack(trackedEvent, this, webWindSource, millisecondsOverWhichToAverageWind));
|
||||
// FIXME need to do something to load expedition wind that was stored in DB because no recordWind will be called
|
||||
this.trackedEvent = trackedEvent;
|
||||
competitorRankings = new HashMap<TimePoint, List<Competitor>>();
|
||||
}
|
||||
@@ -792,7 +793,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
// TODO confidences need to be computed not only based on timePoint but also on position: boats far away don't contribute as confidently as boats close by
|
||||
private Map<LegType, BearingWithConfidenceCluster<TimePoint>> clusterBearingsForWindEstimation(TimePoint timePoint,
|
||||
Position position, DummyMarkPassingWithTimePointOnly dummyMarkPassingForNow, Weigher<TimePoint> weigher) {
|
||||
Weigher<TimePoint> weigherForMarkPassingProximity = new LinearTimeDifferenceWeigher(getMillisecondsOverWhichToAverageSpeed()*5);
|
||||
Weigher<TimePoint> weigherForMarkPassingProximity = new HyperbolicTimeDifferenceWeigher(getMillisecondsOverWhichToAverageSpeed()*5);
|
||||
Map<LegType, BearingWithConfidenceCluster<TimePoint>> bearings = new HashMap<LegType, BearingWithConfidenceCluster<TimePoint>>();
|
||||
for (LegType legType : LegType.values()) {
|
||||
bearings.put(legType, new BearingWithConfidenceCluster<TimePoint>(weigher));
|
||||
|
||||
+32
-9
@@ -47,7 +47,7 @@ import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
public class WindChart implements Component<WindChartSettings>, RaceSelectionChangeListener, TimeListener {
|
||||
private static final int LINE_WIDTH = 1;
|
||||
private final StringMessages stringMessages;
|
||||
private final Set<WindSourceType> windSourcesToDisplay;
|
||||
private final Set<WindSourceType> windSourceTypesToDisplay;
|
||||
|
||||
/**
|
||||
* Holds one series for each wind source for which data has been received.
|
||||
@@ -84,7 +84,7 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
this.windSourceDirectionSeries = new HashMap<WindSource, Series>();
|
||||
this.windSourceSpeedSeries = new HashMap<WindSource, Series>();
|
||||
this.colorMap = new ColorMap<WindSource>();
|
||||
this.windSourcesToDisplay = new HashSet<WindSourceType>();
|
||||
this.windSourceTypesToDisplay = new HashSet<WindSourceType>();
|
||||
this.timer = timer;
|
||||
chart = new Chart()
|
||||
.setZoomType(Chart.ZoomType.X)
|
||||
@@ -143,7 +143,7 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
visible.add(series);
|
||||
}
|
||||
for (Map.Entry<WindSource, Series> e : windSourceDirectionSeries.entrySet()) {
|
||||
if (windSourcesToDisplay.contains(e.getKey().getType())) {
|
||||
if (windSourceTypesToDisplay.contains(e.getKey().getType())) {
|
||||
if (!visible.contains(e.getValue())) {
|
||||
chart.addSeries(e.getValue());
|
||||
} else {
|
||||
@@ -152,7 +152,7 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
}
|
||||
}
|
||||
for (Map.Entry<WindSource, Series> e : windSourceSpeedSeries.entrySet()) {
|
||||
if (windSourcesToDisplay.contains(e.getKey().getType())) {
|
||||
if (windSourceTypesToDisplay.contains(e.getKey().getType())) {
|
||||
if (!visible.contains(e.getValue())) {
|
||||
chart.addSeries(e.getValue());
|
||||
} else {
|
||||
@@ -165,15 +165,26 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the series for the <code>windSource</code> specified. If the series is created and needs to be visible
|
||||
* based on the {@link #windSourceTypesToDisplay}, it is added to the chart.
|
||||
*/
|
||||
private Series getOrCreateSpeedSeries(WindSource windSource) {
|
||||
Series result = windSourceSpeedSeries.get(windSource);
|
||||
if (result == null) {
|
||||
result = createSpeedSeries(windSource);
|
||||
windSourceSpeedSeries.put(windSource, result);
|
||||
if (windSourceTypesToDisplay.contains(windSource.getType())) {
|
||||
chart.addSeries(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only creates the series but doesn't add it to the chart. See also {@link #getOrCreateDirectionSeries(WindSource)} and
|
||||
* {@link #showVisibleSeries()}
|
||||
*/
|
||||
private Series createDirectionSeries(WindSource windSource) {
|
||||
Series newSeries = chart
|
||||
.createSeries()
|
||||
@@ -184,6 +195,10 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
return newSeries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only creates the series but doesn't add it to the chart. See also {@link #getOrCreateSpeedSeries(WindSource)} and
|
||||
* {@link #showVisibleSeries()}
|
||||
*/
|
||||
private Series createSpeedSeries(WindSource windSource) {
|
||||
Series newSeries = chart
|
||||
.createSeries()
|
||||
@@ -206,6 +221,7 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
WindSource windSource = e.getKey();
|
||||
Series directionSeries = getOrCreateDirectionSeries(windSource);
|
||||
Series speedSeries = getOrCreateSpeedSeries(windSource);
|
||||
// FIXME probably need to add the series to the chart...
|
||||
WindTrackInfoDTO windTrackInfo = e.getValue();
|
||||
Point[] directionPoints = new Point[windTrackInfo.windFixes.size()];
|
||||
Point[] speedPoints = new Point[windTrackInfo.windFixes.size()];
|
||||
@@ -252,7 +268,7 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<WindChartSettings> getSettingsDialogComponent() {
|
||||
return new WindChartSettingsDialogComponent(new WindChartSettings(windSourcesToDisplay));
|
||||
return new WindChartSettingsDialogComponent(new WindChartSettings(windSourceTypesToDisplay));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,26 +277,33 @@ public class WindChart implements Component<WindChartSettings>, RaceSelectionCha
|
||||
*/
|
||||
@Override
|
||||
public void updateSettings(WindChartSettings newSettings) {
|
||||
windSourcesToDisplay.clear();
|
||||
windSourcesToDisplay.addAll(newSettings.getWindSourceTypesToDisplay());
|
||||
windSourceTypesToDisplay.clear();
|
||||
windSourceTypesToDisplay.addAll(newSettings.getWindSourceTypesToDisplay());
|
||||
chart.removeAllSeries(/* redraw */ false);
|
||||
for (Map.Entry<WindSource, Series> e : windSourceDirectionSeries.entrySet()) {
|
||||
if (windSourcesToDisplay.contains(e.getKey().getType())) {
|
||||
if (windSourceTypesToDisplay.contains(e.getKey().getType())) {
|
||||
chart.addSeries(e.getValue());
|
||||
}
|
||||
}
|
||||
for (Map.Entry<WindSource, Series> e : windSourceDirectionSeries.entrySet()) {
|
||||
if (windSourcesToDisplay.contains(e.getKey().getType())) {
|
||||
if (windSourceTypesToDisplay.contains(e.getKey().getType())) {
|
||||
chart.addSeries(e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the series for the <code>windSource</code> specified. If the series is created and needs to be visible
|
||||
* based on the {@link #windSourceTypesToDisplay}, it is added to the chart.
|
||||
*/
|
||||
private Series getOrCreateDirectionSeries(WindSource windSource) {
|
||||
Series result = windSourceDirectionSeries.get(windSource);
|
||||
if (result == null) {
|
||||
result = createDirectionSeries(windSource);
|
||||
windSourceDirectionSeries.put(windSource, result);
|
||||
if (windSourceTypesToDisplay.contains(windSource.getType())) {
|
||||
chart.addSeries(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user