forked from upstream-mirrors/OpenTracks
@@ -22,6 +22,9 @@ import androidx.annotation.Nullable;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Distance;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
|
||||
/**
|
||||
* Statistical data about a {@link de.dennisguse.opentracks.content.data.Track}.
|
||||
* The data in this class should be filled out by {@link TrackStatisticsUpdater}.
|
||||
@@ -40,13 +43,13 @@ public class TrackStatistics {
|
||||
// The track stop time.
|
||||
private Instant stopTime;
|
||||
|
||||
private double totalDistance_m;
|
||||
private Distance totalDistance;
|
||||
// Updated when new points are received, may be stale.
|
||||
private Duration totalTime;
|
||||
// Based on when we believe the user is traveling.
|
||||
private Duration movingTime;
|
||||
// The maximum speed (meters/second) that we believe is valid.
|
||||
private double maxSpeed_mps;
|
||||
private Speed maxSpeed;
|
||||
private Float totalAltitudeGain_m = null;
|
||||
private Float totalAltitudeLoss_m = null;
|
||||
|
||||
@@ -62,10 +65,10 @@ public class TrackStatistics {
|
||||
public TrackStatistics(TrackStatistics other) {
|
||||
startTime = other.startTime;
|
||||
stopTime = other.stopTime;
|
||||
totalDistance_m = other.totalDistance_m;
|
||||
totalDistance = other.totalDistance;
|
||||
totalTime = other.totalTime;
|
||||
movingTime = other.movingTime;
|
||||
maxSpeed_mps = other.maxSpeed_mps;
|
||||
maxSpeed = other.maxSpeed;
|
||||
altitudeExtremities.set(other.altitudeExtremities.getMin(), other.altitudeExtremities.getMax());
|
||||
totalAltitudeGain_m = other.totalAltitudeGain_m;
|
||||
totalAltitudeLoss_m = other.totalAltitudeLoss_m;
|
||||
@@ -89,10 +92,10 @@ public class TrackStatistics {
|
||||
stopTime = stopTime.isAfter(other.stopTime) ? stopTime : other.stopTime;
|
||||
}
|
||||
|
||||
totalDistance_m += other.totalDistance_m;
|
||||
totalDistance = totalDistance.plus(other.totalDistance);
|
||||
totalTime = totalTime.plus(other.totalTime);
|
||||
movingTime = movingTime.plus(other.movingTime);
|
||||
maxSpeed_mps = Math.max(maxSpeed_mps, other.maxSpeed_mps);
|
||||
maxSpeed = Speed.max(maxSpeed, other.maxSpeed);
|
||||
if (other.altitudeExtremities.hasData()) {
|
||||
altitudeExtremities.update(other.altitudeExtremities.getMin());
|
||||
altitudeExtremities.update(other.altitudeExtremities.getMax());
|
||||
@@ -121,10 +124,10 @@ public class TrackStatistics {
|
||||
startTime = null;
|
||||
stopTime = null;
|
||||
|
||||
setTotalDistance(0);
|
||||
setTotalDistance(Distance.of(0));
|
||||
setTotalTime(Duration.ofSeconds(0));
|
||||
setMovingTime(Duration.ofSeconds(0));
|
||||
setMaxSpeed(0);
|
||||
setMaxSpeed(Speed.zero());
|
||||
setTotalAltitudeGain(null);
|
||||
setTotalAltitudeLoss(null);
|
||||
}
|
||||
@@ -157,16 +160,16 @@ public class TrackStatistics {
|
||||
this.stopTime = stopTime;
|
||||
}
|
||||
|
||||
public double getTotalDistance() {
|
||||
return totalDistance_m;
|
||||
public Distance getTotalDistance() {
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
public void setTotalDistance(double totalDistance_m) {
|
||||
this.totalDistance_m = totalDistance_m;
|
||||
public void setTotalDistance(Distance totalDistance_m) {
|
||||
this.totalDistance = totalDistance_m;
|
||||
}
|
||||
|
||||
public void addTotalDistance(double distance_m) {
|
||||
totalDistance_m += distance_m;
|
||||
public void addTotalDistance(Distance distance_m) {
|
||||
totalDistance = totalDistance.plus(distance_m);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,35 +198,26 @@ public class TrackStatistics {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the average speed in meters/second.
|
||||
* Gets the average speed.
|
||||
* This calculation only takes into account the displacement until the last point that was accounted for in statistics.
|
||||
*/
|
||||
public double getAverageSpeed() {
|
||||
if (totalTime.isZero()) {
|
||||
return 0.0;
|
||||
public Speed getAverageSpeed() {
|
||||
if (totalDistance.isZero() && totalDistance.isZero()) {
|
||||
return Speed.of(0);
|
||||
}
|
||||
return totalDistance_m / (double) totalTime.getSeconds();
|
||||
return Speed.of(totalDistance.toM() / totalTime.getSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the average moving speed in meters/second.
|
||||
*/
|
||||
public double getAverageMovingSpeed() {
|
||||
if (movingTime.isZero()) {
|
||||
return 0.0;
|
||||
}
|
||||
return totalDistance_m / (double) movingTime.getSeconds();
|
||||
public Speed getAverageMovingSpeed() {
|
||||
return Speed.of(totalDistance, movingTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum speed in meters/second.
|
||||
*/
|
||||
public double getMaxSpeed() {
|
||||
return Math.max(maxSpeed_mps, getAverageMovingSpeed());
|
||||
public Speed getMaxSpeed() {
|
||||
return Speed.max(maxSpeed, getAverageMovingSpeed());
|
||||
}
|
||||
|
||||
public void setMaxSpeed(double maxSpeed_mps) {
|
||||
this.maxSpeed_mps = maxSpeed_mps;
|
||||
public void setMaxSpeed(Speed maxSpeed) {
|
||||
this.maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
public boolean hasAltitudeMin() {
|
||||
|
||||
@@ -23,8 +23,9 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Distance;
|
||||
import de.dennisguse.opentracks.content.data.Speed;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
|
||||
/**
|
||||
* Updater for {@link TrackStatistics}.
|
||||
@@ -103,12 +104,12 @@ public class TrackStatisticsUpdater {
|
||||
* @param trackPoint the trackPoint
|
||||
* @param minGPSDistance the min recording distance
|
||||
*/
|
||||
public void addTrackPoint(TrackPoint trackPoint, int minGPSDistance) {
|
||||
public void addTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
|
||||
internalAddTrackPoint(trackPoint, minGPSDistance);
|
||||
Log.d(TAG, this.toString());
|
||||
}
|
||||
|
||||
private void internalAddTrackPoint(TrackPoint trackPoint, int minGPSDistance) {
|
||||
private void internalAddTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
|
||||
if (!trackInitialized) {
|
||||
trackStatistics.setStartTime(trackPoint.getTime());
|
||||
trackInitialized = true;
|
||||
@@ -158,8 +159,8 @@ public class TrackStatisticsUpdater {
|
||||
|
||||
if (!trackPoint.hasSensorDistance()) {
|
||||
// GPS-based distance/speed
|
||||
float movingDistance = lastMovingTrackPoint.distanceToPrevious(trackPoint);
|
||||
if (movingDistance < minGPSDistance && !trackPoint.isMoving()) {
|
||||
Distance movingDistance = lastMovingTrackPoint.distanceToPrevious(trackPoint);
|
||||
if (movingDistance.lessThan(minGPSDistance) && !trackPoint.isMoving()) {
|
||||
speedBuffer_mps.reset();
|
||||
lastTrackPoint = trackPoint;
|
||||
return;
|
||||
@@ -196,13 +197,6 @@ public class TrackStatisticsUpdater {
|
||||
speedBuffer_mps.reset();
|
||||
}
|
||||
|
||||
public void addTrackPoint(TrackPointIterator iterator, int minRecordingDistance) {
|
||||
while (iterator.hasNext()) {
|
||||
TrackPoint location = iterator.next();
|
||||
addTrackPoint(location, minRecordingDistance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the smoothed altitude over several readings.
|
||||
* The altitude readings is noisy so the smoothed altitude is better than the raw altitude for many tasks.
|
||||
@@ -211,8 +205,8 @@ public class TrackStatisticsUpdater {
|
||||
return altitudeBuffer_m.getAverage();
|
||||
}
|
||||
|
||||
public double getSmoothedSpeed() {
|
||||
return speedBuffer_mps.getAverage();
|
||||
public Speed getSmoothedSpeed() {
|
||||
return Speed.of(speedBuffer_mps.getAverage());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,9 +217,10 @@ public class TrackStatisticsUpdater {
|
||||
if (!trackPoint.isMoving()) {
|
||||
speedBuffer_mps.reset();
|
||||
} else if (isValidSpeed(trackPoint, lastTrackPoint)) {
|
||||
speedBuffer_mps.setNext(trackPoint.getSpeed());
|
||||
if (speedBuffer_mps.getAverage() > currentSegment.getMaxSpeed()) {
|
||||
currentSegment.setMaxSpeed(speedBuffer_mps.getAverage());
|
||||
speedBuffer_mps.setNext(trackPoint.getSpeed().toMPS());
|
||||
Speed average = Speed.of(speedBuffer_mps.getAverage());
|
||||
if (average.greaterThan(currentSegment.getMaxSpeed())) {
|
||||
currentSegment.setMaxSpeed(average);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Invalid speed. speed: " + trackPoint.getSpeed() + " lastLocationSpeed: " + lastTrackPoint.getSpeed());
|
||||
@@ -243,27 +238,26 @@ public class TrackStatisticsUpdater {
|
||||
|
||||
private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
|
||||
// There are a lot of noisy speed readings. Do the cheapest checks first, most expensive last.
|
||||
if (trackPoint.getSpeed() == 0) {
|
||||
if (trackPoint.getSpeed().isZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following code will ignore unlikely readings. 128 m/s seems to be an internal android error code.
|
||||
if (Math.abs(trackPoint.getSpeed() - 128) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the speed seems physically likely. Ignore any speeds that imply acceleration greater than 2g.
|
||||
Duration timeDifference = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime());
|
||||
double speedDifference = Math.abs(lastTrackPoint.getSpeed() - trackPoint.getSpeed());
|
||||
if (speedDifference > MAX_ACCELERATION * timeDifference.toMillis()) {
|
||||
return false;
|
||||
Speed maxAcceleration = Speed.of(MAX_ACCELERATION * timeDifference.toMillis());
|
||||
{
|
||||
// See if the speed seems physically likely. Ignore any speeds that imply acceleration greater than 2g.
|
||||
Speed speedDifference = Speed.absDiff(lastTrackPoint.getSpeed(), trackPoint.getSpeed());
|
||||
if (speedDifference.greaterThan(maxAcceleration)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only check if the speed buffer is full. Check that the speed is less than 10X the smoothed average and the speed difference doesn't imply 2g acceleration.
|
||||
if (speedBuffer_mps.isFull()) {
|
||||
double average = speedBuffer_mps.getAverage();
|
||||
double diff = Math.abs(average - trackPoint.getSpeed());
|
||||
return (trackPoint.getSpeed() < average * 10) && (diff < MAX_ACCELERATION * timeDifference.toMillis());
|
||||
Speed average = Speed.of(speedBuffer_mps.getAverage());
|
||||
Speed speedDifference = Speed.absDiff(average, trackPoint.getSpeed());
|
||||
|
||||
return trackPoint.getSpeed().lessThan(average.mul(10)) && speedDifference.lessThan(maxAcceleration);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user