mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-15 00:30:58 +00:00
cache ScalableBearingAndScalableDouble for ManeuverClassification, avoiding expensive creation; use approximation for ScalableBearing difference which is much faster
This commit is contained in:
1 parent
882f18300f
commit
500dcf41e9
4 files changed
+97
-3
No files matched your search
+21
@@ -63,4 +63,25 @@ public class ScalableBearing implements ScalableValueWithDistance<DoublePair, Be
|
||||
public double getDistance(Bearing other) {
|
||||
return Math.abs(divide(1).getDifferenceTo(other).getDegrees());
|
||||
}
|
||||
|
||||
/**
|
||||
* Computing the difference to a {@link bearing}, as implemented by {@link #getDistance(Bearing)} is correct but
|
||||
* slow because the {@link Math#atan2(double)} function is used to {@link ScalableBearing#divide(double) bring the
|
||||
* scalable bearing down to a bearing}. A less precise, yet much faster to compute and still monotonous distance
|
||||
* measure computes the length of the line segment connecting this bearing's projection onto a circle with the
|
||||
* projection of the bearing <code>a</code> to the same circle. The distance returned by this method will provide
|
||||
* almost equal values for very small differences (below 1deg) but significantly smaller values for big differences.
|
||||
*
|
||||
* @return an approximate difference in degrees, fairly accurate for small differences, but returning 360.0/PI
|
||||
* (approximately 114) instead of 180 for the maximum difference
|
||||
*/
|
||||
public double getApproximateDegreeDistanceTo(Bearing a) {
|
||||
double scale = Math.sqrt(sin*sin + cos*cos);
|
||||
double x = cos/scale;
|
||||
double y = sin/scale;
|
||||
double ax = Math.cos(a.getRadians());
|
||||
double ay = Math.sin(a.getRadians());
|
||||
double normalDistance = Math.sqrt((x-ax)*(x-ax) + (y-ay)*(y-ay));
|
||||
return normalDistance / Math.PI * 180.;
|
||||
}
|
||||
}
|
||||
@@ -531,5 +531,65 @@ public class ConfidenceTest {
|
||||
assertTrue(average.getObject().getLatDeg() < 49.15);
|
||||
assertEquals((8.0*4/4 + 9.0*2/4 + 8.5*1/4)/(7./4.), average.getObject().getLngDeg(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleApproximateScalableBearingDistanceTest1() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(100));
|
||||
Bearing b = new DegreeBearingImpl(280);
|
||||
assertEquals(360./Math.PI, sb.getApproximateDegreeDistanceTo(b), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleApproximateScalableBearingDistanceTest2() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(0));
|
||||
Bearing b = new DegreeBearingImpl(180);
|
||||
assertEquals(360./Math.PI, sb.getApproximateDegreeDistanceTo(b), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleApproximateScalableBearingDistanceTest3() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(100));
|
||||
Bearing b = new DegreeBearingImpl(101);
|
||||
assertEquals(1, sb.getApproximateDegreeDistanceTo(b), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleApproximateScalableBearingDistanceTest4() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(0));
|
||||
Bearing b = new DegreeBearingImpl(1);
|
||||
assertEquals(1, sb.getApproximateDegreeDistanceTo(b), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scaledApproximateScalableBearingDistanceTest1() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(100)).
|
||||
multiply(123);
|
||||
Bearing b = new DegreeBearingImpl(280);
|
||||
assertEquals(360./Math.PI, sb.getApproximateDegreeDistanceTo(b), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scaledApproximateScalableBearingDistanceTest2() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(0)).
|
||||
multiply(123);
|
||||
Bearing b = new DegreeBearingImpl(180);
|
||||
assertEquals(360./Math.PI, sb.getApproximateDegreeDistanceTo(b), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scaledApproximateScalableBearingDistanceTest3() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(100)).
|
||||
multiply(123);
|
||||
Bearing b = new DegreeBearingImpl(101);
|
||||
assertEquals(1, sb.getApproximateDegreeDistanceTo(b), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scaledApproximateScalableBearingDistanceTest4() {
|
||||
com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing sb = new com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing(new DegreeBearingImpl(0)).
|
||||
multiply(123);
|
||||
Bearing b = new DegreeBearingImpl(1);
|
||||
assertEquals(1, sb.getApproximateDegreeDistanceTo(b), 0.01);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -147,6 +147,7 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
|
||||
private final Bearing middleManeuverCourse;
|
||||
private final Distance maneuverLoss;
|
||||
private Pair<Double, SpeedWithBearingWithConfidence<Void>>[] likelihoodAndTWSBasedOnSpeedAndAngleCache;
|
||||
private ScalableBearingAndScalableDouble scalableMiddleManeuverCourseAndManeuverAngleDegCache;
|
||||
|
||||
protected ManeuverClassification(Competitor competitor, Maneuver maneuver) {
|
||||
super();
|
||||
@@ -185,6 +186,14 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
|
||||
public Bearing getMiddleManeuverCourse() {
|
||||
return middleManeuverCourse;
|
||||
}
|
||||
|
||||
public ScalableBearingAndScalableDouble getScalableMiddleManeuverCourseAndManeuverAngleDeg() {
|
||||
if (scalableMiddleManeuverCourseAndManeuverAngleDegCache == null) {
|
||||
scalableMiddleManeuverCourseAndManeuverAngleDegCache = new ScalableBearingAndScalableDouble(
|
||||
getMiddleManeuverCourse(), getManeuverAngleDeg());
|
||||
}
|
||||
return scalableMiddleManeuverCourseAndManeuverAngleDegCache;
|
||||
}
|
||||
|
||||
public SpeedWithBearingWithConfidence<Void> getEstimatedWindSpeedAndBearing(ManeuverType maneuverType) {
|
||||
Pair<Double, SpeedWithBearingWithConfidence<Void>> likelihoodAndTWSBasedOnSpeedAndAngle = polarService.getManeuverLikelihoodAndTwsTwa(
|
||||
@@ -339,7 +348,7 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
|
||||
KMeansMappingClusterer<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> clusterer =
|
||||
new KMeansMappingClusterer<>(numberOfClusters,
|
||||
getManeuverClassifications(maneuvers),
|
||||
(mc)->new ScalableBearingAndScalableDouble(mc.getMiddleManeuverCourse(), mc.getManeuverAngleDeg()), // maps maneuver classification to cluster metric
|
||||
(mc)->mc.getScalableMiddleManeuverCourseAndManeuverAngleDeg(), // maps maneuver classification to cluster metric
|
||||
// use an evenly distributed set of cluster seeds for clustering wind direction estimations
|
||||
Stream.concat(IntStream.range(0, numberOfClusters/2).mapToObj((i)->
|
||||
new Pair<>(new DegreeBearingImpl(((double) i)*360./(double) numberOfClusters/2), 45.)),
|
||||
|
||||
+6
-2
@@ -12,7 +12,11 @@ import com.sap.sse.common.scalablevalue.ScalableValueWithDistance;
|
||||
* Addition} works component wise, and so does {@link #multiply(double) multiplication} and {@link #divide(double)
|
||||
* division}. The {@link #getDistance(Pair) distance} is calculated as the Euklidian two-dimensional distance between
|
||||
* the two bearing pairs, with "degrees" as conceptual unit. For example, another object of this type that is 2 and 3 degrees
|
||||
* apart from this object will have a distance of {@link Math#sqrt(double) Math.sqrt(13)}.
|
||||
* apart from this object will have a distance of {@link Math#sqrt(double) Math.sqrt(13)}.<p>
|
||||
*
|
||||
* The {@link #getDistance(Pair)} implementation uses {@link ScalableBearing#getApproximateDegreeDistanceTo(Bearing)} on
|
||||
* the scalable bearing part of this object. This is only an approximation but works a lot faster and is still monotonous.
|
||||
* It works well for small angles.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
@@ -44,7 +48,7 @@ public class ScalableBearingAndScalableDouble implements
|
||||
|
||||
@Override
|
||||
public double getDistance(Pair<Bearing, Double> other) {
|
||||
final double b1DiffDeg = b1.divide(1).getDifferenceTo(other.getA()).getDegrees();
|
||||
final double b1DiffDeg = b1.getApproximateDegreeDistanceTo(other.getA());
|
||||
final double b2DiffDeg = Math.abs(b2.divide(1)-other.getB());
|
||||
return Math.sqrt(b1DiffDeg*b1DiffDeg + b2DiffDeg*b2DiffDeg);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user