Added main curve analysis to data mining

This commit is contained in:
Vladislav Chumak committed 2017-10-24 18:23:39 +02:00
1 parent c4f051d3d4
commit 14560d0e80
10 files changed
+110 -57

No files matched your search

@@ -30,5 +30,7 @@ public abstract class ManeuverSettings extends SerializableSettings {
public abstract Double getMinManeuverExitingAbsTWA();
public abstract Double getMaxManeuverExitingAbsTWA();
public abstract boolean isMainCurveAnalysis();
}
@@ -19,9 +19,10 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
private Double maxManeuverEnteringAbsTWA;
private Double minManeuverExitingAbsTWA;
private Double maxManeuverExitingAbsTWA;
private boolean mainCurveAnalysis;
public static ManeuverSettingsImpl createDefault() {
return new ManeuverSettingsImpl(1.0, null, 2.0, null, 1.0, null, null, null, null, null);
return new ManeuverSettingsImpl(1.0, null, 2.0, null, 1.0, null, null, null, null, null, false);
}
public ManeuverSettingsImpl() {
@@ -31,7 +32,7 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
Double minManeuverEnteringSpeedInKnots, Double maxManeuverEnteringSpeedInKnots,
Double minManeuverExitingSpeedInKnots, Double maxManeuverExitingSpeedInKnots,
Double minManeuverEnteringAbsTWA, Double maxManeuverEnteringAbsTWA, Double minManeuverExitingAbsTWA,
Double maxManeuverExitingAbsTWA) {
Double maxManeuverExitingAbsTWA, boolean mainCurveAnalysis) {
super();
this.minManeuverDuration = minManeuverDuration;
this.maxManeuverDuration = maxManeuverDuration;
@@ -43,6 +44,7 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
this.maxManeuverEnteringAbsTWA = maxManeuverEnteringAbsTWA;
this.minManeuverExitingAbsTWA = minManeuverExitingAbsTWA;
this.maxManeuverExitingAbsTWA = maxManeuverExitingAbsTWA;
this.mainCurveAnalysis = mainCurveAnalysis;
}
public Double getMinManeuverDuration() {
@@ -84,11 +86,17 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
public Double getMaxManeuverExitingAbsTWA() {
return maxManeuverExitingAbsTWA;
}
@Override
public boolean isMainCurveAnalysis() {
return mainCurveAnalysis;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (mainCurveAnalysis ? 1231 : 1237);
result = prime * result + ((maxManeuverDuration == null) ? 0 : maxManeuverDuration.hashCode());
result = prime * result + ((maxManeuverEnteringAbsTWA == null) ? 0 : maxManeuverEnteringAbsTWA.hashCode());
result = prime * result
@@ -115,6 +123,8 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
if (getClass() != obj.getClass())
return false;
ManeuverSettingsImpl other = (ManeuverSettingsImpl) obj;
if (mainCurveAnalysis != other.mainCurveAnalysis)
return false;
if (maxManeuverDuration == null) {
if (other.maxManeuverDuration != null)
return false;
@@ -167,5 +177,5 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
return false;
return true;
}
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.Tack;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
@@ -27,6 +28,9 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha
@Statistic(messageKey = "ManeuverLoss", resultDecimals = 0, ordinal = 4)
Distance getManeuverLoss();
@Statistic(messageKey = "AbsTWAAtManeuverClimax", ordinal = 7)
Double getAbsTWAAtManeuverClimax();
@Statistic(messageKey = "ManeuverEnteringAbsTWA", ordinal = 5)
Double getEnteringAbsTWA();
@@ -36,9 +40,6 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha
@Statistic(messageKey = "ManeuverDurationInSeconds", ordinal = 8, resultDecimals = 2)
Double getManeuverDuration();
@Statistic(messageKey = "AbsTWAAtManeuverClimax", ordinal = 7)
Double getAbsTWAAtManeuverClimax();
@Statistic(messageKey = "EnteringManeuverSpeedMinusExitingSpeed", ordinal = 19, resultDecimals = 4)
Double getEnteringManeuverSpeedMinusExitingSpeed();
@@ -51,4 +52,10 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha
@Statistic(messageKey = "ManeuverExitingSpeedInKnots", ordinal = 18, resultDecimals = 2)
Double getManeuverExitingSpeed();
TimePoint getTimePointBeforeForAnalysis();
TimePoint getTimePointAfterForAnalysis();
double getDirectionChangeInDegreesForAnalysis();
}
@@ -35,7 +35,7 @@ public class ManeuverRetrievalProcessor
try {
Iterable<Maneuver> maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
for (Maneuver maneuver : maneuvers) {
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(element, maneuver);
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(element, maneuver, settings.isMainCurveAnalysis());
// Compute only numbers which are really required for filtering
double maneuverDuration = settings.getMinManeuverDuration() != null
|| settings.getMaxManeuverDuration() != null ? maneuverWithContext.getManeuverDuration()
@@ -13,10 +13,11 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.tracking.SpeedWithBearingStep;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.SpeedWithBearingStep;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
@@ -50,9 +51,9 @@ public class ManeuverSpeedDetailsRetrievalProcessor
Wind wind = trackedRace.getWind(maneuver.getPosition(), maneuver.getTimePoint());
if (wind != null) {
if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null
&& maneuver.getTimePointBefore().until(maneuver.getTimePointAfter()).asMillis() >= 500) {
&& element.getTimePointBeforeForAnalysis().until(element.getTimePointAfterForAnalysis()).asMillis() >= 500) {
SpeedPerTWAExtraction speedPerTWAExtraction = extractSpeedPerTWA(trackedRace,
trackedLegOfCompetitor.getCompetitor(), wind, maneuver);
trackedLegOfCompetitor.getCompetitor(), wind, element.getTimePointBeforeForAnalysis(), element.getTimePointAfterForAnalysis(), element.getDirectionChangeInDegreesForAnalysis());
ManeuverSpeedDetailsWithContext maneuverSpeedDetailsContext = new ManeuverSpeedDetailsWithContext(
element, speedPerTWAExtraction.getSpeedPerTWA(), speedPerTWAExtraction.getEnteringTWA(),
settings);
@@ -64,19 +65,18 @@ public class ManeuverSpeedDetailsRetrievalProcessor
}
private SpeedPerTWAExtraction extractSpeedPerTWA(TrackedRace trackedRace, Competitor competitor, Wind wind,
Maneuver maneuver) {
long maneuverDuration = maneuver.getTimePointBefore().until(maneuver.getTimePointAfter()).asMillis();
TimePoint timePointBeforeForAnalysis, TimePoint timePointAfterForAnalysis, double directionChangeInDegreesForAnalysis) {
long maneuverDuration = timePointBeforeForAnalysis.until(timePointAfterForAnalysis).asMillis();
long stepMillis = maneuverDuration < 200 * 5 ? maneuverDuration / 5 : 200;
if (stepMillis == 0) {
stepMillis = 1;
}
final Iterable<SpeedWithBearingStep> maneuverBearingSteps = trackedRace.getTrack(competitor).getSpeedWithBearingSteps(
maneuver.getTimePointBefore(), maneuver.getTimePointAfter(), new MillisecondsDurationImpl(stepMillis));
timePointBeforeForAnalysis, timePointAfterForAnalysis, new MillisecondsDurationImpl(stepMillis));
NauticalSide maneuverDirection = maneuver.getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT
NauticalSide maneuverDirection = directionChangeInDegreesForAnalysis < 0 ? NauticalSide.PORT
: NauticalSide.STARBOARD;
double totalCourseChangeSignum = Math.signum(maneuver.getDirectionChangeInDegrees());
Function<Integer, Integer> forNextTWA = ManeuverSpeedDetailsUtils
.getNextTWAFunctionForManeuverDirection(maneuverDirection);
@@ -100,10 +100,6 @@ public class ManeuverSpeedDetailsRetrievalProcessor
enteringTWA = roundedTWA;
}
if (Math.abs(Math.signum(bearingStep.getCourseChangeInDegrees()) - totalCourseChangeSignum) == 2) {
continue;
}
// Neglect speed differences between TWA resolution < 1 Deg
// First twa/speed tuple gets priority over next tuples due it its "speed change freshness" regarding the
// whole twa sequence
@@ -20,29 +20,49 @@ public class ManeuverWithContext implements HasManeuverContext {
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
private final Maneuver maneuver;
private Wind wind;
private TimePoint timePointBeforeForAnalysis;
private TimePoint timePointAfterForAnalysis;
private double directionChangeInDegreesForAnalysis;
public ManeuverWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver maneuver) {
public ManeuverWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver maneuver, boolean mainCurveAnalysis) {
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
this.maneuver = maneuver;
if(mainCurveAnalysis) {
this.timePointBeforeForAnalysis = maneuver.getTimePointBeforeMainCurve();
this.timePointAfterForAnalysis = maneuver.getTimePointAfterMainCurve();
this.directionChangeInDegreesForAnalysis = maneuver.getDirectionChangeWithinMainCurveInDegrees();
} else {
this.timePointBeforeForAnalysis = maneuver.getTimePointBefore();
this.timePointAfterForAnalysis = maneuver.getTimePointAfter();
this.directionChangeInDegreesForAnalysis = maneuver.getDirectionChangeInDegrees();
}
}
public TimePoint getTimePointBeforeForAnalysis() {
return timePointBeforeForAnalysis;
}
public TimePoint getTimePointAfterForAnalysis() {
return timePointAfterForAnalysis;
}
public double getDirectionChangeInDegreesForAnalysis() {
return directionChangeInDegreesForAnalysis;
}
@Override
public Double getManeuverEnteringSpeed() {
Competitor competitor = getTrackedLegOfCompetitorContext().getTrackedLegOfCompetitor().getCompetitor();
TrackedRace trackedRace = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext()
.getTrackedRace();
return trackedRace.getTrack(competitor).getEstimatedSpeed(maneuver.getTimePointBefore()).getKnots();
return getSpeedInKnotsAtTimePoint(getTimePointBeforeForAnalysis());
}
@Override
public Double getManeuverExitingSpeed() {
Competitor competitor = getTrackedLegOfCompetitorContext().getTrackedLegOfCompetitor().getCompetitor();
TrackedRace trackedRace = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext()
.getTrackedRace();
return trackedRace.getTrack(competitor).getEstimatedSpeed(maneuver.getTimePointAfter()).getKnots();
return getSpeedInKnotsAtTimePoint(getTimePointAfterForAnalysis());
}
@Override
public Double getManeuverDuration() {
return maneuver.getTimePointBefore().until(maneuver.getTimePointAfter()).asSeconds();
return getTimePointBeforeForAnalysis().until(getTimePointAfterForAnalysis()).asSeconds();
}
@Override
@@ -72,12 +92,12 @@ public class ManeuverWithContext implements HasManeuverContext {
@Override
public NauticalSide getToSide() {
return getManeuver().getDirectionChangeInDegrees() >= 0 ? NauticalSide.STARBOARD : NauticalSide.PORT;
return getDirectionChangeInDegreesForAnalysis() >= 0 ? NauticalSide.STARBOARD : NauticalSide.PORT;
}
@Override
public Double getAbsoluteDirectionChangeInDegrees() {
return Math.abs(getManeuver().getDirectionChangeInDegrees());
return Math.abs(getDirectionChangeInDegreesForAnalysis());
}
@Override
@@ -97,12 +117,12 @@ public class ManeuverWithContext implements HasManeuverContext {
@Override
public Double getEnteringAbsTWA() {
return getAbsTWAAtTimepoint(maneuver.getTimePointBefore());
return getAbsTWAAtTimepoint(getTimePointBeforeForAnalysis());
}
@Override
public Double getExitingAbsTWA() {
return getAbsTWAAtTimepoint(maneuver.getTimePointAfter());
return getAbsTWAAtTimepoint(getTimePointAfterForAnalysis());
}
private Double getAbsTWAAtTimepoint(TimePoint timepoint) {
@@ -144,7 +164,7 @@ public class ManeuverWithContext implements HasManeuverContext {
@Override
public Tack getTackBeforeManeuver() {
Double twa = getTWAAtTimepoint(maneuver.getTimePointBefore());
Double twa = getTWAAtTimepoint(getTimePointBeforeForAnalysis());
if(twa == null) {
return null;
}
@@ -153,4 +173,12 @@ public class ManeuverWithContext implements HasManeuverContext {
}
return Tack.STARBOARD;
}
private Double getSpeedInKnotsAtTimePoint(TimePoint timePoint) {
Competitor competitor = getTrackedLegOfCompetitorContext().getTrackedLegOfCompetitor().getCompetitor();
TrackedRace trackedRace = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext()
.getTrackedRace();
return trackedRace.getTrack(competitor).getEstimatedSpeed(timePoint).getKnots();
}
}
@@ -1952,4 +1952,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String currentStbdRudderRakeTooltip();
String currentMastRotationInDegree();
String currentMastRotationInDegreeTooltip();
String mainCurveAnalysis();
}
@@ -1938,3 +1938,4 @@ currentStbdRudderRake=Stbd rudder rake
currentStbdRudderRakeTooltip=The current starboard rudder rake
currentMastRotationInDegree=Mast rotation
currentMastRotationInDegreeTooltip=The current mast rotation in degrees
mainCurveAnalysis=Analyze main curve only
@@ -1932,4 +1932,5 @@ dataMiningErrorMargins=Fehlerintervall
elements={0} Elemente
chooseDifferentDimensionTitle=Andere Dimension auswählen
chooseDifferentDimensionMessage=Zum Gruppieren eine andere Dimension auswählen
pleaseSelectADimension=Bitte eine Dimension auswählen
pleaseSelectADimension=Bitte eine Dimension auswählen
mainCurveAnalysis=Nur Hauptkurve untersuchen
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.datamining.presentation;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DoubleBox;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.Grid;
@@ -23,6 +24,7 @@ public class ManeuverSettingsDialogComponent implements SettingsDialogComponent<
private ManeuverSettings settings;
private StringMessages stringMessages;
private CheckBox mainCurveAnalysisBox;
private DoubleBox minManeuverDurationBox;
private DoubleBox maxManeuverDurationBox;
private DoubleBox minManeuverEnteringSpeedBox;
@@ -42,7 +44,7 @@ public class ManeuverSettingsDialogComponent implements SettingsDialogComponent<
@Override
public Widget getAdditionalWidget(DataEntryDialog<?> dialog) {
VerticalPanel vp = new VerticalPanel();
Grid grid = new Grid(10, 2);
Grid grid = new Grid(11, 2);
grid.setCellPadding(5);
vp.add(grid);
setupGrid(grid, dialog);
@@ -50,62 +52,67 @@ public class ManeuverSettingsDialogComponent implements SettingsDialogComponent<
}
private void setupGrid(Grid grid, DataEntryDialog<?> dialog) {
Label mainCurveAnalysisLabel = dialog.createLabel(stringMessages.mainCurveAnalysis());
grid.setWidget(0, 0, mainCurveAnalysisLabel);
mainCurveAnalysisBox = dialog.createCheckbox("");
grid.setWidget(0, 1, mainCurveAnalysisBox);
Label minManeuverDurationLabel = dialog.createLabel(stringMessages.minManeuverDuration());
grid.setWidget(0, 0, minManeuverDurationLabel);
grid.setWidget(1, 0, minManeuverDurationLabel);
minManeuverDurationBox = dialog.createDoubleBox(settings.getMinManeuverDuration(), 10);
grid.setWidget(0, 1, minManeuverDurationBox);
grid.setWidget(1, 1, minManeuverDurationBox);
Label maxManeuverDurationLabel = dialog.createLabel(stringMessages.maxManeuverDuration());
grid.setWidget(1, 0, maxManeuverDurationLabel);
grid.setWidget(2, 0, maxManeuverDurationLabel);
maxManeuverDurationBox = dialog.createDoubleBox(settings.getMaxManeuverDuration(), 10);
grid.setWidget(1, 1, maxManeuverDurationBox);
grid.setWidget(2, 1, maxManeuverDurationBox);
Label minManeuverEnteringSpeedLabel = dialog.createLabel(stringMessages.minManeuverEnteringSpeedInKnots());
grid.setWidget(2, 0, minManeuverEnteringSpeedLabel);
grid.setWidget(3, 0, minManeuverEnteringSpeedLabel);
minManeuverEnteringSpeedBox = dialog.createDoubleBox(settings.getMinManeuverEnteringSpeedInKnots(), 10);
grid.setWidget(2, 1, minManeuverEnteringSpeedBox);
grid.setWidget(3, 1, minManeuverEnteringSpeedBox);
Label maxManeuverEnteringSpeedLabel = dialog.createLabel(stringMessages.maxManeuverEnteringSpeedInKnots());
grid.setWidget(3, 0, maxManeuverEnteringSpeedLabel);
grid.setWidget(4, 0, maxManeuverEnteringSpeedLabel);
maxManeuverEnteringSpeedBox = dialog.createDoubleBox(settings.getMaxManeuverEnteringSpeedInKnots(), 10);
grid.setWidget(3, 1, maxManeuverEnteringSpeedBox);
grid.setWidget(4, 1, maxManeuverEnteringSpeedBox);
Label minManeuverExitingSpeedLabel = dialog.createLabel(stringMessages.minManeuverExitingSpeedInKnots());
grid.setWidget(4, 0, minManeuverExitingSpeedLabel);
grid.setWidget(5, 0, minManeuverExitingSpeedLabel);
minManeuverExitingSpeedBox = dialog.createDoubleBox(settings.getMinManeuverExitingSpeedInKnots(), 10);
grid.setWidget(4, 1, minManeuverExitingSpeedBox);
grid.setWidget(5, 1, minManeuverExitingSpeedBox);
Label maxManeuverExitingSpeedLabel = dialog.createLabel(stringMessages.maxManeuverExitingSpeedInKnots());
grid.setWidget(5, 0, maxManeuverExitingSpeedLabel);
grid.setWidget(6, 0, maxManeuverExitingSpeedLabel);
maxManeuverExitingSpeedBox = dialog.createDoubleBox(settings.getMaxManeuverExitingSpeedInKnots(), 10);
grid.setWidget(5, 1, maxManeuverExitingSpeedBox);
grid.setWidget(6, 1, maxManeuverExitingSpeedBox);
Label minManeuverEnteringAbsTWALabel = dialog.createLabel(stringMessages.minManeuverEnteringAbsTWA());
grid.setWidget(6, 0, minManeuverEnteringAbsTWALabel);
grid.setWidget(7, 0, minManeuverEnteringAbsTWALabel);
minManeuverEnteringAbsTWA = dialog.createDoubleBox(settings.getMinManeuverEnteringAbsTWA(), 10);
grid.setWidget(6, 1, minManeuverEnteringAbsTWA);
grid.setWidget(7, 1, minManeuverEnteringAbsTWA);
Label maxManeuverEnteringAbsTWALabel = dialog.createLabel(stringMessages.maxManeuverEnteringAbsTWA());
grid.setWidget(7, 0, maxManeuverEnteringAbsTWALabel);
grid.setWidget(8, 0, maxManeuverEnteringAbsTWALabel);
maxManeuverEnteringAbsTWA = dialog.createDoubleBox(settings.getMaxManeuverEnteringAbsTWA(), 10);
grid.setWidget(7, 1, maxManeuverEnteringAbsTWA);
grid.setWidget(8, 1, maxManeuverEnteringAbsTWA);
Label minManeuverExitingAbsTWALabel = dialog.createLabel(stringMessages.minManeuverExitingAbsTWA());
grid.setWidget(8, 0, minManeuverExitingAbsTWALabel);
grid.setWidget(9, 0, minManeuverExitingAbsTWALabel);
minManeuverExitingAbsTWA = dialog.createDoubleBox(settings.getMinManeuverExitingAbsTWA(), 10);
grid.setWidget(8, 1, minManeuverExitingAbsTWA);
grid.setWidget(9, 1, minManeuverExitingAbsTWA);
Label maxManeuverExitingAbsTWALabel = dialog.createLabel(stringMessages.maxManeuverExitingAbsTWA());
grid.setWidget(9, 0, maxManeuverExitingAbsTWALabel);
grid.setWidget(10, 0, maxManeuverExitingAbsTWALabel);
maxManeuverExitingAbsTWA = dialog.createDoubleBox(settings.getMaxManeuverExitingAbsTWA(), 10);
grid.setWidget(9, 1, maxManeuverExitingAbsTWA);
grid.setWidget(10, 1, maxManeuverExitingAbsTWA);
}
@Override
public ManeuverSettings getResult() {
return new ManeuverSettingsImpl(minManeuverDurationBox.getValue(), maxManeuverDurationBox.getValue(),
minManeuverEnteringSpeedBox.getValue(), maxManeuverEnteringSpeedBox.getValue(),
minManeuverExitingSpeedBox.getValue(), maxManeuverExitingSpeedBox.getValue(), minManeuverEnteringAbsTWA.getValue(), maxManeuverEnteringAbsTWA.getValue(), minManeuverExitingAbsTWA.getValue(), maxManeuverExitingAbsTWA.getValue());
minManeuverExitingSpeedBox.getValue(), maxManeuverExitingSpeedBox.getValue(), minManeuverEnteringAbsTWA.getValue(), maxManeuverEnteringAbsTWA.getValue(), minManeuverExitingAbsTWA.getValue(), maxManeuverExitingAbsTWA.getValue(), mainCurveAnalysisBox.getValue());
}
@Override