Removed MovingAverage processor from polar data miner

Was only meant for comparison purposes with Regression. Now regression is
used every anyway, so we only need to have the regression processors
This commit is contained in:
Frederik Petersen committed 2015-07-20 17:41:54 +02:00
1 parent e25d10bddb
commit 071a23bc8f
12 files changed
+33 -195

No files matched your search

@@ -7,10 +7,6 @@ import com.sap.sse.common.Util.Pair;
public interface PolarSheetsXYDiagramData extends Serializable { public interface PolarSheetsXYDiagramData extends Serializable {
List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType);
List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType);
List<Pair<Double, Double>> getPointsForAverageSpeedRegression(Tack tack, LegType legType); List<Pair<Double, Double>> getPointsForAverageSpeedRegression(Tack tack, LegType legType);
} }
@@ -14,30 +14,12 @@ public class PolarSheetsXYDiagramDataImpl implements PolarSheetsXYDiagramData {
PolarSheetsXYDiagramDataImpl() { PolarSheetsXYDiagramDataImpl() {
} }
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedMovingAverage;
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedRegression; private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedRegression;
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageConfidence;
public PolarSheetsXYDiagramDataImpl( public PolarSheetsXYDiagramDataImpl(
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists, Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists) {
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists,
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists) {
pointsForAverageSpeedMovingAverage = movingAverageSpeedDataLists;
pointsForAverageSpeedRegression = regressionSpeedDataLists; pointsForAverageSpeedRegression = regressionSpeedDataLists;
pointsForAverageConfidence = averageConfidenceDataLists;
}
@Override
public List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType) {
return pointsForAverageSpeedMovingAverage.get(new Pair<LegType, Tack>(legType, tack));
}
@Override
public List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType) {
return pointsForAverageConfidence.get(new Pair<LegType, Tack>(legType, tack));
} }
@Override @Override
@@ -52,36 +52,6 @@ public interface PolarDataService {
SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle) SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle)
throws NotEnoughDataHasBeenAddedException; throws NotEnoughDataHasBeenAddedException;
/**
*
* @param boatClass
* @param windSpeed
* @param legType
* Should be {@link LegType#UPWIND} or {@link LegType#DOWNWIND}, there is no information for other
* courses yet. Use getSpeed for the desired angle to get rawer information on other courses for now.
* @param tack
* Polar data can vary depending on the tack the boat is on.
* @param useRegressionForSpeed TODO
* @return The estimated average speed of a boat for the supplied parameters with the estimated average bearing to
* the true wind and a confidence which consists of the confidences of the wind speed, and boat speed sources (50%)
* and a confidence calculated using the amount of underlying fixes (50%). 0 <= confidence < 1<br/>
* A value with zero confidence doesn't have any significance!<br/>
* <br/>
*
* The bearing is somewhere between -179 to +180<br/>
* <br/>
*
* Get the speed using returnValue.getObject()<br/>
* <br/>
*
* Returns null if the leg type is not up or downwind.
*
* @throws NotEnoughDataHasBeenAddedException
* If there is not enough data to supply a value with some kind of significance.
*/
SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException;
/** /**
* Generates a polar sheet for given races and settings using the provided executor for the worker threads. This * Generates a polar sheet for given races and settings using the provided executor for the worker threads. This
@@ -4,12 +4,9 @@ import java.util.List;
import org.moxieapps.gwt.highcharts.client.AxisTitle; import org.moxieapps.gwt.highcharts.client.AxisTitle;
import org.moxieapps.gwt.highcharts.client.Chart; import org.moxieapps.gwt.highcharts.client.Chart;
import org.moxieapps.gwt.highcharts.client.PlotLine;
import org.moxieapps.gwt.highcharts.client.Point; import org.moxieapps.gwt.highcharts.client.Point;
import org.moxieapps.gwt.highcharts.client.Series; import org.moxieapps.gwt.highcharts.client.Series;
import org.moxieapps.gwt.highcharts.client.Series.Type; import org.moxieapps.gwt.highcharts.client.Series.Type;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import org.moxieapps.gwt.highcharts.client.plotOptions.SplinePlotOptions;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
@@ -58,33 +55,14 @@ public class PolarSheetsXYDiagramPopupPanel extends DialogBox {
} }
private void addSpeedAndConfidenceSeriesForTackAndLegType(PolarSheetsXYDiagramData result, Tack tack, LegType legType, boolean showByDefault) { private void addSpeedAndConfidenceSeriesForTackAndLegType(PolarSheetsXYDiagramData result, Tack tack, LegType legType, boolean showByDefault) {
Point[] pointsForUpwindStarboardAverageSpeedMovingAverage = toPointArray(result.getPointsForAverageSpeedMovingAverage(tack, legType));
Series speedSeriesMovingAverage = chart.createSeries();
speedSeriesMovingAverage.setName(tack + " " + legType + " Speed - MovingAverage");
speedSeriesMovingAverage.setPoints(pointsForUpwindStarboardAverageSpeedMovingAverage);
chart.addSeries(speedSeriesMovingAverage, false, false);
Point[] pointsForUpwindStarboardAverageSpeedRegression = toPointArray(result.getPointsForAverageSpeedRegression(tack, legType)); Point[] pointsForUpwindStarboardAverageSpeedRegression = toPointArray(result.getPointsForAverageSpeedRegression(tack, legType));
Series speedSeriesRegression = chart.createSeries(); Series speedSeriesRegression = chart.createSeries();
speedSeriesRegression.setName(tack + " " + legType + " Speed - Regression"); speedSeriesRegression.setName(tack + " " + legType + " Speed - Regression");
speedSeriesRegression.setPoints(pointsForUpwindStarboardAverageSpeedRegression); speedSeriesRegression.setPoints(pointsForUpwindStarboardAverageSpeedRegression);
chart.addSeries(speedSeriesRegression, false, false); chart.addSeries(speedSeriesRegression, false, false);
Point[] pointsForUpwindStarboardAverageConfidence = toPointArray(result.getPointsForAverageConfidence(tack, legType));
Series confidenceSeries = chart
.createSeries()
.setYAxis(1)
.setType(Series.Type.SPLINE)
.setPlotOptions(
new SplinePlotOptions().setColor("#AA4643").setMarker(new Marker().setEnabled(false))
.setDashStyle(PlotLine.DashStyle.SHORT_DOT));
confidenceSeries.setName(tack + " " + legType + " Confidence");
confidenceSeries.setPoints(pointsForUpwindStarboardAverageConfidence);
chart.addSeries(confidenceSeries, false, false);
if (!showByDefault) { if (!showByDefault) {
speedSeriesRegression.setVisible(false, false); speedSeriesRegression.setVisible(false, false);
confidenceSeries.setVisible(false, false);
} }
} }
@@ -61,10 +61,10 @@ import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent; import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer; import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder; import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder;
@@ -5585,45 +5585,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override @Override
public PolarSheetsXYDiagramData createXYDiagramForBoatClass(String boatClassName) { public PolarSheetsXYDiagramData createXYDiagramForBoatClass(String boatClassName) {
BoatClass boatClass = getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName); BoatClass boatClass = getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName);
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists = new HashMap<>();
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists = new HashMap<>(); Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists = new HashMap<>();
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists = new HashMap<>();
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) { for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) { for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
movingAverageSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>());
regressionSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack), regressionSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>()); new ArrayList<Pair<Double, Double>>());
averageConfidenceDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>());
} }
} }
for (double windInKnots = 0.1; windInKnots < 30; windInKnots = windInKnots + 0.1) { for (double windInKnots = 0.1; windInKnots < 30; windInKnots = windInKnots + 0.1) {
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) { for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) { for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
try {
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardMovingAverage = getService()
.getPolarDataService().getAverageSpeedWithBearing(boatClass,
new KnotSpeedImpl(windInKnots), legType, tack, false);
movingAverageSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage.getObject()
.getKnots()));
averageConfidenceDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage
.getConfidence()));
} catch (NotEnoughDataHasBeenAddedException e) {
// Do not add a point to the result
}
try { try {
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardRegression = getService() SpeedWithBearingWithConfidence<Void> averageUpwindStarboardRegression = getService()
.getPolarDataService().getAverageSpeedWithBearing(boatClass, .getPolarDataService().getAverageSpeedWithBearing(boatClass,
new KnotSpeedImpl(windInKnots), legType, tack, true); new KnotSpeedImpl(windInKnots), legType, tack);
regressionSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add( regressionSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardRegression.getObject() new Pair<Double, Double>(windInKnots, averageUpwindStarboardRegression.getObject()
@@ -5635,8 +5610,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} }
} }
PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(movingAverageSpeedDataLists, PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(regressionSpeedDataLists);
regressionSpeedDataLists, averageConfidenceDataLists);
return data; return data;
} }
@@ -32,7 +32,6 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.PolarSheetGenerationSettings; import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
@@ -52,9 +51,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl; import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
import com.sap.sailing.polars.mining.BearingClusterGroup; import com.sap.sailing.polars.mining.BearingClusterGroup;
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor; import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
import com.sap.sailing.polars.mining.MovingAverageProcessorImpl;
import com.sap.sailing.polars.mining.PolarDataMiner; import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.mining.SpeedClusterGroupFromWindSteppingCreator;
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor; import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
@@ -91,12 +88,9 @@ public class PolarDataMinerTest {
NotEnoughDataHasBeenAddedException { NotEnoughDataHasBeenAddedException {
PolarSheetGenerationSettings settings = createTestPolarSettings(); PolarSheetGenerationSettings settings = createTestPolarSettings();
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup(); ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
WindSpeedSteppingWithMaxDistance stepping = settings.getWindSpeedStepping(); PolarDataMiner miner = new PolarDataMiner(settings,
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
.createSpeedClusterGroupFrom(stepping);
PolarDataMiner miner = new PolarDataMiner(settings, new MovingAverageProcessorImpl(speedClusterGroup),
new CubicRegressionPerCourseProcessor(), new CubicRegressionPerCourseProcessor(),
new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup), speedClusterGroup, angleClusterGroup); new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup), angleClusterGroup);
BoatClass mockedBoatClass = mock(BoatClass.class); BoatClass mockedBoatClass = mock(BoatClass.class);
@@ -33,7 +33,6 @@ import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl; import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.polars.PolarDataService;
@@ -46,9 +45,7 @@ import com.sap.sailing.polars.data.PolarFix;
import com.sap.sailing.polars.generation.PolarSheetGenerator; import com.sap.sailing.polars.generation.PolarSheetGenerator;
import com.sap.sailing.polars.mining.BearingClusterGroup; import com.sap.sailing.polars.mining.BearingClusterGroup;
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor; import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
import com.sap.sailing.polars.mining.MovingAverageProcessorImpl;
import com.sap.sailing.polars.mining.PolarDataMiner; import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.mining.SpeedClusterGroupFromWindSteppingCreator;
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor; import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.data.ClusterGroup; import com.sap.sse.datamining.data.ClusterGroup;
@@ -91,15 +88,11 @@ public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObj
public PolarDataServiceImpl() { public PolarDataServiceImpl() {
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings(); PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings();
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup(); ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
WindSpeedSteppingWithMaxDistance stepping = settings.getWindSpeedStepping();
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
.createSpeedClusterGroupFrom(stepping);
MovingAverageProcessorImpl movingAverageProcessor = new MovingAverageProcessorImpl(speedClusterGroup);
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(); CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor();
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor( SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(
angleClusterGroup); angleClusterGroup);
this.polarDataMiner = new PolarDataMiner(settings, movingAverageProcessor, cubicRegressionPerCourseProcessor, this.polarDataMiner = new PolarDataMiner(settings, cubicRegressionPerCourseProcessor,
speedRegressionPerAngleClusterProcessor, speedClusterGroup, angleClusterGroup); speedRegressionPerAngleClusterProcessor, angleClusterGroup);
this.operationsSentToMasterForReplication = new HashSet<>(); this.operationsSentToMasterForReplication = new HashSet<>();
this.operationExecutionListeners = new ConcurrentHashMap<>(); this.operationExecutionListeners = new ConcurrentHashMap<>();
} }
@@ -124,12 +117,12 @@ public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObj
@Override @Override
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed, public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
if (polarDataMiner == null) { if (polarDataMiner == null) {
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?"); throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
} }
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = polarDataMiner SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = polarDataMiner
.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, useRegressionForSpeed); .getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
if (tack == Tack.PORT) { if (tack == Tack.PORT) {
//Negative twa //Negative twa
DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing() DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing()
@@ -251,19 +244,13 @@ public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObj
if (polarDataMiner == null) { if (polarDataMiner == null) {
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?"); throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
} }
SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, true); SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
Bearing bearing = new DegreeBearingImpl(speed.getObject().getBearing().getDegrees() * 2); Bearing bearing = new DegreeBearingImpl(speed.getObject().getBearing().getDegrees() * 2);
BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, speed.getConfidence(), BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, speed.getConfidence(),
null); null);
return bearingWithConfidence; return bearingWithConfidence;
} }
@Override
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
return getAverageSpeedWithBearing(boatClass, windSpeed, legType, tack, true);
}
@Override @Override
public void insertExistingFixes(TrackedRace trackedRace) { public void insertExistingFixes(TrackedRace trackedRace) {
for (Competitor competitor : trackedRace.getRace().getCompetitors()) { for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
@@ -331,19 +318,13 @@ public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObj
public void initiallyFillFromInternal(ObjectInputStream is) throws IOException, ClassNotFoundException, public void initiallyFillFromInternal(ObjectInputStream is) throws IOException, ClassNotFoundException,
InterruptedException { InterruptedException {
PolarSheetGenerationSettings backendPolarSettings = (PolarSheetGenerationSettings) is.readObject(); PolarSheetGenerationSettings backendPolarSettings = (PolarSheetGenerationSettings) is.readObject();
//MovingAverageProcessor movingAverageProcessor = (MovingAverageProcessor) is.readObject();
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings();
WindSpeedSteppingWithMaxDistance stepping = settings.getWindSpeedStepping();
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
.createSpeedClusterGroupFrom(stepping);
MovingAverageProcessorImpl movingAverageProcessor = new MovingAverageProcessorImpl(speedClusterGroup);
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = (CubicRegressionPerCourseProcessor) is.readObject(); CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = (CubicRegressionPerCourseProcessor) is.readObject();
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = (SpeedRegressionPerAngleClusterProcessor) is.readObject(); SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = (SpeedRegressionPerAngleClusterProcessor) is.readObject();
polarDataMiner = new PolarDataMiner(backendPolarSettings, movingAverageProcessor, polarDataMiner = new PolarDataMiner(backendPolarSettings,
cubicRegressionPerCourseProcessor, speedRegressionPerAngleClusterProcessor, cubicRegressionPerCourseProcessor, speedRegressionPerAngleClusterProcessor,
movingAverageProcessor.getSpeedCluster(), speedRegressionPerAngleClusterProcessor.getAngleCluster()); speedRegressionPerAngleClusterProcessor.getAngleCluster());
} }
@Override @Override
@@ -10,7 +10,6 @@ import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
@@ -28,12 +27,11 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.data.ClusterGroup; import com.sap.sse.datamining.data.ClusterGroup;
public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKey, AngleClusterPolarClusterKey { public class GPSFixMovingWithPolarContext implements LegTypePolarClusterKey, AngleClusterPolarClusterKey {
private final GPSFixMoving fix; private final GPSFixMoving fix;
private final TrackedRace race; private final TrackedRace race;
private final Competitor competitor; private final Competitor competitor;
private final ClusterGroup<Speed> windSpeedClusterGroup;
private final Set<WindSource> windSourcesToExcludeForSpeed; private final Set<WindSource> windSourcesToExcludeForSpeed;
private final ClusterGroup<Bearing> angleClusterGroup; private final ClusterGroup<Bearing> angleClusterGroup;
private final BearingWithConfidence<Void> absTrueWindAngle; private final BearingWithConfidence<Void> absTrueWindAngle;
@@ -42,11 +40,10 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private LegType legType; private LegType legType;
public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor, public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor,
ClusterGroup<Speed> windSpeedClusterGroup, ClusterGroup<Bearing> angleClusterGroup) { ClusterGroup<Bearing> angleClusterGroup) {
this.fix = fix; this.fix = fix;
this.race = race; this.race = race;
this.competitor = competitor; this.competitor = competitor;
this.windSpeedClusterGroup = windSpeedClusterGroup;
this.angleClusterGroup = angleClusterGroup; this.angleClusterGroup = angleClusterGroup;
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed(); this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
this.absTrueWindAngle = computeTrueWindAngleAbsolute(); this.absTrueWindAngle = computeTrueWindAngleAbsolute();
@@ -89,12 +86,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
return result; return result;
} }
@Override
public Cluster<Speed> getWindSpeedCluster() {
final WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = getWind();
return windWithConfidence == null ? null : windSpeedClusterGroup.getClusterFor(windWithConfidence.getObject());
}
public WindWithConfidence<Pair<Position, TimePoint>> getWind() { public WindWithConfidence<Pair<Position, TimePoint>> getWind() {
return wind; return wind;
} }
@@ -68,15 +68,9 @@ public class PolarDataMiner {
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners = new ConcurrentHashMap<>(); private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners = new ConcurrentHashMap<>();
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor; private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings; private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
/**
* This processor keeps track of the moving average of the speed values and the average angle for each course (legtype tack combination)
*/
private final MovingAverageProcessor movingAverageProcessor;
/** /**
* This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each * This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each
* course (legtype tack combination) * course (legtype tack combination)
@@ -84,7 +78,6 @@ public class PolarDataMiner {
private final CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor; private final CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
private final SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor; private final SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
private final ClusterGroup<Speed> speedClusterGroup;
private final ClusterGroup<Bearing> angleClusterGroup; private final ClusterGroup<Bearing> angleClusterGroup;
private ThreadPoolExecutor createExecutor() { private ThreadPoolExecutor createExecutor() {
@@ -109,16 +102,15 @@ public class PolarDataMiner {
}; };
} }
public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings, MovingAverageProcessor movingAverageProcessor, public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings,
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor, SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor, CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor,
ClusterGroup<Speed> speedClusterGroup, ClusterGroup<Bearing> angleClusterGroup) { SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor,
ClusterGroup<Bearing> angleClusterGroup) {
cubicRegressionPerCourseProcessor.setListeners(listeners); cubicRegressionPerCourseProcessor.setListeners(listeners);
speedRegressionPerAngleClusterProcessor.setListeners(listeners); speedRegressionPerAngleClusterProcessor.setListeners(listeners);
backendPolarSheetGenerationSettings = backendPolarSettings; backendPolarSheetGenerationSettings = backendPolarSettings;
this.movingAverageProcessor = movingAverageProcessor;
this.cubicRegressionPerCourseProcessor = cubicRegressionPerCourseProcessor; this.cubicRegressionPerCourseProcessor = cubicRegressionPerCourseProcessor;
this.speedRegressionPerAngleClusterProcessor = speedRegressionPerAngleClusterProcessor; this.speedRegressionPerAngleClusterProcessor = speedRegressionPerAngleClusterProcessor;
this.speedClusterGroup = speedClusterGroup;
this.angleClusterGroup = angleClusterGroup; this.angleClusterGroup = angleClusterGroup;
try { try {
setUpWorkflow(); setUpWorkflow();
@@ -130,17 +122,6 @@ public class PolarDataMiner {
private void setUpWorkflow() throws ClassCastException, NoSuchMethodException, private void setUpWorkflow() throws ClassCastException, NoSuchMethodException,
SecurityException { SecurityException {
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> movingAverageGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
movingAverageGrouperResultReceivers.add(movingAverageProcessor);
Collection<ParameterizedFunction<?>> parameterizedDimensions = new ArrayList<>();
for (Function<?> function : PolarDataDimensionCollectionFactory.getMovingAverageClusterKeyDimensions()) {
parameterizedDimensions.add(new SimpleParameterizedFunction<>(function, ParameterProvider.NULL));
}
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> movingAverageGroupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions);
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>(); Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor); regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor);
@@ -164,7 +145,6 @@ public class PolarDataMiner {
Collection<Processor<GPSFixMovingWithPolarContext, ?>> filteringResultReceivers = new ArrayList<>(); Collection<Processor<GPSFixMovingWithPolarContext, ?>> filteringResultReceivers = new ArrayList<>();
filteringResultReceivers.add(movingAverageGroupingProcessor);
filteringResultReceivers.add(cubicRegressionPerCourseGroupingProcessor); filteringResultReceivers.add(cubicRegressionPerCourseGroupingProcessor);
filteringResultReceivers.add(regressionPerAngleClusterGroupingProcessor); filteringResultReceivers.add(regressionPerAngleClusterGroupingProcessor);
@@ -183,7 +163,7 @@ public class PolarDataMiner {
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) { protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
GPSFixMovingWithPolarContext result = null; GPSFixMovingWithPolarContext result = null;
result = new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(), result = new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(),
element.getCompetitor(), speedClusterGroup, angleClusterGroup); element.getCompetitor(), angleClusterGroup);
return result; return result;
} }
}; };
@@ -397,13 +377,9 @@ public class PolarDataMiner {
} }
public SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass, public SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass,
Speed windSpeed, LegType legType, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException { Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException {
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = null; SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = null;
if (useRegressionForSpeed) { averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
} else {
averageSpeedAndCourseOverGround = movingAverageProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
}
return averageSpeedAndCourseOverGround; return averageSpeedAndCourseOverGround;
} }
@@ -453,10 +429,6 @@ public class PolarDataMiner {
} }
} }
public MovingAverageProcessor getMovingAverageProcessor() {
return movingAverageProcessor;
}
public CubicRegressionPerCourseProcessor getCubicRegressionPerCourseProcessor() { public CubicRegressionPerCourseProcessor getCubicRegressionPerCourseProcessor() {
return cubicRegressionPerCourseProcessor; return cubicRegressionPerCourseProcessor;
} }
@@ -122,7 +122,7 @@ public class PolarResource extends AbstractSailingServerResource {
try { try {
PolarDataService service = getService().getPolarDataService(); PolarDataService service = getService().getPolarDataService();
SpeedWithBearingWithConfidence<Void> speedWithBearing = service.getAverageSpeedWithBearing(boatClass, SpeedWithBearingWithConfidence<Void> speedWithBearing = service.getAverageSpeedWithBearing(boatClass,
windSpeed, legType, tack, true); windSpeed, legType, tack);
String resultString = "Speed: " + speedWithBearing.getObject().getKnots() + "kn; Angle: " String resultString = "Speed: " + speedWithBearing.getObject().getKnots() + "kn; Angle: "
+ speedWithBearing.getObject().getBearing().getDegrees() + "°; Confidence: " + speedWithBearing.getObject().getBearing().getDegrees() + "°; Confidence: "
+ speedWithBearing.getConfidence(); + speedWithBearing.getConfidence();
@@ -57,9 +57,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
for (int i = 0; i < windSpeeds.size(); i++) { for (int i = 0; i < windSpeeds.size(); i++) {
try { try {
beatPort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND, beatPort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
Tack.PORT, true).getObject(); Tack.PORT).getObject();
beatStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND, beatStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
Tack.STARBOARD, true).getObject(); Tack.STARBOARD).getObject();
} catch (NotEnoughDataHasBeenAddedException e) { } catch (NotEnoughDataHasBeenAddedException e) {
beatPort = null; beatPort = null;
beatStar = null; beatStar = null;
@@ -86,9 +86,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
for (int i = 0; i < windSpeeds.size(); i++) { for (int i = 0; i < windSpeeds.size(); i++) {
try { try {
jibePort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), jibePort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
LegType.DOWNWIND, Tack.PORT, true).getObject(); LegType.DOWNWIND, Tack.PORT).getObject();
jibeStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), jibeStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
LegType.DOWNWIND, Tack.STARBOARD, true).getObject(); LegType.DOWNWIND, Tack.STARBOARD).getObject();
} catch (NotEnoughDataHasBeenAddedException e) { } catch (NotEnoughDataHasBeenAddedException e) {
jibePort = null; jibePort = null;
jibeStar = null; jibeStar = null;
@@ -146,13 +146,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
try { try {
if (beatPort == null) { if (beatPort == null) {
SpeedWithBearing beatPortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind, SpeedWithBearing beatPortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.UPWIND, Tack.PORT, true).getObject(); LegType.UPWIND, Tack.PORT).getObject();
beatPort = new KnotSpeedWithBearingImpl(beatPortRelative.getKnots(), this.wind.getBearing().reverse() beatPort = new KnotSpeedWithBearingImpl(beatPortRelative.getKnots(), this.wind.getBearing().reverse()
.add(beatPortRelative.getBearing())); .add(beatPortRelative.getBearing()));
} }
if (beatStar == null) { if (beatStar == null) {
SpeedWithBearing beatStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind, SpeedWithBearing beatStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.UPWIND, Tack.STARBOARD, true).getObject(); LegType.UPWIND, Tack.STARBOARD).getObject();
beatStar = new KnotSpeedWithBearingImpl(beatStarRelative.getKnots(), this.wind.getBearing().reverse() beatStar = new KnotSpeedWithBearingImpl(beatStarRelative.getKnots(), this.wind.getBearing().reverse()
.add(beatStarRelative.getBearing())); .add(beatStarRelative.getBearing()));
} }
@@ -175,13 +175,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
try { try {
if (jibePort == null) { if (jibePort == null) {
SpeedWithBearing jibePortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind, SpeedWithBearing jibePortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.DOWNWIND, Tack.PORT, true).getObject(); LegType.DOWNWIND, Tack.PORT).getObject();
jibePort = new KnotSpeedWithBearingImpl(jibePortRelative.getKnots(), this.wind.getBearing().reverse() jibePort = new KnotSpeedWithBearingImpl(jibePortRelative.getKnots(), this.wind.getBearing().reverse()
.add(jibePortRelative.getBearing())); .add(jibePortRelative.getBearing()));
} }
if (jibeStar == null) { if (jibeStar == null) {
SpeedWithBearing jibeStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind, SpeedWithBearing jibeStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.DOWNWIND, Tack.STARBOARD, true).getObject(); LegType.DOWNWIND, Tack.STARBOARD).getObject();
jibeStar = new KnotSpeedWithBearingImpl(jibeStarRelative.getKnots(), this.wind.getBearing().reverse() jibeStar = new KnotSpeedWithBearingImpl(jibeStarRelative.getKnots(), this.wind.getBearing().reverse()
.add(jibeStarRelative.getBearing())); .add(jibeStarRelative.getBearing()));
} }