mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-13 22:15:26 +00:00
implemented interpolation for extended Bravo tracks; added test
Change-Id: Iafe5db8392d574794ba057e4522dc63f3fb53b8d
This commit is contained in:
1 parent
c1d07aa56f
commit
ce02f6d84b
3 files changed
+104
-26
No files matched your search
+50
-22
@@ -6,6 +6,8 @@ import java.util.function.Function;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.confidence.impl.ScalableDouble;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -16,6 +18,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.WithID;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
* Specific {@link SensorFixTrackImpl} used for {@link BravoFix}es.
|
||||
@@ -186,26 +189,14 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
* In case of a mix of {@link BravoFix} and {@link BravoExtendedFix} instances, this method may return null values
|
||||
* for specific {@link TimePoint TimePoints}.
|
||||
*/
|
||||
private <T> T getValueFromExtendedFix(final TimePoint timePoint, final Function<BravoExtendedFix, T> getter) {
|
||||
private <T, I> T getValueFromExtendedFix(final TimePoint timePoint, final Function<BravoExtendedFix, T> getter,
|
||||
Function<T, ScalableValue<I, T>> converterToScalableValue) {
|
||||
if (!hasExtendedFixes) {
|
||||
return null;
|
||||
}
|
||||
final BravoExtendedFix fixAfter = getFirstFixAtOrAfterIfExtended(timePoint);
|
||||
if (fixAfter != null && fixAfter.getTimePoint().compareTo(timePoint) == 0) {
|
||||
// exact match of timepoint -> no interpolation necessary
|
||||
return getter.apply(fixAfter);
|
||||
}
|
||||
final BravoExtendedFix fixBefore = getLastFixAtOrBeforeIfExtended(timePoint);
|
||||
if (fixBefore != null && fixBefore.getTimePoint().compareTo(timePoint) == 0) {
|
||||
// exact match of timepoint -> no interpolation necessary
|
||||
return getter.apply(fixBefore);
|
||||
}
|
||||
if (fixAfter == null || fixBefore == null) {
|
||||
// the fix is out of the TimeRange where we have fixes
|
||||
return null;
|
||||
}
|
||||
// TODO interpolate if necessary
|
||||
return getter.apply(fixBefore);
|
||||
final com.sap.sse.common.Util.Function<BravoFix, ScalableValue<I, T>> converter =
|
||||
fix -> converterToScalableValue.apply(getter.apply((BravoExtendedFix) fix));
|
||||
return getInterpolatedValue(timePoint, converter);
|
||||
}
|
||||
|
||||
public BravoExtendedFix getFirstFixAtOrAfterIfExtended(TimePoint timePoint) {
|
||||
@@ -220,26 +211,63 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
|
||||
@Override
|
||||
public Double getPortDaggerboardRakeIfAvailable(TimePoint timePoint) {
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getPortDaggerboardRake);
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getPortDaggerboardRake,
|
||||
ScalableDouble::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getStbdDaggerboardRakeStbdIfAvailable(TimePoint timePoint) {
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getStbdDaggerboardRake);
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getStbdDaggerboardRake,
|
||||
ScalableDouble::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getPortRudderRakeIfAvailable(TimePoint timePoint) {
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getPortRudderRake);
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getPortRudderRake,
|
||||
ScalableDouble::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getStbdRudderRakeIfAvailable(TimePoint timePoint) {
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getStbdRudderRake);
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getStbdRudderRake,
|
||||
ScalableDouble::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getMastRotationIfAvailable(TimePoint timePoint) {
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getMastRotation);
|
||||
return getValueFromExtendedFix(timePoint, BravoExtendedFix::getMastRotation,
|
||||
NaivelyScalableBearing::new);
|
||||
}
|
||||
|
||||
private static class NaivelyScalableBearing implements ScalableValue<Double, Bearing> {
|
||||
private final double deg;
|
||||
|
||||
public NaivelyScalableBearing(Bearing b) {
|
||||
deg = b.getDegrees();
|
||||
}
|
||||
|
||||
private NaivelyScalableBearing(double deg) {
|
||||
this.deg = deg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableValue<Double, Bearing> multiply(double factor) {
|
||||
return new NaivelyScalableBearing(deg*factor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableValue<Double, Bearing> add(ScalableValue<Double, Bearing> t) {
|
||||
return new NaivelyScalableBearing(deg+t.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing divide(double divisor) {
|
||||
return new DegreeBearingImpl(deg/divisor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return deg;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -7,7 +7,6 @@ import java.util.Map;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.impl.BravoFixImpl;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
@@ -21,7 +20,7 @@ public abstract class AbstractBravoDataImportTest {
|
||||
|
||||
private DownsamplerTo1HzProcessor downsampler;
|
||||
|
||||
private BaseBravoDataImporterImpl bravoDataImporter;
|
||||
protected BaseBravoDataImporterImpl bravoDataImporter;
|
||||
private int callbackCallCount = 0;
|
||||
private double sumRideHeightInMeters = 0.0;
|
||||
|
||||
@@ -44,7 +43,7 @@ public abstract class AbstractBravoDataImportTest {
|
||||
DoubleVectorFixImporter.Callback callback,
|
||||
TrackFileImportDeviceIdentifier trackIdentifier) {
|
||||
final LearningBatchProcessor batchProcessor = new LearningBatchProcessor(5000, 5000, callback, trackIdentifier);
|
||||
downsampler = new DownsamplerTo1HzProcessor(BravoSensorDataMetadata.getTrackColumnCount(), batchProcessor);
|
||||
downsampler = new DownsamplerTo1HzProcessor(getTrackColumnCount(), batchProcessor);
|
||||
return downsampler;
|
||||
};
|
||||
};
|
||||
|
||||
+52
-1
@@ -1,15 +1,28 @@
|
||||
package com.sap.sailing.server.trackfiles.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoExtendedSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.impl.BravoExtendedFixImpl;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.tracking.DynamicBravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class BravoExtendedDataImportTest extends AbstractBravoDataImportTest {
|
||||
|
||||
@@ -38,6 +51,39 @@ public class BravoExtendedDataImportTest extends AbstractBravoDataImportTest {
|
||||
testImport(ImportData.DUMMY_RANDOM_HAEDER_ONE_LINE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadingTwoLinesAndInterpolating() throws FormatNotSupportedException, IOException {
|
||||
DynamicBravoFixTrack<Competitor> track = new BravoFixTrackImpl<>(null, "Test Track", /* hasExtendedFixes */ true);
|
||||
bravoDataImporter.importFixes(new ByteArrayInputStream((
|
||||
HEADER_ORDER_DEFAULT+DUMMY_CONTENT+DUMMY_CONTENT2).getBytes(StandardCharsets.UTF_8)),
|
||||
(fixes, device) -> {
|
||||
for (DoubleVectorFix fix : fixes) {
|
||||
track.add(new BravoExtendedFixImpl(fix));
|
||||
}
|
||||
}, "filename", "source", /* downsample */ true);
|
||||
final TimePoint t1 = new MillisecondsTimePoint(1500648308500l);
|
||||
final TimePoint t2 = new MillisecondsTimePoint(1500648309500l);
|
||||
final BravoExtendedFix bef1, bef2;
|
||||
track.lockForRead();
|
||||
try {
|
||||
final Iterator<BravoFix> i = track.getFixes().iterator();
|
||||
bef1 = (BravoExtendedFix) i.next();
|
||||
bef2 = (BravoExtendedFix) i.next();
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
assertEquals(t1, bef1.getTimePoint());
|
||||
assertEquals(t2, bef2.getTimePoint());
|
||||
assertEquals(0.915471, bef1.getPortRudderRake(), 0.00001);
|
||||
assertEquals(0.913729, bef2.getPortRudderRake(), 0.00001);
|
||||
assertEquals(0.915471, track.getPortRudderRakeIfAvailable(t1), 0.00001);
|
||||
assertEquals(0.913729, track.getPortRudderRakeIfAvailable(t2), 0.00001);
|
||||
assertEquals((0.915471+0.913729)/2., track.getPortRudderRakeIfAvailable(t1.plus(t1.until(t2).divide(2.))), 0.00001);
|
||||
assertEquals(new DegreeBearingImpl(-46.507845).getDegrees(), track.getMastRotationIfAvailable(t1).getDegrees(), 0.00001);
|
||||
assertEquals(new DegreeBearingImpl(-46.845317).getDegrees(), track.getMastRotationIfAvailable(t2).getDegrees(), 0.00001);
|
||||
assertEquals(new DegreeBearingImpl((-46.507845-46.845317)/2.).getDegrees(), track.getMastRotationIfAvailable(t1.plus(t1.until(t2).divide(2.))).getDegrees(), 0.00001);
|
||||
}
|
||||
|
||||
private enum ImportData implements ImportDataDefinition {
|
||||
DUMMY_DEFAULT_HEADER_NO_DATA(0, 0) {
|
||||
@Override
|
||||
@@ -97,5 +143,10 @@ public class BravoExtendedDataImportTest extends AbstractBravoDataImportTest {
|
||||
+ "-0.142641\t0.661195\t0.640803\t11.024831\t4.831789\t274.531789\t11.415373\t-28.235512\t12.815985\t"
|
||||
+ "-88.908514\t6.063496\t183.968325\t0.000000\t0.000000\t0.000000\t0.000000\t-0.080389\t-46.507845\t"
|
||||
+ "-0.301864\t0.915471\t0.737711\t5.518818\t60.000000\t4.049104\t8.098208\t11.025103\t134.646042\t0.684715\t\n";
|
||||
|
||||
private static final String DUMMY_CONTENT2 = "20170721.000000\t144509.118053\t1500648309088.000000\t0.000000\t0.000000\t"
|
||||
+ "0.000000\t0.100000\t4121.750782\t211.854789\t270.700000\t12.176000\t274.577803\t8.372667\t1.532401\t-0.512621\t"
|
||||
+ "4.513550\t2.952788\t5.778569\t0.009470\t0.074722\t-0.023186\t-0.053617\t0.575403\t-0.142008\t0.680177\t0.661195\t"
|
||||
+ "11.118556\t7.659780\t274.859780\t11.461121\t-28.065986\t12.819678\t-88.995990\t6.032477\t183.831801\t0.000000\t"
|
||||
+ "0.000000\t0.000000\t0.000000\t-0.112260\t-46.845317\t-0.301864\t0.913729\t0.738945\t5.526500\t60.000000\t4.031748\t"
|
||||
+ "8.063496\t10.993632\t136.139139\t1.985348\n";
|
||||
}
|
||||
Reference in new issue
Block a user