Commit 4f7789bb authored by Administrator's avatar Administrator

form power on activity level

parent 205c3415
......@@ -92,6 +92,8 @@ const tableActivity = SqfEntityTable(
SqfEntityField('sdevGroundTime', DbType.real),
SqfEntityField('avgLegSpringStiffness', DbType.real),
SqfEntityField('sdevLegSpringStiffness', DbType.real),
SqfEntityField('avgFormPower', DbType.real),
SqfEntityField('sdevFormPower', DbType.real),
SqfEntityFieldRelationship(
parentTable: tableAthlete,
......@@ -185,6 +187,8 @@ const tableLap = SqfEntityTable(
SqfEntityField('sdevGroundTime', DbType.real),
SqfEntityField('avgLegSpringStiffness', DbType.real),
SqfEntityField('sdevLegSpringStiffness', DbType.real),
SqfEntityField('avgFormPower', DbType.real),
SqfEntityField('sdevFormPower', DbType.real),
SqfEntityFieldRelationship(
parentTable: tableEvent,
......
This diff is collapsed.
......@@ -180,6 +180,26 @@ class Activity extends ChangeNotifier {
return db.sdevLegSpringStiffness;
}
Future<double> get avgFormPower async {
if (db.avgFormPower == null) {
List<Event> records = await this.records;
db.avgFormPower = Lap.calculateAverageFormPower(records: records);
await db.save();
notifyListeners();
}
return db.avgFormPower;
}
Future<double> get sdevFormPower async {
if (db.sdevFormPower == null) {
List<Event> records = await this.records;
db.sdevFormPower = Lap.calculateSdevFormPower(records: records);
await db.save();
notifyListeners();
}
return db.sdevFormPower;
}
parse({@required Athlete athlete}) async {
var appDocDir = await getApplicationDocumentsDirectory();
......
......@@ -135,6 +135,9 @@ class Event {
case "power":
sum = sum + record.db.power;
break;
case "formPower":
sum = sum + record.db.formPower;
break;
case "heartRate":
sum = sum + record.db.heartRate;
}
......@@ -171,9 +174,6 @@ class Event {
case "verticalOscillation":
sum = sum + record.db.verticalOscillation;
break;
case "formPower":
sum = sum + record.db.formPower;
break;
case "legSpringStiffness":
sum = sum + record.db.legSpringStiffness;
}
......
......@@ -223,4 +223,19 @@ class Lap {
records.map((record) => record.db.legSpringStiffness).nonZeroDoubles();
return legSpringStiffnesses.sdev();
}
static double calculateAverageFormPower({List<Event> records}) {
var legSpringStiffnesses =
records.map((record) => record.db.formPower).nonZeroInts();
if (legSpringStiffnesses.length > 0) {
return legSpringStiffnesses.mean();
} else
return -1;
}
static double calculateSdevFormPower({List<Event> records}) {
var legSpringStiffnesses =
records.map((record) => record.db.formPower).nonZeroInts();
return legSpringStiffnesses.sdev();
}
}
......@@ -6,6 +6,7 @@ import 'package:encrateia/widgets/activity_power_widget.dart';
import 'package:encrateia/widgets/activity_power_duration_widget.dart';
import 'package:encrateia/widgets/activity_ground_time_widget.dart';
import 'package:encrateia/widgets/activity_leg_spring_stiffness_widget.dart';
import 'package:encrateia/widgets/activity_form_power_widget.dart';
import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
......@@ -20,7 +21,7 @@ class ShowActivityScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 8,
length: 9,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
......@@ -48,11 +49,15 @@ class ShowActivityScreen extends StatelessWidget {
),
Tab(
icon: Icon(Icons.vertical_align_bottom),
text: "Grnd.time",
text: "Grnd.Time",
),
Tab(
icon: Icon(Icons.airline_seat_recline_extra),
text: "Leg spr.stiff.",
text: "Leg Spr.Stiff.",
),
Tab(
icon: Icon(Icons.accessibility_new),
text: "Form Power",
),
Tab(
icon: Icon(Icons.storage),
......@@ -73,6 +78,7 @@ class ShowActivityScreen extends StatelessWidget {
ActivityPowerDurationWidget(activity: activity),
ActivityGroundTimeWidget(activity: activity),
ActivityLegSpringStiffnessWidget(activity: activity),
ActivityFormPowerWidget(activity: activity),
ActivityMetadataWidget(activity: activity),
]),
),
......
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/models/lap.dart';
import 'package:encrateia/models/plot_point.dart';
class ActivityFormPowerChart extends StatelessWidget {
final List<Event> records;
final Activity activity;
final colorArray = [
MaterialPalette.white,
MaterialPalette.gray.shade200,
];
ActivityFormPowerChart({this.records, @required this.activity});
@override
Widget build(BuildContext context) {
var nonZero = records.where((value) => value.db.formPower > 0);
var smoothedRecords = Event.toIntDataPoints(
attribute: "formPower",
records: nonZero,
amount: 30,
);
List<Series<dynamic, num>> data = [
new Series<IntPlotPoint, int>(
id: 'Form power',
colorFn: (_, __) => MaterialPalette.green.shadeDefault,
domainFn: (IntPlotPoint record, _) => record.domain,
measureFn: (IntPlotPoint record, _) => record.measure,
data: smoothedRecords,
)
];
return FutureBuilder<List<Lap>>(
future: activity.laps,
builder: (BuildContext context, AsyncSnapshot<List<Lap>> snapshot) {
if (snapshot.hasData) {
var laps = snapshot.data;
return Container(
height: 300,
child: LineChart(
data,
domainAxis: NumericAxisSpec(
viewport: NumericExtents(0, nonZero.last.db.distance + 500),
tickProviderSpec: BasicNumericTickProviderSpec(
desiredTickCount: 6,
),
),
primaryMeasureAxis: NumericAxisSpec(
tickProviderSpec: BasicNumericTickProviderSpec(
zeroBound: false,
dataIsInWholeNumbers: true,
desiredTickCount: 5),
),
animate: false,
layoutConfig: LayoutConfig(
leftMarginSpec: MarginSpec.fixedPixel(60),
topMarginSpec: MarginSpec.fixedPixel(20),
rightMarginSpec: MarginSpec.fixedPixel(20),
bottomMarginSpec: MarginSpec.fixedPixel(40),
),
behaviors: [
RangeAnnotation(rangeAnnotations(laps: laps)),
ChartTitle(
'Form Power (W)',
titleStyleSpec: TextStyleSpec(fontSize: 13),
behaviorPosition: BehaviorPosition.start,
titleOutsideJustification: OutsideJustification.end,
),
ChartTitle(
'Distance (m)',
titleStyleSpec: TextStyleSpec(fontSize: 13),
behaviorPosition: BehaviorPosition.bottom,
titleOutsideJustification: OutsideJustification.end,
),
],
),
);
} else {
return Container(
height: 100,
child: Center(child: Text("Loading")),
);
}
},
);
}
rangeAnnotations({List<Lap> laps}) {
return [
for (int index = 0; index < laps.length; index++)
RangeAnnotationSegment(
laps
.sublist(0, index + 1)
.map((lap) => lap.db.totalDistance)
.reduce((a, b) => a + b) -
laps[index].db.totalDistance,
laps
.sublist(0, index + 1)
.map((lap) => lap.db.totalDistance)
.reduce((a, b) => a + b),
RangeAnnotationAxisType.domain,
color: colorArray[index % 2],
endLabel: 'Lap ${laps[index].index}',
)
];
}
}
import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/utils/list_utils.dart';
import 'package:encrateia/utils/num_utils.dart';
import 'activity_form_power_chart.dart';
class ActivityFormPowerWidget extends StatefulWidget {
final Activity activity;
ActivityFormPowerWidget({this.activity});
@override
_ActivityFormPowerWidgetState createState() => _ActivityFormPowerWidgetState();
}
class _ActivityFormPowerWidgetState extends State<ActivityFormPowerWidget> {
List<Event> records = [];
String avgFormPowerString = "Loading ...";
String sdevFormPowerString = "Loading ...";
@override
void initState() {
getData();
super.initState();
}
@override
Widget build(context) {
if (records.length > 0) {
var powerValues = records.map((value) => value.db.formPower).nonZeroInts();
if (powerValues.length > 0) {
return ListTileTheme(
iconColor: Colors.deepOrange,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ActivityFormPowerChart(records: records, activity: widget.activity),
ListTile(
leading: Icon(Icons.ev_station),
title: Text(avgFormPowerString),
subtitle: Text("average form power"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(sdevFormPowerString),
subtitle: Text("standard deviation form power"),
),
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
],
),
);
} else {
return Center(
child: Text("No form power data available."),
);
}
} else {
return Center(
child: Text("Loading"),
);
}
}
getData() async {
Activity activity = widget.activity;
records = await activity.records;
double avg = await activity.avgFormPower;
setState(() {
avgFormPowerString = avg.toStringOrDashes(1) + " W";
});
double sdev = await activity.sdevFormPower;
setState(() {
sdevFormPowerString = sdev.toStringOrDashes(2) + " W";
});
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment