Skip to content

Commit

Permalink
Cleanup: renames in sensor data handling.
Browse files Browse the repository at this point in the history
Part of #1995.
  • Loading branch information
dennisguse committed Feb 21, 2025
1 parent 28daee8 commit c2fd257
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -549,23 +549,23 @@ private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Di
SensorDataSet sensorDataSet = trackPointCreator.getSensorManager().sensorDataSet;

AggregatorCyclingPower cyclingPower = Mockito.mock(AggregatorCyclingPower.class);
Mockito.when(cyclingPower.hasValue()).thenReturn(true);
Mockito.when(cyclingPower.getValue(Mockito.any())).thenReturn(Power.of(power));
Mockito.when(cyclingPower.hasAggregatedValue()).thenReturn(true);
Mockito.when(cyclingPower.getAggregatedValue(Mockito.any())).thenReturn(Power.of(power));
sensorDataSet.add(cyclingPower);

AggregatorHeartRate avgHeartRate = Mockito.mock(AggregatorHeartRate.class);
Mockito.when(avgHeartRate.getValue(Mockito.any())).thenReturn(HeartRate.of(heartRate));
Mockito.when(avgHeartRate.getAggregatedValue(Mockito.any())).thenReturn(HeartRate.of(heartRate));
sensorDataSet.add(avgHeartRate);

AggregatorCyclingCadence cyclingCadence = Mockito.mock(AggregatorCyclingCadence.class);
Mockito.when(cyclingCadence.hasValue()).thenReturn(true);
Mockito.when(cyclingCadence.getValue(Mockito.any())).thenReturn(Cadence.of(cadence));
Mockito.when(cyclingCadence.hasAggregatedValue()).thenReturn(true);
Mockito.when(cyclingCadence.getAggregatedValue(Mockito.any())).thenReturn(Cadence.of(cadence));
sensorDataSet.add(cyclingCadence);

if (distance != null && speed != null) {
AggregatorCyclingDistanceSpeed distanceSpeed = Mockito.mock(AggregatorCyclingDistanceSpeed.class);
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
Mockito.when(distanceSpeed.getValue(Mockito.any())).thenReturn(new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed)));
Mockito.when(distanceSpeed.hasAggregatedValue()).thenReturn(true);
Mockito.when(distanceSpeed.getAggregatedValue(Mockito.any())).thenReturn(new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed)));
sensorDataSet.add(distanceSpeed);
} else {
sensorDataSet.add(new AggregatorCyclingDistanceSpeed("", ""));
Expand All @@ -581,8 +581,8 @@ private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altit

if (altitudeGain != null) {
AggregatorBarometer barometer = Mockito.mock(AggregatorBarometer.class);
Mockito.when(barometer.hasValue()).thenReturn(true);
Mockito.when(barometer.getValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain));
Mockito.when(barometer.hasAggregatedValue()).thenReturn(true);
Mockito.when(barometer.getAggregatedValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain));
sensorDataSet.add(barometer);
} else {
sensorDataSet.add(new AggregatorBarometer("test", null));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void getAltitudeGainLoss_downhill() {
addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f});

// then
Assert.assertEquals(0f, subject.value.gain_m(), 0.01);
Assert.assertEquals(15f, subject.value.loss_m(), 0.01);
Assert.assertEquals(0f, subject.aggregatedValue.gain_m(), 0.01);
Assert.assertEquals(15f, subject.aggregatedValue.loss_m(), 0.01);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

import androidx.test.ext.junit.runners.AndroidJUnit4;

Expand All @@ -13,6 +12,7 @@

import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.UintUtils;
Expand All @@ -29,7 +29,7 @@ public void compute_cadence_1() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 2048)));

// then
assertEquals(60, current.getValue(Instant.MIN).getRPM(), 0.01);
assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01);
}

@Test
Expand All @@ -41,7 +41,7 @@ public void compute_cadence_2() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 8016)));

// then
assertEquals(33.53, current.getValue(Instant.MIN).getRPM(), 0.01);
assertEquals(33.53, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01);
}

@Test
Expand All @@ -53,7 +53,7 @@ public void compute_cadence_sameCount() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 2048)));

// then
assertEquals(Cadence.of(0), current.getValue(Instant.MIN));
assertEquals(Cadence.of(0), current.getAggregatedValue(Instant.MIN));
}


Expand All @@ -66,7 +66,7 @@ public void compute_cadence_sameTime() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 1024)));

// then
assertFalse(current.hasValue()); //TODO Cadence should be 0?
assertFalse(current.hasAggregatedValue()); //TODO Cadence should be 0?
}

@Test
Expand All @@ -78,7 +78,7 @@ public void compute_cadence_rollOverTime() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 0)));

// then
assertEquals(60, current.getValue(Instant.MIN).getRPM(), 0.01);
assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01);
}

@Test
Expand All @@ -93,7 +93,7 @@ public void compute_cadence_rollOverCount() {
// then
// TODO See #953
// assertEquals(60, current.getValue().getRPM(), 0.01);
assertNull(current.getValue(Instant.MIN));
assertEquals(Cadence.of(0), current.getAggregatedValue(Instant.MIN));
}

@Test
Expand All @@ -106,8 +106,8 @@ public void compute_speed() {
current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(2, 8016)));

// then
assertEquals(2.15, current.getValue(Instant.MIN).distance().toM(), 0.01);
assertEquals(1.20, current.getValue(Instant.MIN).speed().toMPS(), 0.01);
assertEquals(2.15, current.getAggregatedValue(Instant.MIN).distance().toM(), 0.01);
assertEquals(1.20, current.getAggregatedValue(Instant.MIN).speed().toMPS(), 0.01);
}

@Test
Expand All @@ -125,6 +125,6 @@ public void compute_speed_rollOverCount() {
// TODO See #953
// assertEquals(2, current.getValue().getDistance().toM(), 0.01);
// assertEquals(2, current.getValue().getSpeed().toMPS(), 0.01);
assertNull(current.getValue(Instant.MIN));
assertEquals(new AggregatorCyclingDistanceSpeed.Data(Distance.of(0), Distance.of(0), Speed.of(0)), current.getAggregatedValue(Instant.MIN));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,8 @@ public void testRecording_gpsAndSensor_gpsIdleMoving_sensorMoving() {

private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
AggregatorBarometer barometer = Mockito.mock(AggregatorBarometer.class);
Mockito.when(barometer.hasValue()).thenReturn(true);
Mockito.when(barometer.getValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain));
Mockito.when(barometer.hasAggregatedValue()).thenReturn(true);
Mockito.when(barometer.getAggregatedValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain));

trackPointCreator.getSensorManager().sensorDataSet.barometer = barometer;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.dennisguse.opentracks.sensors.sensorData;

import android.util.Pair;

import androidx.annotation.NonNull;

import java.time.Instant;
Expand All @@ -10,7 +12,7 @@ public abstract class Aggregator<Input, Output> {

protected Raw<Input> previous;

protected Output value;
protected Output aggregatedValue;

private final String sensorAddress;
private final String sensorName;
Expand All @@ -35,27 +37,35 @@ public final void add(Raw<Input> current) {

protected abstract void computeValue(Raw<Input> current);

public boolean hasValue() {
return value != null;
public boolean hasAggregatedValue() {
return aggregatedValue != null;
}

@NonNull
protected abstract Output getNoneValue();

public Output getValue(Instant now) {
if (!hasValue()) {
return null; //TODO Check if this is a good idea!
@NonNull
public Output getAggregatedValue(Instant now) {
if (!hasAggregatedValue()) {
return getNoneValue();
}
//TODO This should only affect measured data (like heartrate), but not aggregated values.
//Remove current measurements, but provide aggregates?
if (isRecent(now)) {
return value;
return aggregatedValue;
}
return getNoneValue();
}

@NonNull
public Pair<Output, String> getAggregatedValueWithSensorName(Instant now) {
return new Pair<>(getAggregatedValue(now), getSensorNameOrAddress());
}

/**
* Reset long term aggregated values (more than derived from previous SensorData). e.g. overall distance.
*/
public void reset() {}
public abstract void reset();

/**
* Is the data recent considering the current time.
Expand All @@ -66,12 +76,12 @@ private boolean isRecent(Instant now) {
}

return now
.isBefore(previous.time().plus(BluetoothRemoteSensorManager.MAX_SENSOR_DATE_SET_AGE));
.isBefore(previous.time().plus(BluetoothRemoteSensorManager.MAX_SENSOR_DATE_SET_AGE)); //TODO Per Sensor!
}

@NonNull
@Override
public String toString() {
return "sensorAddress=" + sensorAddress + " data=" + value;
return "sensorAddress=" + sensorAddress + " data=" + aggregatedValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ public AggregatorBarometer(String sensorAddress, String sensorName) {
protected void computeValue(Raw<AtmosphericPressure> current) {
if (previous == null) {
lastAcceptedSensorValue = current.value();
value = getNoneValue();
aggregatedValue = getNoneValue();
return;
}

PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChangesWithSmoothing_m(lastAcceptedSensorValue, previous.value(), current.value());
if (altitudeChange != null) {
value = new AltitudeGainLoss(value.gain_m() + altitudeChange.getAltitudeGain_m(), value.loss_m() + altitudeChange.getAltitudeLoss_m());
aggregatedValue = new AltitudeGainLoss(aggregatedValue.gain_m() + altitudeChange.getAltitudeGain_m(), aggregatedValue.loss_m() + altitudeChange.getAltitudeLoss_m());

lastAcceptedSensorValue = altitudeChange.currentSensorValue();
}
}

@NonNull
@Override
protected AltitudeGainLoss getNoneValue() {
return new AltitudeGainLoss(0f, 0f);
public void reset() {
aggregatedValue = getNoneValue();
}

@NonNull
@Override
public void reset() {
value = getNoneValue();
protected AltitudeGainLoss getNoneValue() {
return new AltitudeGainLoss(0f, 0f);
}

public record Data(Altitude gain, Altitude loss) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,34 @@ public AggregatorCyclingCadence(String sensorAddress, String sensorName) {

@Override
protected void computeValue(Raw<BluetoothHandlerCyclingCadence.CrankData> current) {
if (previous != null) {
float timeDiff_ms = UintUtils.diff(current.value().crankRevolutionsTime(), previous.value().crankRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);

if (timeDiff.isZero()) {
return;
}
if (timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
value = null;
return;
}

// TODO We have to treat with overflow according to the documentation: read https://github.com/OpenTracksApp/OpenTracks/pull/953#discussion_r711625268
if (current.value().crankRevolutionsCount() < previous.value().crankRevolutionsCount()) {
Log.e(TAG, "Crank revolutions count difference is invalid: cannot compute cadence.");
return;
}

long crankDiff = UintUtils.diff(current.value().crankRevolutionsCount(), previous.value().crankRevolutionsCount(), UintUtils.UINT32_MAX);
value = Cadence.of(crankDiff, timeDiff);
if (previous == null) {
return;
}

float timeDiff_ms = UintUtils.diff(current.value().crankRevolutionsTime(), previous.value().crankRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);

if (timeDiff.isZero()) {
return;
}
if (timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
aggregatedValue = null;
return;
}

// TODO We have to treat with overflow according to the documentation: read https://github.com/OpenTracksApp/OpenTracks/pull/953#discussion_r711625268
if (current.value().crankRevolutionsCount() < previous.value().crankRevolutionsCount()) {
Log.e(TAG, "Crank revolutions count difference is invalid: cannot compute cadence.");
return;
}

long crankDiff = UintUtils.diff(current.value().crankRevolutionsCount(), previous.value().crankRevolutionsCount(), UintUtils.UINT32_MAX);
aggregatedValue = Cadence.of(crankDiff, timeDiff);
}

@Override
public void reset() {
}

@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,47 +23,49 @@ public AggregatorCyclingDistanceSpeed(String sensorAddress, String sensorName) {

@Override
protected void computeValue(Raw<BluetoothHandlerCyclingDistanceSpeed.WheelData> current) {
if (previous != null) {
float timeDiff_ms = UintUtils.diff(current.value().wheelRevolutionsTime(), previous.value().wheelRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);

if (timeDiff.isZero()) {
return;
}
if (timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
value = null;
return;
}

if (current.value().wheelRevolutionsCount() < previous.value().wheelRevolutionsCount()) {
Log.e(TAG, "Wheel revolutions count difference is invalid: cannot compute speed.");
return;
}
long wheelDiff = UintUtils.diff(current.value().wheelRevolutionsCount(), previous.value().wheelRevolutionsCount(), UintUtils.UINT32_MAX);

Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (value != null) {
distanceOverall = distance.plus(value.distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
value = new Data(distance, distanceOverall, speed_mps);
if (previous == null) {
return;
}

float timeDiff_ms = UintUtils.diff(current.value().wheelRevolutionsTime(), previous.value().wheelRevolutionsTime(), UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);

if (timeDiff.isZero()) {
return;
}
if (timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
aggregatedValue = null;
return;
}

if (current.value().wheelRevolutionsCount() < previous.value().wheelRevolutionsCount()) {
Log.e(TAG, "Wheel revolutions count difference is invalid: cannot compute speed.");
return;
}
long wheelDiff = UintUtils.diff(current.value().wheelRevolutionsCount(), previous.value().wheelRevolutionsCount(), UintUtils.UINT32_MAX);

Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (aggregatedValue != null) {
distanceOverall = distance.plus(aggregatedValue.distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
aggregatedValue = new Data(distance, distanceOverall, speed_mps);
}

@Override
public void reset() {
if (value != null) {
value = new Data(value.distance, Distance.of(0), value.speed);
if (aggregatedValue != null) {
aggregatedValue = new Data(aggregatedValue.distance, Distance.of(0), aggregatedValue.speed);
}
}

@NonNull
@Override
protected Data getNoneValue() {
if (value != null) {
return new Data(value.distance, value.distanceOverall, Speed.zero());
if (aggregatedValue != null) {
return new Data(aggregatedValue.distance, aggregatedValue.distanceOverall, Speed.zero());
} else {
return new Data(Distance.of(0), Distance.of(0), Speed.zero());
}
Expand Down
Loading

0 comments on commit c2fd257

Please sign in to comment.