Improved data mining of complete maneuver curves with estimation data

This commit is contained in:
Vladislav Chumak committed 2018-03-30 04:17:56 +02:00
1 parent 795f322717
commit 3c9801e7b0
12 files changed
+373 -102

No files matched your search

@@ -177,8 +177,6 @@ RatioBetweenDistanceSailedWithAndWithoutManeuver=Ratio between distance sailed w
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Ratio between distance sailed toward middle angle projection with and without maneuver
DurationLostByManeuver=Duration lost by maneuver
DurationLostByManeuverTowardMiddleAngleProjection=duration lost by maneuver toward middle angle projection
CurveWithUnstableCourseAndSpeed=Curve with unstable course and speed
MainCurve=Main curve
JibingCount=Jibing count
TackingCount=Tacking count
AbsTwaAtMaxTurningRate=Abs. TWA at max. turning rate
@@ -187,4 +185,5 @@ AbsTwaAtHighestSpeed=Abs. TWA at highest speed
PercentageOfMainCurveProgressUntilLowestSpeed=Percentage of main curve progress until lowest speed
PercentageOfMainCurveProgressUntilHighestSpeed=Percentage of main curve progress until highest speed
PercentageOfMainCurveProgressUntilMaxTurningRate=Percentage of main curve progress until max. turning rate speed
ManeuverTypeForCompleteManeuverCurve=Maneuver type for complete maneuver curve
AbsTwaAtManeuverMiddle=Abs. TWA at maneuver middle
GpsSamplingRate=GPS sampling rate
@@ -187,4 +187,6 @@ AbsTwaAtHighestSpeed=Abs. TWA bei höchster Geschwindigkeit
PercentageOfMainCurveProgressUntilLowestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von geringster Geschwindigkeit
PercentageOfMainCurveProgressUntilHighestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von höchster Geschwindigkeit
PercentageOfMainCurveProgressUntilMaxTurningRate=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von max. Drehrate
ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve
ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve
AbsTwaAtManeuverMiddle=Abs. TWA während Manövermitte
GpsSamplingRate=GPS-Samplingrate
@@ -28,7 +28,7 @@ import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProce
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverSpeedDetailsRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverBoundariesRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.CompleteManeuverCurveWithEstimationDataRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
@@ -128,13 +128,13 @@ public class SailingDataRetrievalChainDefinitions {
"ManeuverSpeedDetails");
dataRetrieverChainDefinitions.add(speedDetailsDataRetrieverChainDefinition);
DataRetrieverChainDefinition<RacingEventService, HasCompleteManeuverCurveWithEstimationDataContext> maneuverBoundariesRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
DataRetrieverChainDefinition<RacingEventService, HasCompleteManeuverCurveWithEstimationDataContext> completeManeuverCurveWithEstimationDataRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
raceOfCompetitorRetrieverChainDefinition, HasCompleteManeuverCurveWithEstimationDataContext.class,
"CompleteManeuverCurveWithEstimationDataRetrieverChain");
maneuverBoundariesRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class,
ManeuverBoundariesRetrievalProcessor.class, HasCompleteManeuverCurveWithEstimationDataContext.class,
completeManeuverCurveWithEstimationDataRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class,
CompleteManeuverCurveWithEstimationDataRetrievalProcessor.class, HasCompleteManeuverCurveWithEstimationDataContext.class, ManeuverSettings.class, ManeuverSettingsImpl.createDefault(),
"CompleteManeuverCurveWithEstimationData");
dataRetrieverChainDefinitions.add(maneuverBoundariesRetrieverChainDefinition);
dataRetrieverChainDefinitions.add(completeManeuverCurveWithEstimationDataRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasMarkPassingContext> markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
legOfCompetitorRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain");
@@ -1,6 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
@@ -20,6 +21,9 @@ public interface HasCompleteManeuverCurveWithEstimationDataContext {
@Connector
CompleteManeuverCurveWithEstimationData getCompleteManeuverCurveWithEstimationData();
@Dimension(messageKey = "ToSide")
NauticalSide getToSide();
@Statistic(messageKey = "ManeuverStartSpeedDeviationRatioFromAvg", ordinal = 1, resultDecimals = 4)
Double getManeuverStartSpeedDeviationRatioFromAvgStatistic();
@@ -51,12 +55,57 @@ public interface HasCompleteManeuverCurveWithEstimationDataContext {
ClusterDTO getTackingCount();
@Statistic(messageKey = "AbsTwaAtMaxTurningRate")
Bearing getAbsTwaAtMaxTurningRate();
double getAbsTwaAtMaxTurningRate();
@Statistic(messageKey = "AbsTwaAtLowestSpeed")
Bearing getAbsTwaAtLowestSpeed();
double getAbsTwaAtLowestSpeed();
@Statistic(messageKey = "AbsTwaAtHighestSpeed")
Bearing getAbsTwaAtHighestSpeed();
double getAbsTwaAtHighestSpeed();
@Statistic(messageKey = "AbsTwaAtManeuverMiddle")
double getAbsTwaAtManeuverMiddle();
@Statistic(messageKey = "GpsSamplingRate")
double getGpsSamplingRate();
@Statistic(messageKey = "ManeuverEnteringAbsTWA")
Double getEnteringAbsTWA();
@Statistic(messageKey = "ManeuverExitingAbsTWA")
Double getExitingAbsTWA();
@Dimension(messageKey = "TypeOfPreviousManeuver")
ManeuverType getTypeOfPreviousManeuver();
@Dimension(messageKey = "TypeOfNextManeuver")
ManeuverType getTypeOfNextManeuver();
@Statistic(messageKey = "AbsoluteDirectionChange", resultDecimals = 2)
Double getAbsoluteDirectionChangeInDegrees();
@Statistic(messageKey = "RatioBetweenDistanceSailedWithAndWithoutManeuver", resultDecimals = 4)
double getRatioBetweenDistanceSailedWithAndWithoutManeuver();
@Statistic(messageKey = "DurationLostByManeuver", resultDecimals = 4)
double getDurationLostByManeuver();
@Statistic(messageKey = "DurationLostByManeuverTowardMiddleAngleProjection", resultDecimals = 4)
double getDurationLostByManeuverTowardMiddleAngleProjection();
@Statistic(messageKey = "RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver", resultDecimals = 4)
double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver();
@Statistic(messageKey = "RelativeBearingToNextMarkBeforeManeuver", resultDecimals = 1)
Double getRelativeBearingToNextMarkBeforeManeuver();
@Statistic(messageKey = "RelativeBearingToNextMarkAfterManeuver", resultDecimals = 1)
Double getRelativeBearingToNextMarkAfterManeuver();
@Statistic(messageKey = "ManeuverEnteringSpeedInKnots", resultDecimals = 2)
Double getManeuverEnteringSpeed();
@Statistic(messageKey = "ManeuverExitingSpeedInKnots", resultDecimals = 2)
Double getManeuverExitingSpeed();
}
@@ -0,0 +1,151 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.CompleteManeuverCurveWithEstimationDataWithContext;
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl;
import com.sap.sailing.domain.tracking.CompleteManeuverCurve;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.Duration;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class CompleteManeuverCurveWithEstimationDataRetrievalProcessor extends
AbstractRetrievalProcessor<HasRaceOfCompetitorContext, HasCompleteManeuverCurveWithEstimationDataContext> {
private final ManeuverSettings settings;
public CompleteManeuverCurveWithEstimationDataRetrievalProcessor(ExecutorService executor,
Collection<Processor<HasCompleteManeuverCurveWithEstimationDataContext, ?>> resultReceivers,
ManeuverSettings settings, int retrievalLevel) {
super(HasRaceOfCompetitorContext.class, HasCompleteManeuverCurveWithEstimationDataContext.class, executor,
resultReceivers, retrievalLevel);
this.settings = settings;
}
@Override
protected Iterable<HasCompleteManeuverCurveWithEstimationDataContext> retrieveData(
HasRaceOfCompetitorContext element) {
List<HasCompleteManeuverCurveWithEstimationDataContext> result = new ArrayList<>();
TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
Competitor competitor = element.getCompetitor();
ManeuverDetector maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor);
Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, false);
Iterable<CompleteManeuverCurve> maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers);
Iterable<CompleteManeuverCurveWithEstimationData> maneuversWithEstimationData = maneuverDetector
.getCompleteManeuverCurvesWithEstimationData(maneuverCurves);
CompleteManeuverCurveWithEstimationData previousManeuver = null;
CompleteManeuverCurveWithEstimationData currentManeuver = null;
for (CompleteManeuverCurveWithEstimationData nextManeuver : maneuversWithEstimationData) {
if (currentManeuver != null) {
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
element, currentManeuver, settings, previousManeuver, nextManeuver);
if (currentManeuver.getWind() != null
&& isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, nextManeuver)) {
result.add(maneuverWithContext);
}
}
previousManeuver = currentManeuver;
currentManeuver = nextManeuver;
}
if (currentManeuver != null) {
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
element, currentManeuver, settings, previousManeuver, null);
if (currentManeuver.getWind() != null
&& isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, null)) {
result.add(maneuverWithContext);
}
}
return result;
}
private boolean isManeuverCompliantWithSettings(CompleteManeuverCurveWithEstimationData previousManeuver,
CompleteManeuverCurveWithEstimationDataWithContext currentManeuverWithContext,
CompleteManeuverCurveWithEstimationData nextManeuver) {
boolean mainCurveAnalysis = settings.isMainCurveAnalysis();
// Compute only numbers which are really required for filtering
Duration maneuverDuration = settings.getMinManeuverDuration() != null
|| settings.getMaxManeuverDuration() != null
? currentManeuverWithContext.getTimePointBeforeForAnalysis()
.until(currentManeuverWithContext.getTimePointAfterForAnalysis())
: null;
double maneuverEnteringSpeed = settings.getMinManeuverEnteringSpeedInKnots() != null
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
? currentManeuverWithContext.getManeuverEnteringSpeed() : 0;
double maneuverExitingSpeed = settings.getMinManeuverExitingSpeedInKnots() != null
|| settings.getMaxManeuverExitingSpeedInKnots() != null
? currentManeuverWithContext.getManeuverExitingSpeed() : 0;
double maneuverEnteringAbsTWA = settings.getMinManeuverEnteringAbsTWA() != null
? currentManeuverWithContext.getEnteringAbsTWA() : 0;
double maneuverExitingAbsTWA = settings.getMinManeuverExitingAbsTWA() != null
? currentManeuverWithContext.getExitingAbsTWA() : 0;
Duration durationToPreviousManeuver = previousManeuver != null
? getManeuverBoundariesForAnalysis(previousManeuver, mainCurveAnalysis).getTimePointAfter()
.until(currentManeuverWithContext.getTimePointBeforeForAnalysis())
: null;
Duration durationToNextManeuver = nextManeuver != null
? currentManeuverWithContext.getTimePointAfterForAnalysis().until(
getManeuverBoundariesForAnalysis(nextManeuver, mainCurveAnalysis).getTimePointBefore())
: null;
if (!(settings.getMinManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMinManeuverDuration()) < 0
|| settings.getMaxManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMaxManeuverDuration()) > 0
|| settings.getMinManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed < settings.getMinManeuverEnteringSpeedInKnots()
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed > settings.getMaxManeuverEnteringSpeedInKnots()
|| settings.getMinManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed < settings.getMinManeuverExitingSpeedInKnots()
|| settings.getMaxManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed > settings.getMaxManeuverExitingSpeedInKnots()
|| settings.getMinManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA < settings.getMinManeuverEnteringAbsTWA()
|| settings.getMaxManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA > settings.getMaxManeuverEnteringAbsTWA()
|| settings.getMinManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA < settings.getMinManeuverExitingAbsTWA()
|| settings.getMaxManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA > settings.getMaxManeuverExitingAbsTWA()
|| settings.getMinAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() < settings.getMinAbsCourseChangeInDegrees()
|| settings.getMaxAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() > settings.getMaxAbsCourseChangeInDegrees()
|| settings.getMinDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMinDurationFromPrecedingManeuver()) < 0)
|| settings.getMaxDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMaxDurationFromPrecedingManeuver()) > 0)
|| settings.getMinDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMinDurationToFollowingManeuver()) < 0)
|| settings.getMaxDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMaxDurationToFollowingManeuver()) > 0))) {
return true;
} else {
return false;
}
}
private ManeuverCurveBoundaries getManeuverBoundariesForAnalysis(CompleteManeuverCurveWithEstimationData maneuver,
boolean mainCurveAnalysis) {
return mainCurveAnalysis ? maneuver.getMainCurve() : maneuver.getCurveWithUnstableCourseAndSpeed();
}
}
@@ -1,51 +0,0 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.CompleteManeuverCurveWithEstimationDataWithContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl;
import com.sap.sailing.domain.tracking.CompleteManeuverCurve;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class ManeuverBoundariesRetrievalProcessor
extends AbstractRetrievalProcessor<HasRaceOfCompetitorContext, HasCompleteManeuverCurveWithEstimationDataContext> {
public ManeuverBoundariesRetrievalProcessor(ExecutorService executor,
Collection<Processor<HasCompleteManeuverCurveWithEstimationDataContext, ?>> resultReceivers, int retrievalLevel) {
super(HasRaceOfCompetitorContext.class, HasCompleteManeuverCurveWithEstimationDataContext.class, executor, resultReceivers,
retrievalLevel);
}
@Override
protected Iterable<HasCompleteManeuverCurveWithEstimationDataContext> retrieveData(HasRaceOfCompetitorContext element) {
List<HasCompleteManeuverCurveWithEstimationDataContext> result = new ArrayList<>();
TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
Competitor competitor = element.getCompetitor();
ManeuverDetector maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor);
Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, false);
Iterable<CompleteManeuverCurve> maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers);
Iterable<CompleteManeuverCurveWithEstimationData> maneuversWithEstimationData = maneuverDetector
.getCompleteManeuverCurvesWithEstimationData(maneuverCurves);
for (CompleteManeuverCurveWithEstimationData maneuverWithEstimationData : maneuversWithEstimationData) {
result.add(new CompleteManeuverCurveWithEstimationDataWithContext(element, maneuverWithEstimationData));
}
return result;
}
}
@@ -2,11 +2,17 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.HasDetailedManeuverLoss;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
/**
@@ -18,12 +24,20 @@ public class CompleteManeuverCurveWithEstimationDataWithContext
implements HasCompleteManeuverCurveWithEstimationDataContext {
private final CompleteManeuverCurveWithEstimationData maneuverWithEstimationData;
private HasRaceOfCompetitorContext raceOfCompetitorContext;
private final HasRaceOfCompetitorContext raceOfCompetitorContext;
private final ManeuverSettings maneuverSettings;
private final CompleteManeuverCurveWithEstimationData previousManeuverCurve;
private final CompleteManeuverCurveWithEstimationData nextManeuverCurve;
public CompleteManeuverCurveWithEstimationDataWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext,
CompleteManeuverCurveWithEstimationData maneuverWithEstimationData) {
CompleteManeuverCurveWithEstimationData maneuverWithEstimationData, ManeuverSettings maneuverSettings,
CompleteManeuverCurveWithEstimationData previousManeuverCurve,
CompleteManeuverCurveWithEstimationData nextManeuverCurve) {
this.raceOfCompetitorContext = raceOfCompetitorContext;
this.maneuverWithEstimationData = maneuverWithEstimationData;
this.maneuverSettings = maneuverSettings;
this.previousManeuverCurve = previousManeuverCurve;
this.nextManeuverCurve = nextManeuverCurve;
}
@Override
@@ -33,8 +47,8 @@ public class CompleteManeuverCurveWithEstimationDataWithContext
@Override
public Double getManeuverStartSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getSpeedWithBearingBefore();
SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
@@ -49,8 +63,8 @@ public class CompleteManeuverCurveWithEstimationDataWithContext
@Override
public Double getManeuverStartCogDeviationFromAvgInDegreesStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getSpeedWithBearingBefore();
SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
@@ -62,7 +76,7 @@ public class CompleteManeuverCurveWithEstimationDataWithContext
@Override
public Double getManeuverEndSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingAfterManeuver = maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
SpeedWithBearing speedWithBearingAfterManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingAfter();
SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingAfter();
@@ -140,23 +154,132 @@ public class CompleteManeuverCurveWithEstimationDataWithContext
}
@Override
public Bearing getAbsTwaAtMaxTurningRate() {
public double getAbsTwaAtMaxTurningRate() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getCourseAtMaxTurningRate());
}
@Override
public Bearing getAbsTwaAtLowestSpeed() {
public double getAbsTwaAtLowestSpeed() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getLowestSpeed().getBearing());
}
@Override
public Bearing getAbsTwaAtHighestSpeed() {
public double getAbsTwaAtHighestSpeed() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getHighestSpeed().getBearing());
}
private Bearing getAbsTwaFromCourse(Bearing course) {
private double getAbsTwaFromCourse(Bearing course) {
double twa = maneuverWithEstimationData.getWind().getFrom().getDifferenceTo(course).getDegrees();
return new DegreeBearingImpl(twa);
return Math.abs(twa);
}
@Override
public NauticalSide getToSide() {
return maneuverWithEstimationData.getMainCurve().getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT
: NauticalSide.STARBOARD;
}
private ManeuverCurveBoundaries getManeuverCurveBoundariesForAnalysis() {
return maneuverSettings.isMainCurveAnalysis() ? maneuverWithEstimationData.getMainCurve()
: maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed();
}
@Override
public Double getEnteringAbsTWA() {
return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getBearing());
}
@Override
public Double getExitingAbsTWA() {
return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getBearing());
}
@Override
public ManeuverType getTypeOfPreviousManeuver() {
return previousManeuverCurve == null ? ManeuverType.UNKNOWN
: previousManeuverCurve.getManeuverTypeForCompleteManeuverCurve();
}
@Override
public ManeuverType getTypeOfNextManeuver() {
return nextManeuverCurve == null ? ManeuverType.UNKNOWN
: nextManeuverCurve.getManeuverTypeForCompleteManeuverCurve();
}
@Override
public Double getAbsoluteDirectionChangeInDegrees() {
return Math.abs(getManeuverCurveBoundariesForAnalysis().getDirectionChangeInDegrees());
}
@Override
public double getRatioBetweenDistanceSailedWithAndWithoutManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getRatioBetweenDistanceSailedWithAndWithoutManeuver();
}
@Override
public double getDurationLostByManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()).getDurationLostByManeuver()
.asSeconds();
}
@Override
public double getDurationLostByManeuverTowardMiddleAngleProjection() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getDurationLostByManeuverTowardMiddleAngleProjection().asSeconds();
}
@Override
public double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver();
}
@Override
public Double getRelativeBearingToNextMarkBeforeManeuver() {
return maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver() == null ? null
: maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver().getDegrees();
}
@Override
public Double getRelativeBearingToNextMarkAfterManeuver() {
return maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver() == null ? null
: maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver().getDegrees();
}
public TimePoint getTimePointBeforeForAnalysis() {
return getManeuverCurveBoundariesForAnalysis().getTimePointBefore();
}
public TimePoint getTimePointAfterForAnalysis() {
return getManeuverCurveBoundariesForAnalysis().getTimePointAfter();
}
@Override
public Double getManeuverEnteringSpeed() {
return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getKnots();
}
@Override
public Double getManeuverExitingSpeed() {
return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getKnots();
}
@Override
public double getAbsTwaAtManeuverMiddle() {
ManeuverCurveBoundaries boundariesForAnalysis = getManeuverCurveBoundariesForAnalysis();
Bearing middleCourse = boundariesForAnalysis.getSpeedWithBearingBefore().getBearing()
.add(new DegreeBearingImpl(boundariesForAnalysis.getDirectionChangeInDegrees() / 2));
return getAbsTwaFromCourse(middleCourse);
}
@Override
public double getGpsSamplingRate() {
return maneuverSettings.isMainCurveAnalysis()
? maneuverWithEstimationData.getMainCurve().getGpsFixesCount()
/ maneuverWithEstimationData.getMainCurve().getDuration().asSeconds()
: maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getGpsFixesCount()
/ maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getDuration().asSeconds();
}
}
@@ -6,7 +6,6 @@ import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.tracking.CompleteManeuverCurve;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
/**
* Contains information of a complete maneuver curve which is regarded as relevant for maneuver classification
@@ -17,19 +16,19 @@ import com.sap.sse.datamining.annotations.Statistic;
*
*/
public interface CompleteManeuverCurveWithEstimationData {
@Dimension(messageKey = "ManeuverTypeForCompleteManeuverCurve")
@Dimension(messageKey = "ManeuverType")
default ManeuverType getManeuverTypeForCompleteManeuverCurve() {
if(getJibingCount() > 0 && getTackingCount() > 0) {
if (getJibingCount() > 0 && getTackingCount() > 0) {
return ManeuverType.PENALTY_CIRCLE;
}
if(getTackingCount() > 0) {
if (getTackingCount() > 0) {
return ManeuverType.TACK;
}
if(getJibingCount() > 0) {
if (getJibingCount() > 0) {
return ManeuverType.JIBE;
}
if(getWind() == null) {
if (getWind() == null) {
return ManeuverType.UNKNOWN;
}
return isManeuverStartsByRunningAwayFromTheWind() ? ManeuverType.BEAR_AWAY : ManeuverType.HEAD_UP;
@@ -39,14 +38,13 @@ public interface CompleteManeuverCurveWithEstimationData {
* Gets the information of the main curve of maneuver including its boundaries, course change, and other data
* relevant for maneuver classification.
*/
@Connector(messageKey="MainCurve")
@Connector
ManeuverMainCurveWithEstimationData getMainCurve();
/**
* Gets the information of the curve with unstable course and speed of maneuver including its boundaries, course
* change, and other data relevant for maneuver classification.
*/
@Connector(messageKey="CurveWithUnstableCourseAndSpeed")
ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData getCurveWithUnstableCourseAndSpeed();
/**
@@ -82,7 +80,6 @@ public interface CompleteManeuverCurveWithEstimationData {
* calculated by absolute bearing of next mark from the boat's position minus the boat's course. As the maneuver
* boundaries, the boundaries of the curve with unstable course and speed are used.
*/
@Statistic(messageKey="RelativeBearingToNextMarkBeforeManeuver", resultDecimals=1)
Bearing getRelativeBearingToNextMarkBeforeManeuver();
/**
@@ -90,9 +87,8 @@ public interface CompleteManeuverCurveWithEstimationData {
* calculated by absolute bearing of next mark from the boat's position minus the boat's course. As the maneuver
* boundaries, the boundaries of the curve with unstable course and speed are used.
*/
@Statistic(messageKey="RelativeBearingToNextMarkAfterManeuver", resultDecimals=1)
Bearing getRelativeBearingToNextMarkAfterManeuver();
/**
* Gets whether a mark was crossed within the maneuver curve.
*/
@@ -5,7 +5,6 @@ import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasDetailedManeuverLoss {
@@ -44,7 +43,6 @@ public interface HasDetailedManeuverLoss {
* Gets the ratio between {@link #getDistanceSailedWithinManeuver()} and
* {@link #getDistanceSailedIfNotManeuvering()}.
*/
@Statistic(messageKey = "RatioBetweenDistanceSailedWithAndWithoutManeuver", resultDecimals=4)
default double getRatioBetweenDistanceSailedWithAndWithoutManeuver() {
return getDistanceSailedWithinManeuver().getMeters() / getDistanceSailedIfNotManeuvering().getMeters();
}
@@ -70,7 +68,6 @@ public interface HasDetailedManeuverLoss {
/**
* Gets the duration lost by maneuver.
*/
@Statistic(messageKey = "DurationLostByManeuver", resultDecimals=4)
default Duration getDurationLostByManeuver() {
return new MillisecondsDurationImpl(
(long) (getDistanceLost().getMeters() / getSpeedWithBearingBefore().getMetersPerSecond() * 1000));
@@ -79,7 +76,6 @@ public interface HasDetailedManeuverLoss {
/**
* Gets the duration lost by maneuver toward middle angle projection.
*/
@Statistic(messageKey = "DurationLostByManeuverTowardMiddleAngleProjection", resultDecimals=4)
default Duration getDurationLostByManeuverTowardMiddleAngleProjection() {
return new MillisecondsDurationImpl((long) (getDistanceLostTowardMiddleAngleProjection().getMeters()
/ getSpeedWithBearingBefore().getMetersPerSecond() * 1000));
@@ -89,7 +85,6 @@ public interface HasDetailedManeuverLoss {
* Gets the ratio between {@link #getDistanceSailedWithinManeuverTowardMiddleAngleProjection()} and
* {@link #getDistanceSailedTowardMiddleAngleProjectionIfNotManeuvering()}
*/
@Statistic(messageKey = "RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver", resultDecimals=4)
default double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver() {
return getDistanceSailedWithinManeuverTowardMiddleAngleProjection().getMeters()
/ getDistanceSailedTowardMiddleAngleProjectionIfNotManeuvering().getMeters();
@@ -11,7 +11,8 @@ import com.sap.sse.common.Duration;
* @author Vladislav Chumak (D069712)
*
*/
public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData extends ManeuverCurveBoundaries, HasDetailedManeuverLoss {
public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData
extends ManeuverCurveBoundaries, HasDetailedManeuverLoss {
/**
* Gets the average speed and course measured from the end of the previous maneuver until the start of this
@@ -46,7 +47,7 @@ public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData exten
* distance of at least one second, the result will be {@null}.
*/
Duration getDurationFromManeuverEndToNextManeuverStart();
/**
* Gets the number of GPS-fixes contained within the maneuver curve.
*/
@@ -25,7 +25,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda
* Gets the time point at which the lowest speed was recorded within the main curve.
*/
TimePoint getLowestSpeedTimePoint();
@Statistic(messageKey = "PercentageOfMainCurveProgressUntilLowestSpeed", resultDecimals = 4)
default double getPercentageOfMainCurveProgressUntilLowestSpeed() {
return getTimePointBefore().until(getLowestSpeedTimePoint()).asSeconds() / getDuration().asSeconds();
@@ -40,7 +40,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda
* Gets the time point at which the highest speed was recorded within the main curve.
*/
TimePoint getHighestSpeedTimePoint();
@Statistic(messageKey = "PercentageOfMainCurveProgressUntilHighestSpeed", resultDecimals = 4)
default double getPercentageOfMainCurveProgressUntilHighestSpeed() {
return getTimePointBefore().until(getHighestSpeedTimePoint()).asSeconds() / getDuration().asSeconds();
@@ -50,7 +50,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda
* Gets the time point at which the maximal turning rate was recorded within the main curve.
*/
TimePoint getTimePointOfMaxTurningRate();
@Statistic(messageKey = "PercentageOfMainCurveProgressUntilMaxTurningRate", resultDecimals = 4)
default double getPercentageOfMainCurveProgressUntilMaxTurningRate() {
return getTimePointBefore().until(getTimePointOfMaxTurningRate()).asSeconds() / getDuration().asSeconds();
@@ -61,7 +61,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda
*/
@Statistic(messageKey = "MaxTurningRateInDegreesPerSecond", resultDecimals = 4)
double getMaxTurningRateInDegreesPerSecond();
/**
* Gets the average turning rate recorded within the maneuver main curve. It is calculated by absolute course change
* within main curve divided by maneuver main curve duration.
@@ -73,7 +73,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda
* Gets the course at which the maximal turning rate was measured within the main curve.
*/
Bearing getCourseAtMaxTurningRate();
/**
* Gets the number of GPS-fixes contained within the maneuver main curve.
*/
@@ -253,10 +253,11 @@ public class ManeuverDetectorImpl implements ManeuverDetector {
private CompleteManeuverCurveWithEstimationData calculateCompleteManeuverCurveWithEstimationData(
CompleteManeuverCurve maneuverCurve, CompleteManeuverCurve previousManeuverCurve,
CompleteManeuverCurve nextManeuverCurve) {
Bearing courseAtMaxTurningRate = track.getEstimatedSpeed(maneuverCurve.getMainCurveBoundaries().getTimePoint())
.getBearing();
Bearing courseAtMaxTurningRate = null;
SpeedWithBearingStep stepWithLowestSpeed = null;
SpeedWithBearingStep stepWithHighestSpeed = null;
SpeedWithBearingStep stepWithMaxTurningRate = null;
SpeedWithBearingStep previousStep = null;
for (SpeedWithBearingStep step : maneuverCurve.getMainCurveBoundaries().getSpeedWithBearingSteps()) {
if (stepWithLowestSpeed == null
|| stepWithLowestSpeed.getSpeedWithBearing().compareTo(step.getSpeedWithBearing()) > 0) {
@@ -266,6 +267,11 @@ public class ManeuverDetectorImpl implements ManeuverDetector {
|| stepWithHighestSpeed.getSpeedWithBearing().compareTo(step.getSpeedWithBearing()) < 0) {
stepWithHighestSpeed = step;
}
if(previousStep != null && (stepWithMaxTurningRate == null || stepWithMaxTurningRate.getAngularVelocityInDegreesPerSecond() < step.getAngularVelocityInDegreesPerSecond())) {
stepWithMaxTurningRate = step;
courseAtMaxTurningRate = previousStep.getSpeedWithBearing().getBearing().add(new DegreeBearingImpl(step.getCourseChangeInDegrees() / 2));
}
previousStep = step;
}
int gpsFixCountWithinMainCurve = 0;
int gpsFixCountWithinWholeCurve = 0;