From e62091996ec26b2324aa4733751aaf9e9ad12e11 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Thu, 28 May 2015 15:48:26 +0200 Subject: [PATCH] Added some confidence by datacount calculations to angle cluster polar service --- .../sailing/polars/mining/PolarDataMiner.java | 8 ++++- ...eedRegressionPerAngleClusterProcessor.java | 30 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java index a4780d2351f..58c6d535ed6 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java @@ -326,8 +326,14 @@ public class PolarDataMiner { SpeedWithConfidence speedWithConfidence; try { int convertedAngle = convertAngleIfNecessary(angle); - speedWithConfidence = speedRegressionPerAngleClusterProcessor.estimateBoatSpeed(boatClass, + SpeedWithConfidence regressionResult = speedRegressionPerAngleClusterProcessor.estimateBoatSpeed(boatClass, new KnotSpeedImpl(windSpeed), new DegreeBearingImpl(convertedAngle)); + if (regressionResult.getConfidence() > 0.1) { + speedWithConfidence = regressionResult; + } else { + // Low confidence. So put in 0 speed for chart + speedWithConfidence = new SpeedWithConfidenceImpl(new KnotSpeedImpl(0), regressionResult.getConfidence(), null); + } } catch (NotEnoughDataHasBeenAddedException e) { // No data so put in a 0 speed with 0 confidence speedWithConfidence = new SpeedWithConfidenceImpl(new KnotSpeedImpl(0), 0, null); diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java index 5953fde119b..e1fb5b9e1b4 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java @@ -29,6 +29,8 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor regressions = new HashMap<>(); + + private final Map fixCountPerBoatClass = new HashMap<>(); private final ClusterGroup angleClusterGroup; @@ -46,6 +48,13 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor element) { GroupKey key = element.getKey(); IncrementalLeastSquares regression; + BoatClass boatClass = element.getDataEntry().getBoatClass(); + synchronized (fixCountPerBoatClass) { + if (!fixCountPerBoatClass.containsKey(boatClass)) { + fixCountPerBoatClass.put(boatClass, 0L); + } + fixCountPerBoatClass.put(boatClass, fixCountPerBoatClass.get(boatClass) + 1); + } synchronized (regressions) { regression = regressions.get(key); if (regression == null) { @@ -66,18 +75,29 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor estimateBoatSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle) throws NotEnoughDataHasBeenAddedException { double speedSum = 0; double numberOfSpeeds = 0; - for (int i = -5; i <= 5; i++) { + long fixCount = 0; + for (int i = -2; i <= 2; i++) { GroupKey key = createGroupKey(boatClass, new DegreeBearingImpl(Math.abs(trueWindAngle.getDegrees()) + i)); if (regressions.containsKey(key)) { - speedSum += regressions.get(key).getOrCreatePolynomialFunction().value(windSpeed.getKnots()); - numberOfSpeeds++; + IncrementalLeastSquares incrementalLeastSquares = regressions.get(key); + fixCount = fixCount + incrementalLeastSquares.getNumberOfAddedPoints(); + if (fixCount > 10) { + speedSum += incrementalLeastSquares.getOrCreatePolynomialFunction().value(windSpeed.getKnots()); + numberOfSpeeds++; + } } } - if (numberOfSpeeds < 1) { + fixCount = (long) (fixCount / numberOfSpeeds); + long fixCountOverall = 0; + if (numberOfSpeeds < 2 || fixCount < 10) { throw new NotEnoughDataHasBeenAddedException("Not enough data has been added to Per Course Regressions"); + } else { + synchronized (fixCountPerBoatClass) { + fixCountOverall = fixCountPerBoatClass.get(boatClass); + } } Speed speed = new KnotSpeedImpl(speedSum / numberOfSpeeds); - return new SpeedWithConfidenceImpl(speed, /*FIXME*/ 0.5, null); + return new SpeedWithConfidenceImpl(speed, Math.min(1, 5.0 * ((double) fixCount / fixCountOverall)), null); } private GroupKey createGroupKey(final BoatClass boatClass, final Bearing angle) {