@@ 200,6 200,10 @@ def guess_type(analysis) -> str:
except:
return 'Exercise'
+# Speed (in m/s) that is considered "moving", lower speeds are considered
+# "stopped"
+MOVING_THRESHOLD = 0.05
+
def analyse(track: Track, athlete_data: Mapping[str, float], raw: bool = False):
pos = track.positions
raw_hr = track.hr
@@ 224,6 228,16 @@ def analyse(track: Track, athlete_data: Mapping[str, float], raw: bool = False):
dist[i][1] = length_acc
# print(pos[i])
+ # since time values in the `dist` array are relative to the start, elapsed
+ # time is just the last time value from the array
+ elapsed_seconds = dist[-1][0]
+
+ time_deltas = np.diff(dist[:, 0])
+ dist_deltas = np.diff(dist[:, 1])
+ speed = dist_deltas / time_deltas
+ moving_seconds = np.dot(np.greater(speed, MOVING_THRESHOLD), time_deltas)
+ assert moving_seconds <= elapsed_seconds
+
hr = np.zeros((raw_hr.shape[0], 2))
if raw_hr.shape[0] > 0:
hr[:, 1] = raw_hr[:, 1]
@@ 248,9 262,6 @@ def analyse(track: Track, athlete_data: Mapping[str, float], raw: bool = False):
max_hr = None
min_hr = None
- # elapsed_seconds = (pos[-1][0] - pos[0][0]).item().total_seconds()
- elapsed_seconds = dist[-1][0]
-
weight = athlete_data.get('weight')
if weight is not None:
energy = round(estimate_energy(dist[-1][1],
@@ 260,12 271,10 @@ def analyse(track: Track, athlete_data: Mapping[str, float], raw: bool = False):
else:
energy = None
-
-
result = {
'distance': dist[-1][1],
'elapsed_seconds': elapsed_seconds,
- 'moving_seconds': elapsed_seconds, # TODO: real "moving time" calculation
+ 'moving_seconds': moving_seconds,
'start_date': pos[0][0].item(),
'avg_hr': avg_hr,
'max_hr': max_hr,
@@ 51,6 51,18 @@ class TestFitImport(SimpleTestCase):
npt.assert_allclose(a['elapsed_seconds'], 1533)
npt.assert_allclose(a['distance'], 4790, atol=1)
+class TestAnalysis(SimpleTestCase):
+ def setUp(self):
+ with open('test/data/sample_walk.fit', 'rb') as f:
+ content = f.read()
+ self.track = from_fit_bytes(content)
+
+ def test_moving_time(self):
+ a = analyse(self.track, {})
+
+ npt.assert_allclose(a['elapsed_seconds'], 51 * 60 + 23, atol=1)
+ npt.assert_allclose(a['moving_seconds'], 50 * 60, atol=10)
+
class TestStravaImport(SimpleTestCase):
def test_import(self):