Elevation gain: apply exponential smoothing and limit changes (defined change diff per sensor value).

This commit is contained in:
Dennis Guse
2020-06-21 20:01:47 +02:00
parent 8a14bc46f6
commit c7db4f528e
4 changed files with 56 additions and 24 deletions
@@ -20,10 +20,11 @@ public class PressureSensorUtilsTest {
}
}
// Simulate a sudden drop of elevation.
// test data
@Test
public void computeChanges_downhill() {
float[] sensorValues_hPa = 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, 1015.14f, 1015.15f};
float[] sensorValues_hPa = 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};
float firstSensorValue = sensorValues_hPa[0];
// when
@@ -34,18 +35,15 @@ public class PressureSensorUtilsTest {
for (float v : sensorValues_hPa) {
PressureSensorUtils.ElevationChange elevationChange = PressureSensorUtils.computeChanges_m(lastUsedPressureValue_hPa, v);
if (elevationChange != null) {
if (elevationChange.getElevationChange_m() > 0) {
elevationGain_m += elevationChange.getElevationChange_m();
} else {
elevationLoss_m += elevationChange.getElevationChange_m();
}
elevationGain_m += elevationChange.getElevationGain_m();
elevationLoss_m += elevationChange.getElevationLoss_m();
lastUsedPressureValue_hPa = elevationChange.getCurrentSensorValue_hPa();
}
}
// then
assertEquals(0f, elevationGain_m, 0.01);
assertEquals(-1.08f, elevationLoss_m, 0.01);
assertEquals(1015.13, lastUsedPressureValue_hPa, 0.01);
assertEquals(-25.0f, elevationLoss_m, 0.01);
assertEquals(1018.01f, lastUsedPressureValue_hPa, 0.01);
}
}
@@ -135,8 +135,6 @@ public class StatisticsRecordedFragment extends Fragment {
speedMovingValue = view.findViewById(R.id.stats_moving_speed_value);
speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit);
elevationCurrentGroup = view.findViewById(R.id.stats_elevation_current_group);
elevationTotalGainValue = view.findViewById(R.id.stats_elevation_gain_value);
elevationTotalGainUnit = view.findViewById(R.id.stats_elevation_gain_unit);
}
@@ -23,7 +23,9 @@ public class ElevationSumManager implements SensorEventListener {
private boolean isConnected = false;
private float lastUsedPressureValue_hPa;
private float lastAcceptedPressureValue_hPa;
private float lastSeenSensorValue_hPa;
private float elevationGain_m;
private float elevationLoss_m;
@@ -38,7 +40,7 @@ public class ElevationSumManager implements SensorEventListener {
}
isConnected = sensorManager.registerListener(this, pressureSensor, SAMPLING_RATE);
lastUsedPressureValue_hPa = Float.NaN;
lastAcceptedPressureValue_hPa = Float.NaN;
reset();
}
@@ -82,21 +84,21 @@ public class ElevationSumManager implements SensorEventListener {
@VisibleForTesting
void onSensorValueChanged(float value_hPa) {
if (Float.isNaN(lastUsedPressureValue_hPa)) {
lastUsedPressureValue_hPa = value_hPa;
if (Float.isNaN(lastAcceptedPressureValue_hPa)) {
lastAcceptedPressureValue_hPa = value_hPa;
lastSeenSensorValue_hPa = value_hPa;
return;
}
PressureSensorUtils.ElevationChange elevationChange = PressureSensorUtils.computeChanges_m(lastUsedPressureValue_hPa, value_hPa);
PressureSensorUtils.ElevationChange elevationChange = PressureSensorUtils.computeChangesWithSmoothing_m(lastAcceptedPressureValue_hPa, lastSeenSensorValue_hPa, value_hPa);
if (elevationChange != null) {
if (elevationChange.getElevationChange_m() > 0) {
elevationGain_m += elevationChange.getElevationChange_m();
} else {
elevationLoss_m += elevationChange.getElevationChange_m();
}
lastUsedPressureValue_hPa = elevationChange.getCurrentSensorValue_hPa();
elevationGain_m += elevationChange.getElevationGain_m();
elevationLoss_m += elevationChange.getElevationLoss_m();
lastAcceptedPressureValue_hPa = elevationChange.getCurrentSensorValue_hPa();
}
lastSeenSensorValue_hPa = value_hPa;
Log.v(TAG, "elevation gain: " + elevationGain_m);
}
}
@@ -7,6 +7,8 @@ public class PressureSensorUtils {
//Everything above is considered a meaningful change in elevation.
private static float ELEVATION_CHANGE_DIFF_M = 5.0f;
private static float EXPONENTIAL_SMOOTHING = 0.3f;
private PressureSensorUtils() {
}
@@ -28,6 +30,23 @@ public class PressureSensorUtils {
public float getElevationChange_m() {
return elevationChange_m;
}
public float getElevationGain_m() {
return elevationChange_m > 0 ? elevationChange_m : 0;
}
public float getElevationLoss_m() {
return elevationChange_m < 0 ? elevationChange_m : 0;
}
}
/**
* Applies exponential smoothing to sensor value before computation.
*/
public static ElevationChange computeChangesWithSmoothing_m(float lastAcceptedSensorValue_hPa, float lastSeenSensorValue_hPa, float currentSensorValue_hPa) {
float nextSensorValue_hPa = EXPONENTIAL_SMOOTHING * currentSensorValue_hPa + (1 - EXPONENTIAL_SMOOTHING) * lastSeenSensorValue_hPa;
return computeChanges_m(lastAcceptedSensorValue_hPa, nextSensorValue_hPa);
}
/**
@@ -35,8 +54,8 @@ public class PressureSensorUtils {
*
* @return null if no meaningful elevation change occurred.
*/
public static ElevationChange computeChanges_m(float lastSensorValue_hPa, float currentSensorValue_hPa) {
float lastSensorValue_m = SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, lastSensorValue_hPa);
public static ElevationChange computeChanges_m(float lastAcceptedSensorValue_hPa, float currentSensorValue_hPa) {
float lastSensorValue_m = SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, lastAcceptedSensorValue_hPa);
float currentSensorValue_m = SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, currentSensorValue_hPa);
float elevationChange_m = currentSensorValue_m - lastSensorValue_m;
@@ -44,6 +63,21 @@ public class PressureSensorUtils {
return null;
}
return new ElevationChange(currentSensorValue_hPa, elevationChange_m);
// Limit elevation change by ELEVATION_CHANGE_DIFF and computes pressure value accordingly.
ElevationChange elevationChange = new ElevationChange(currentSensorValue_hPa, elevationChange_m);
if (elevationChange.getElevationGain_m() > 0) {
return new ElevationChange(getBarometricPressure(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, lastSensorValue_m + ELEVATION_CHANGE_DIFF_M), ELEVATION_CHANGE_DIFF_M);
} else {
return new ElevationChange(getBarometricPressure(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, lastSensorValue_m - ELEVATION_CHANGE_DIFF_M), -1 * ELEVATION_CHANGE_DIFF_M);
}
}
/*
* Barometeric pressure to elevation estimation; inverts of SensorManager.getAltitude(float, float)
* https://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Internationale_H%C3%B6henformel
* {\color{White} p(h)} = p_0 \cdot \left( 1 - \frac{0{,}0065 \frac{\mathrm K}{\mathrm m} \cdot h}{T_0\ } \right)^{5{,}255}
*/
private static float getBarometricPressure(float p0, float altitude_m) {
return (float) (p0 * Math.pow(1.0 - 0.0065 * altitude_m / 288.15, 5.255f));
}
}