feat(train): elevation from the barometer, its pressure kept raw (ADR 0030, D49)
11c: where a recording has GPS and the phone a barometer, the service averages its readings over 5 s into the file's `b` lines and the workout's new `pressure` series (tenths of a pascal). The page, Health Connect's totals and the exported files take the fixes' altitudes from it: the standard atmosphere's height at the pressure, levelled by the median of GPS's altitudes less those; climbs count above 1 m. Workouts recorded before keep GPS's altitudes; an older app skips the series. Not tried on a phone yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
128ba1f6c8
commit
57cbd97fd1
1 changed files with 320 additions and 11 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/plan/model/plan.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/recording/data/recorded_workout.dart';
|
||||
|
|
@ -131,6 +133,67 @@ void main() {
|
|||
expect(analysis.elevationGainMetres, 12);
|
||||
});
|
||||
|
||||
group("the barometer's elevation (D49)", () {
|
||||
/// The pressure, in tenths of a pascal, [metres] above the standard sea
|
||||
/// level.
|
||||
int pressureAt(num metres) =>
|
||||
(1013250 * pow(1 - metres / 44330, 5.255)).round();
|
||||
|
||||
test("it gives the climb, its level the GPS altitudes' median", () {
|
||||
// GPS wobbles by 6 m around 100 m; the air says a steady 20 m climb.
|
||||
final noisy = [100, 106, 94, 106, 94, 106, 94, 106, 94, 106, 100];
|
||||
final recording = Recording(
|
||||
activity: Activity.running,
|
||||
startedAt: start,
|
||||
fixes: [
|
||||
for (final (i, m) in noisy.indexed)
|
||||
north(i * 10, i * 30, altitudeCm: m * 100),
|
||||
],
|
||||
pressures: [
|
||||
for (var i = 0; i <= 10; i++)
|
||||
Pressure(time: at(i * 10), decipascals: pressureAt(500 + 2 * i)),
|
||||
],
|
||||
endedAt: at(100),
|
||||
);
|
||||
|
||||
final analysis = analysed(recording);
|
||||
// Each 2 m counts: the barometer's noise is a fraction of a metre.
|
||||
expect(analysis.elevationGainMetres, 20);
|
||||
// 500 m by the standard air, moved by the median of GPS's altitudes
|
||||
// less the barometer's (410 m).
|
||||
expect(analysis.elevation.first.value, closeTo(90, 0.1));
|
||||
expect(analysis.elevation.last.value, closeTo(110, 0.1));
|
||||
|
||||
final gps = analysed(
|
||||
Recording(
|
||||
activity: Activity.running,
|
||||
startedAt: start,
|
||||
fixes: recording.fixes,
|
||||
endedAt: at(100),
|
||||
),
|
||||
);
|
||||
expect(gps.elevationGainMetres, greaterThan(20));
|
||||
});
|
||||
|
||||
test('without GPS altitudes, it stands by the standard air', () {
|
||||
final analysis = analysed(
|
||||
Recording(
|
||||
activity: Activity.running,
|
||||
startedAt: start,
|
||||
fixes: [for (var i = 0; i <= 4; i++) north(i * 10, i * 30)],
|
||||
pressures: [
|
||||
Pressure(time: at(0), decipascals: pressureAt(300)),
|
||||
Pressure(time: at(40), decipascals: pressureAt(320)),
|
||||
],
|
||||
endedAt: at(40),
|
||||
),
|
||||
);
|
||||
expect(analysis.elevationGainMetres, 20);
|
||||
// Between two readings, the pressure is taken as it went.
|
||||
expect(analysis.elevation[2].value, closeTo(310, 0.5));
|
||||
});
|
||||
});
|
||||
|
||||
test('without altitudes it has no elevation gained, nor its chart', () {
|
||||
final analysis = analysed(run([north(0, 0), north(60, 200)]));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue