From 03abff486b16056d30938e186f9a2a97fc1c4cc4 Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Tue, 2 Nov 2021 00:52:56 -0300 Subject: [PATCH 1/6] millis instead of elapsed time --- lib/datacollection/measurements_collector.dart | 10 +++++----- lib/datacollection/storage.dart | 16 +++++++++++----- lib/edgeimpulse/api_client.dart | 2 +- lib/model/glove_measurement.dart | 12 ++++++------ lib/pages/ble_data_collection_page.dart | 2 +- lib/pages/data_visualization_page.dart | 2 +- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/datacollection/measurements_collector.dart b/lib/datacollection/measurements_collector.dart index a6b4f80..b352bf3 100644 --- a/lib/datacollection/measurements_collector.dart +++ b/lib/datacollection/measurements_collector.dart @@ -91,7 +91,7 @@ class MeasurementsCollector { GloveMeasurement gloveMeasurement = GloveMeasurement.fromFingerMeasurementsList( parsedMeasurements.eventNumber, - parsedMeasurements.elapsedTime, + parsedMeasurements.millis, deviceId, parsedMeasurements.values); // developer.log('map to -> ${gloveMeasurement.toJson().toString()}'); @@ -138,8 +138,8 @@ class MeasurementsCollector { return null; } int eventNum = int.parse(fingerMeasurements.removeAt(0)); - double elapsedTime = double.parse(fingerMeasurements.removeAt(0)); - return _ParsedMeasurements(eventNum, elapsedTime, fingerMeasurements); + double millis = double.parse(fingerMeasurements.removeAt(0)); + return _ParsedMeasurements(eventNum, millis, fingerMeasurements); } void _notifyListeners(GloveMeasurement measurement) { @@ -151,10 +151,10 @@ class MeasurementsCollector { class _ParsedMeasurements { final int eventNumber; - final double elapsedTime; + final double millis; final List values; - _ParsedMeasurements(this.eventNumber, this.elapsedTime, this.values); + _ParsedMeasurements(this.eventNumber, this.millis, this.values); @override String toString() { diff --git a/lib/datacollection/storage.dart b/lib/datacollection/storage.dart index d0c023a..bb3b6ee 100644 --- a/lib/datacollection/storage.dart +++ b/lib/datacollection/storage.dart @@ -155,11 +155,11 @@ class SensorMeasurements { final String deviceName; final String deviceId; final String word; + final List millis; final List> values; - double intervalSumInMillis; SensorMeasurements(this.deviceName, this.deviceId, this.word,this.values, - this.intervalSumInMillis); + this.millis); bool add(GloveMeasurement gloveMeasurement) { if (gloveMeasurement.deviceId != this.deviceId) { @@ -173,7 +173,7 @@ class SensorMeasurements { measurementList.addAll(extractFingerMeasurement(gloveMeasurement.index)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.thumb)); this.values.add(measurementList); - this.intervalSumInMillis = this.intervalSumInMillis + gloveMeasurement.elapsedTimeMs; + this.millis.add(gloveMeasurement.millis); return true; } @@ -193,6 +193,8 @@ class SensorMeasurements { factory SensorMeasurements.fromJson(dynamic json) { List> _values = >[]; + List _millis = []; + if (json['values'] != null) { var jsonLists = json['values'] as List; _values = jsonLists.map((jsonList) { @@ -200,12 +202,16 @@ class SensorMeasurements { return valuesList.map((v) => v as double).toList(); }).toList(); } + if (json['millis'] != null) { + var jsonLists = json['millis'] as List; + _millis = jsonLists.map((v) => v as double).toList(); + } return SensorMeasurements( json['device_name'] as String, json['device_id'] as String, json['word'] as String, _values, - json['interval_sum_in_millis'] as double, + _millis, ); } @@ -215,7 +221,7 @@ class SensorMeasurements { 'device_id': deviceId, 'word': word, 'values': values, - 'interval_sum_in_millis': intervalSumInMillis, + 'millis': millis }; } } diff --git a/lib/edgeimpulse/api_client.dart b/lib/edgeimpulse/api_client.dart index 0c8a042..a2f32fc 100644 --- a/lib/edgeimpulse/api_client.dart +++ b/lib/edgeimpulse/api_client.dart @@ -52,7 +52,7 @@ class EdgeImpulseApiClient { request.headers.set('x-api-key', secret.rightGloveApiKey); } request.headers.set('x-file-name', fileName); - request.headers.set('x-label', sensorMeasurements.word); + request.headers.set('x-label', sensorMeasurements.word); request.add(utf8.encode(json.encode(edgeImpulseBody))); HttpClientResponse response = await request.close(); String reply = await response.transform(utf8.decoder).join(); diff --git a/lib/model/glove_measurement.dart b/lib/model/glove_measurement.dart index 944c44f..793fad7 100644 --- a/lib/model/glove_measurement.dart +++ b/lib/model/glove_measurement.dart @@ -34,18 +34,18 @@ class GloveMeasurement { final String deviceId; final int eventNum; - final double elapsedTimeMs; + final double millis; final Finger thumb; final Finger index; final Finger middle; final Finger ring; final Finger pinky; - GloveMeasurement(this.deviceId, this.eventNum,this.elapsedTimeMs,this.pinky, this.ring, this.middle, this.index, this.thumb); + GloveMeasurement(this.deviceId, this.eventNum,this.millis,this.pinky, this.ring, this.middle, this.index, this.thumb); GloveMeasurement.fromJson(Map json) : deviceId = json['device_id'], eventNum = json['event_num'], - elapsedTimeMs = json['elapsed_time'], + millis = json['millis'], pinky = Finger.fromJson(json['pinky'] as Map), ring = Finger.fromJson(json['ring'] as Map), middle = Finger.fromJson(json['middle'] as Map), @@ -54,7 +54,7 @@ class GloveMeasurement { Map toJson() => { 'device_id': deviceId, - 'elapsed_time': elapsedTimeMs, + 'millis': millis, 'event_num': eventNum, 'pinky' : pinky.toJson(), 'ring': ring.toJson(), @@ -64,7 +64,7 @@ class GloveMeasurement { }; - static fromFingerMeasurementsList(int eventNum, double elapsedTime, String deviceId, List fingerMeasurements) { + static fromFingerMeasurementsList(int eventNum, double millis, String deviceId, List fingerMeasurements) { Map measurementsMap = new Map(); for (final item in fingerMeasurements) { @@ -80,7 +80,7 @@ class GloveMeasurement { Finger? middle = measurementsMap[middleLetter]; Finger? index = measurementsMap[indexLetter]; Finger? thumb = measurementsMap[thumbLetter]; - return new GloveMeasurement(deviceId, eventNum, elapsedTime, pinky!, ring!, middle!, index!, thumb!); + return new GloveMeasurement(deviceId, eventNum, millis, pinky!, ring!, middle!, index!, thumb!); } Finger getFinger(FingerValue fingerName) { diff --git a/lib/pages/ble_data_collection_page.dart b/lib/pages/ble_data_collection_page.dart index 06c2036..ff8fd81 100644 --- a/lib/pages/ble_data_collection_page.dart +++ b/lib/pages/ble_data_collection_page.dart @@ -351,7 +351,7 @@ class _DataVisualizerState extends State if (!_stats.containsKey(measurement.deviceId)) { _stats[measurement.deviceId] = GloveStats(); } else { - _stats[measurement.deviceId]?.update(measurement.elapsedTimeMs); + _stats[measurement.deviceId]?.update(measurement.millis); } }); } diff --git a/lib/pages/data_visualization_page.dart b/lib/pages/data_visualization_page.dart index 330e547..5e86038 100644 --- a/lib/pages/data_visualization_page.dart +++ b/lib/pages/data_visualization_page.dart @@ -196,7 +196,7 @@ class _MeasurementsChartState extends State @override void onMeasurement(GloveMeasurement measurement) { measurementsBuffer.add(measurement); - lastTimestampMs += measurement.elapsedTimeMs; + lastTimestampMs += measurement.millis; Vector3 sensorValues = measurement.getFinger(finger).getSensorValues(sensor); _measurementsX.add(SeriesEntry(lastTimestampMs, sensorValues.getX())); _measurementsY.add(SeriesEntry(lastTimestampMs, sensorValues.getY())); From 9ee6e0fb1243aafbc8db8190efd776bd266570fc Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Tue, 2 Nov 2021 01:14:23 -0300 Subject: [PATCH 2/6] fix calculated avarage elapsed time --- lib/datacollection/storage.dart | 4 +--- lib/edgeimpulse/api_client.dart | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/datacollection/storage.dart b/lib/datacollection/storage.dart index bb3b6ee..036d390 100644 --- a/lib/datacollection/storage.dart +++ b/lib/datacollection/storage.dart @@ -70,10 +70,8 @@ class DeviceMeasurementsFile { static Future create( String deviceName, String deviceId, String word) async { var creationDate = DateTime.now(); - var values = >[]; - double intervalSumInMillis = 0.0; SensorMeasurements json = new SensorMeasurements( - deviceName, deviceId, word, values, intervalSumInMillis); + deviceName, deviceId, word, >[], []); String datetimeStr = format(creationDate); var filename = "${deviceName.substring(0, 1)}_${word}_$datetimeStr"; var file = await new GloveEventsStorage().createFile(filename); diff --git a/lib/edgeimpulse/api_client.dart b/lib/edgeimpulse/api_client.dart index a2f32fc..00c5ac2 100644 --- a/lib/edgeimpulse/api_client.dart +++ b/lib/edgeimpulse/api_client.dart @@ -21,8 +21,12 @@ class EdgeImpulseApiClient { //the algorithm used to sign this file. Either HS256 (HMAC-SHA256) or none (required) iat: datetime.toUtc().millisecondsSinceEpoch ~/1000.0// date when the file was created in seconds since epoch ); - - double averageIntervalInMilliseconds = sensorMeasurements.intervalSumInMillis / double.parse("${sensorMeasurements.values.length}"); + double elapsedTimeSum = 0.0; + for(var i = sensorMeasurements.millis.length -1 ; i > 0 ; i--){ + var elapsedTime = sensorMeasurements.millis[i] - sensorMeasurements.millis[i-1]; + elapsedTimeSum += elapsedTime ; + } + double averageIntervalInMilliseconds = elapsedTimeSum / (sensorMeasurements.values.length * 1.0); developer.log("averageIntervalInMilliseconds: $averageIntervalInMilliseconds", name: TAG); var payload = Payload( deviceName: sensorMeasurements.deviceId, From 2774214c811d85acb160d18a7ab1865642efe68f Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Thu, 4 Nov 2021 22:52:29 -0300 Subject: [PATCH 3/6] new file graphic visualization --- lib/pages/file_data_visualization_page.dart | 152 ++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 lib/pages/file_data_visualization_page.dart diff --git a/lib/pages/file_data_visualization_page.dart b/lib/pages/file_data_visualization_page.dart new file mode 100644 index 0000000..1b58a00 --- /dev/null +++ b/lib/pages/file_data_visualization_page.dart @@ -0,0 +1,152 @@ + + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:lsa_gloves/connection/ble/bluetooth_backend.dart'; +import 'package:lsa_gloves/model/glove_measurement.dart'; +import 'package:lsa_gloves/navigation/navigation_drawer.dart'; +import 'package:provider/provider.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'dart:developer' as developer; + +class FileDataVisualizationPage extends StatefulWidget { + const FileDataVisualizationPage({Key? key}) : super(key: key); + + @override + _FileDataVisualizationPageState createState() => _FileDataVisualizationPageState(); +} + +class _FileDataVisualizationPageState extends State { + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, backend, _) => SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text('Visualización'), + ), + drawer: NavDrawer(), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child:MeasurementsChart() + ) + + ], + )), + ))); + } +} + +class MeasurementsChart extends StatefulWidget { + final List measurements; + + const MeasurementsChart( + {Key? key, required this.measurements}) + : super(key: key); + + @override + _MeasurementsChartState createState() => + _MeasurementsChartState(measurements); +} + +class _MeasurementsChartState extends State { + + SensorValue sensor = SensorValue.Acceleration; + + List _measurements; + static const int maxWindowSize = 100; + List _measurementsX = []; + List _measurementsY = []; + List _measurementsZ = []; + + _MeasurementsChartState( + this._measurements); + + @override + void initState() { + super.initState(); + this._measurements.forEach((gloveMeasurement) { + gloveMeasurement.elapsedTimeMs + var sensorValues = gloveMeasurement.getFinger(FingerValue.Thumb).getSensorValues(sensor); + _measurementsX.add(SeriesEntry(lastTimestampMs, sensorValues.getX())); + _measurementsY.add(SeriesEntry(lastTimestampMs, sensorValues.getY())); + _measurementsZ.add(SeriesEntry(lastTimestampMs, sensorValues.getZ())); + + }); + } + + + @override + Widget build(BuildContext context) { + return SfCartesianChart( + series: [ + LineSeries( + name: sensor.getXLabel(), + dataSource: _measurementsX, + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y, + onRendererCreated: (ChartSeriesController controller) { + _chartSeriesControllerX = controller; + }), + LineSeries( + name: sensor.getYLabel(), + dataSource: _measurementsY, + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y, + onRendererCreated: (ChartSeriesController controller) { + _chartSeriesControllerY = controller; + }), + LineSeries( + name: sensor.getZLabel(), + dataSource: _measurementsZ, + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y, + onRendererCreated: (ChartSeriesController controller) { + _chartSeriesControllerZ = controller; + }), + ], + legend: Legend(isVisible: true, position: LegendPosition.bottom), + primaryXAxis: NumericAxis( + numberFormat: NumberFormat("##,###s") + ) + ); + } + + @override + void onMeasurement(GloveMeasurement measurement) { + measurementsBuffer.add(measurement); + + if (measurementsBuffer.length > maxWindowSize) { + _measurementsX.removeAt(0); + _measurementsY.removeAt(0); + _measurementsZ.removeAt(0); + measurementsBuffer.remove(0); + _chartSeriesControllerX?.updateDataSource( + addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); + _chartSeriesControllerY?.updateDataSource( + addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); + _chartSeriesControllerZ?.updateDataSource( + addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); + } else { + int measurementsAmount = _measurementsX.length; + _chartSeriesControllerX?.updateDataSource( + addedDataIndex: measurementsAmount - 1); + _chartSeriesControllerY?.updateDataSource( + addedDataIndex: measurementsAmount - 1); + _chartSeriesControllerZ?.updateDataSource( + addedDataIndex: measurementsAmount - 1); + } + } +} + +class SeriesEntry { + double x; + double y; + + SeriesEntry(this.x, this.y); +} From f0861c44a1b576ca1b6f520e6fb343e0f6fd0e86 Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Fri, 5 Nov 2021 02:02:58 -0300 Subject: [PATCH 4/6] new graphics --- lib/datacollection/storage.dart | 2 +- lib/main.dart | 2 + lib/pages/file_content_chart_page.dart | 205 ++++++++++++++++++++ lib/pages/file_data_visualization_page.dart | 152 --------------- lib/pages/file_manager_page.dart | 7 +- 5 files changed, 213 insertions(+), 155 deletions(-) create mode 100644 lib/pages/file_content_chart_page.dart delete mode 100644 lib/pages/file_data_visualization_page.dart diff --git a/lib/datacollection/storage.dart b/lib/datacollection/storage.dart index 036d390..27e8b50 100644 --- a/lib/datacollection/storage.dart +++ b/lib/datacollection/storage.dart @@ -165,11 +165,11 @@ class SensorMeasurements { return false; } List measurementList = []; + measurementList.addAll(extractFingerMeasurement(gloveMeasurement.thumb)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.pinky)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.ring)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.middle)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.index)); - measurementList.addAll(extractFingerMeasurement(gloveMeasurement.thumb)); this.values.add(measurementList); this.millis.add(gloveMeasurement.millis); return true; diff --git a/lib/main.dart b/lib/main.dart index ff80a01..80b2d46 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lsa_gloves/datacollection/file_content.dart'; import 'package:lsa_gloves/pages/ble_connection_error_page.dart'; import 'package:lsa_gloves/pages/ble_devices_connection_page.dart'; +import 'package:lsa_gloves/pages/file_content_chart_page.dart'; import 'package:lsa_gloves/pages/home_page.dart'; import 'package:provider/provider.dart'; @@ -24,6 +25,7 @@ class MyApp extends StatelessWidget { return MaterialApp( routes: { FileContentPage.routeName: (context) => FileContentPage(), + FileContentChartPage.routeName: (context) => FileContentChartPage(), BleGloveConnectionPage.routeName: (context) => BleGloveConnectionPage(), BleConnectionErrorPage.routeName: (context) => BleConnectionErrorPage(), }, diff --git a/lib/pages/file_content_chart_page.dart b/lib/pages/file_content_chart_page.dart new file mode 100644 index 0000000..be02a45 --- /dev/null +++ b/lib/pages/file_content_chart_page.dart @@ -0,0 +1,205 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:lsa_gloves/connection/ble/bluetooth_backend.dart'; +import 'package:lsa_gloves/datacollection/storage.dart'; +import 'package:lsa_gloves/model/glove_measurement.dart'; +import 'package:lsa_gloves/navigation/navigation_drawer.dart'; +import 'package:provider/provider.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'dart:developer' as developer; + +class FileContentChartPage extends StatefulWidget { + static const routeName = '/fileContentChart'; + + const FileContentChartPage({Key? key}) : super(key: key); + + @override + _FileContentChartPageState createState() => _FileContentChartPageState(); +} + +class _FileContentChartPageState extends State { + int _fingerChosen = 0; + + @override + Widget build(BuildContext context) { + SensorMeasurements sensorMeasurements = + ModalRoute.of(context)!.settings.arguments as SensorMeasurements; + + return Consumer( + builder: (context, backend, _) => SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text('Visualización'), + ), + drawer: NavDrawer(), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Wrap( + spacing: 6.0, + runSpacing: 6.0, + children: List.generate( + FingerValue.values.length, (int index) { + return ChoiceChip( + label: Text(FingerValue.values[index].spanishName()), + selected: _fingerChosen == index, + selectedColor: Colors.cyan, + onSelected: (bool selected) { + setState(() { + _fingerChosen = selected ? index : 0; + }); + }, + backgroundColor: Colors.blue, + labelStyle: TextStyle(color: Colors.white), + ); + }), + ), + Expanded( + child: MeasurementsChart( + measurements: sensorMeasurements, + finger: FingerValue.values[_fingerChosen], + key: ValueKey(_fingerChosen), + sensor: SensorValue.Acceleration, + title: "Aceleracion", + legend: false)), + Expanded( + child: MeasurementsChart( + measurements: sensorMeasurements, + finger: FingerValue.values[_fingerChosen], + key: ValueKey(_fingerChosen), + sensor: SensorValue.Gyroscope, + title: "Velocidad angular", + legend: false)), + Expanded( + child: MeasurementsChart( + measurements: sensorMeasurements, + finger: FingerValue.values[_fingerChosen], + key: ValueKey(_fingerChosen), + sensor: SensorValue.Inclination, + title: "Inclinacion", + legend: true)) + ], + )), + ))); + } +} + +class MeasurementsChart extends StatefulWidget { + final SensorMeasurements measurements; + final FingerValue finger; + final SensorValue sensor; + final String title; + final bool legend; + + const MeasurementsChart( + {Key? key, + required this.measurements, + required this.finger, + required this.sensor, + required this.title, + required this.legend}) + : super(key: key); + + @override + _MeasurementsChartState createState() => + _MeasurementsChartState(measurements, finger, sensor, title, legend); +} + +class _MeasurementsChartState extends State { + SensorMeasurements _measurements; + FingerValue finger; + String title; + bool legend; + SensorValue sensor; + late ZoomPanBehavior _zoomPanBehavior; + + List _measurementsX = []; + List _measurementsY = []; + List _measurementsZ = []; + + _MeasurementsChartState( + this._measurements, this.finger, this.sensor, this.title, this.legend); + + @override + void initState() { + super.initState(); + _zoomPanBehavior = ZoomPanBehavior( + enablePinching: true, enablePanning: true, zoomMode: ZoomMode.xy); + } + + @override + Widget build(BuildContext context) { + var initialTimestamp = 0.0; + for (var i = 0; i < this._measurements.values.length; i++) { + if (i == 0) { + initialTimestamp = this._measurements.millis[i]; + } + var timestamp = (this._measurements.millis[i] - initialTimestamp); + var fingerValues = getFingerValues(this._measurements.values[i]); + var sensorValues = this.getSensorValues(fingerValues); + _measurementsX.add(SeriesEntry(timestamp, sensorValues.getX())); + _measurementsY.add(SeriesEntry(timestamp, sensorValues.getY())); + _measurementsZ.add(SeriesEntry(timestamp, sensorValues.getZ())); + } + return SfCartesianChart( + title: ChartTitle(text: this.title), + zoomPanBehavior: _zoomPanBehavior, + series: [ + LineSeries( + name: 'X', + dataSource: _measurementsX, + markerSettings: MarkerSettings(isVisible: true), + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y), + LineSeries( + name: 'Y', + dataSource: _measurementsY, + markerSettings: MarkerSettings(isVisible: true), + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y), + LineSeries( + name: 'Z', + dataSource: _measurementsZ, + markerSettings: MarkerSettings(isVisible: true), + xValueMapper: (SeriesEntry measurement, _) => measurement.x, + yValueMapper: (SeriesEntry measurement, _) => measurement.y), + ], + legend: Legend(isVisible: this.legend, position: LegendPosition.bottom), + primaryXAxis: NumericAxis(numberFormat: NumberFormat("##,###s"))); + } + + List getFingerValues(List m) { + switch (finger) { + case FingerValue.Thumb: + return m.sublist(0, 9); + case FingerValue.Index: + return m.sublist(9, 18); + case FingerValue.Middle: + return m.sublist(18, 27); + case FingerValue.Ring: + return m.sublist(27, 36); + case FingerValue.Pinky: + return m.sublist(36); + } + } + + Vector3 getSensorValues(List m) { + switch (this.sensor) { + case SensorValue.Acceleration: + return Acceleration(m[0], m[1], m[2]); + case SensorValue.Gyroscope: + return Gyro(m[3], m[4], m[5]); + case SensorValue.Inclination: + return Inclination(m[6], m[7], m[8]); + } + } +} + +class SeriesEntry { + double x; + double y; + + SeriesEntry(this.x, this.y); +} diff --git a/lib/pages/file_data_visualization_page.dart b/lib/pages/file_data_visualization_page.dart deleted file mode 100644 index 1b58a00..0000000 --- a/lib/pages/file_data_visualization_page.dart +++ /dev/null @@ -1,152 +0,0 @@ - - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:lsa_gloves/connection/ble/bluetooth_backend.dart'; -import 'package:lsa_gloves/model/glove_measurement.dart'; -import 'package:lsa_gloves/navigation/navigation_drawer.dart'; -import 'package:provider/provider.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; -import 'dart:developer' as developer; - -class FileDataVisualizationPage extends StatefulWidget { - const FileDataVisualizationPage({Key? key}) : super(key: key); - - @override - _FileDataVisualizationPageState createState() => _FileDataVisualizationPageState(); -} - -class _FileDataVisualizationPageState extends State { - - @override - Widget build(BuildContext context) { - return Consumer( - builder: (context, backend, _) => SafeArea( - child: Scaffold( - appBar: AppBar( - title: Text('Visualización'), - ), - drawer: NavDrawer(), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Expanded( - child:MeasurementsChart() - ) - - ], - )), - ))); - } -} - -class MeasurementsChart extends StatefulWidget { - final List measurements; - - const MeasurementsChart( - {Key? key, required this.measurements}) - : super(key: key); - - @override - _MeasurementsChartState createState() => - _MeasurementsChartState(measurements); -} - -class _MeasurementsChartState extends State { - - SensorValue sensor = SensorValue.Acceleration; - - List _measurements; - static const int maxWindowSize = 100; - List _measurementsX = []; - List _measurementsY = []; - List _measurementsZ = []; - - _MeasurementsChartState( - this._measurements); - - @override - void initState() { - super.initState(); - this._measurements.forEach((gloveMeasurement) { - gloveMeasurement.elapsedTimeMs - var sensorValues = gloveMeasurement.getFinger(FingerValue.Thumb).getSensorValues(sensor); - _measurementsX.add(SeriesEntry(lastTimestampMs, sensorValues.getX())); - _measurementsY.add(SeriesEntry(lastTimestampMs, sensorValues.getY())); - _measurementsZ.add(SeriesEntry(lastTimestampMs, sensorValues.getZ())); - - }); - } - - - @override - Widget build(BuildContext context) { - return SfCartesianChart( - series: [ - LineSeries( - name: sensor.getXLabel(), - dataSource: _measurementsX, - xValueMapper: (SeriesEntry measurement, _) => measurement.x, - yValueMapper: (SeriesEntry measurement, _) => measurement.y, - onRendererCreated: (ChartSeriesController controller) { - _chartSeriesControllerX = controller; - }), - LineSeries( - name: sensor.getYLabel(), - dataSource: _measurementsY, - xValueMapper: (SeriesEntry measurement, _) => measurement.x, - yValueMapper: (SeriesEntry measurement, _) => measurement.y, - onRendererCreated: (ChartSeriesController controller) { - _chartSeriesControllerY = controller; - }), - LineSeries( - name: sensor.getZLabel(), - dataSource: _measurementsZ, - xValueMapper: (SeriesEntry measurement, _) => measurement.x, - yValueMapper: (SeriesEntry measurement, _) => measurement.y, - onRendererCreated: (ChartSeriesController controller) { - _chartSeriesControllerZ = controller; - }), - ], - legend: Legend(isVisible: true, position: LegendPosition.bottom), - primaryXAxis: NumericAxis( - numberFormat: NumberFormat("##,###s") - ) - ); - } - - @override - void onMeasurement(GloveMeasurement measurement) { - measurementsBuffer.add(measurement); - - if (measurementsBuffer.length > maxWindowSize) { - _measurementsX.removeAt(0); - _measurementsY.removeAt(0); - _measurementsZ.removeAt(0); - measurementsBuffer.remove(0); - _chartSeriesControllerX?.updateDataSource( - addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); - _chartSeriesControllerY?.updateDataSource( - addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); - _chartSeriesControllerZ?.updateDataSource( - addedDataIndex: maxWindowSize - 1, removedDataIndex: 0); - } else { - int measurementsAmount = _measurementsX.length; - _chartSeriesControllerX?.updateDataSource( - addedDataIndex: measurementsAmount - 1); - _chartSeriesControllerY?.updateDataSource( - addedDataIndex: measurementsAmount - 1); - _chartSeriesControllerZ?.updateDataSource( - addedDataIndex: measurementsAmount - 1); - } - } -} - -class SeriesEntry { - double x; - double y; - - SeriesEntry(this.x, this.y); -} diff --git a/lib/pages/file_manager_page.dart b/lib/pages/file_manager_page.dart index a4a9344..c15a043 100644 --- a/lib/pages/file_manager_page.dart +++ b/lib/pages/file_manager_page.dart @@ -7,6 +7,8 @@ import 'package:path/path.dart'; import 'package:flutter/material.dart'; import 'package:lsa_gloves/datacollection/storage.dart'; +import 'file_content_chart_page.dart'; + class FileManagerPage extends StatefulWidget { @override State createState() { @@ -40,10 +42,11 @@ class _FileManagerPage extends State { leading: IconButton( icon: Icon(Icons.folder_open_sharp), onPressed: () async { + SensorMeasurements measurements = await f.readJsonContent(); Navigator.pushNamed( context, - FileContentPage.routeName, - arguments: f, + FileContentChartPage.routeName, + arguments: measurements, ); }, ), From 5e48be53edb7b0dff83fff9cddf45411806615db Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Sat, 6 Nov 2021 20:18:49 -0300 Subject: [PATCH 5/6] fix in frequency --- .../measurements_collector.dart | 10 ++--- lib/datacollection/storage.dart | 20 +++++----- lib/edgeimpulse/api_client.dart | 4 +- lib/model/glove_measurement.dart | 12 +++--- lib/pages/ble_data_collection_page.dart | 40 ++++++++++++++----- lib/pages/data_visualization_page.dart | 2 +- lib/pages/file_content_chart_page.dart | 6 +-- 7 files changed, 56 insertions(+), 38 deletions(-) diff --git a/lib/datacollection/measurements_collector.dart b/lib/datacollection/measurements_collector.dart index b352bf3..b6ad1be 100644 --- a/lib/datacollection/measurements_collector.dart +++ b/lib/datacollection/measurements_collector.dart @@ -91,7 +91,7 @@ class MeasurementsCollector { GloveMeasurement gloveMeasurement = GloveMeasurement.fromFingerMeasurementsList( parsedMeasurements.eventNumber, - parsedMeasurements.millis, + parsedMeasurements.timestampMillis, deviceId, parsedMeasurements.values); // developer.log('map to -> ${gloveMeasurement.toJson().toString()}'); @@ -138,8 +138,8 @@ class MeasurementsCollector { return null; } int eventNum = int.parse(fingerMeasurements.removeAt(0)); - double millis = double.parse(fingerMeasurements.removeAt(0)); - return _ParsedMeasurements(eventNum, millis, fingerMeasurements); + int timestampMillis = int.parse(fingerMeasurements.removeAt(0)); + return _ParsedMeasurements(eventNum, timestampMillis, fingerMeasurements); } void _notifyListeners(GloveMeasurement measurement) { @@ -151,10 +151,10 @@ class MeasurementsCollector { class _ParsedMeasurements { final int eventNumber; - final double millis; + final int timestampMillis; final List values; - _ParsedMeasurements(this.eventNumber, this.millis, this.values); + _ParsedMeasurements(this.eventNumber, this.timestampMillis, this.values); @override String toString() { diff --git a/lib/datacollection/storage.dart b/lib/datacollection/storage.dart index 27e8b50..49a2ede 100644 --- a/lib/datacollection/storage.dart +++ b/lib/datacollection/storage.dart @@ -71,7 +71,7 @@ class DeviceMeasurementsFile { String deviceName, String deviceId, String word) async { var creationDate = DateTime.now(); SensorMeasurements json = new SensorMeasurements( - deviceName, deviceId, word, >[], []); + deviceName, deviceId, word, >[], []); String datetimeStr = format(creationDate); var filename = "${deviceName.substring(0, 1)}_${word}_$datetimeStr"; var file = await new GloveEventsStorage().createFile(filename); @@ -153,11 +153,11 @@ class SensorMeasurements { final String deviceName; final String deviceId; final String word; - final List millis; + final List timestamps; final List> values; SensorMeasurements(this.deviceName, this.deviceId, this.word,this.values, - this.millis); + this.timestamps); bool add(GloveMeasurement gloveMeasurement) { if (gloveMeasurement.deviceId != this.deviceId) { @@ -171,7 +171,7 @@ class SensorMeasurements { measurementList.addAll(extractFingerMeasurement(gloveMeasurement.middle)); measurementList.addAll(extractFingerMeasurement(gloveMeasurement.index)); this.values.add(measurementList); - this.millis.add(gloveMeasurement.millis); + this.timestamps.add(gloveMeasurement.timestampMillis); return true; } @@ -191,7 +191,7 @@ class SensorMeasurements { factory SensorMeasurements.fromJson(dynamic json) { List> _values = >[]; - List _millis = []; + List _timestamps = []; if (json['values'] != null) { var jsonLists = json['values'] as List; @@ -200,16 +200,16 @@ class SensorMeasurements { return valuesList.map((v) => v as double).toList(); }).toList(); } - if (json['millis'] != null) { - var jsonLists = json['millis'] as List; - _millis = jsonLists.map((v) => v as double).toList(); + if (json['timestamps'] != null) { + var jsonLists = json['timestamps'] as List; + _timestamps = jsonLists.map((v) => v as int).toList(); } return SensorMeasurements( json['device_name'] as String, json['device_id'] as String, json['word'] as String, _values, - _millis, + _timestamps, ); } @@ -219,7 +219,7 @@ class SensorMeasurements { 'device_id': deviceId, 'word': word, 'values': values, - 'millis': millis + 'timestamps': timestamps }; } } diff --git a/lib/edgeimpulse/api_client.dart b/lib/edgeimpulse/api_client.dart index 00c5ac2..0899d62 100644 --- a/lib/edgeimpulse/api_client.dart +++ b/lib/edgeimpulse/api_client.dart @@ -22,8 +22,8 @@ class EdgeImpulseApiClient { iat: datetime.toUtc().millisecondsSinceEpoch ~/1000.0// date when the file was created in seconds since epoch ); double elapsedTimeSum = 0.0; - for(var i = sensorMeasurements.millis.length -1 ; i > 0 ; i--){ - var elapsedTime = sensorMeasurements.millis[i] - sensorMeasurements.millis[i-1]; + for(var i = sensorMeasurements.timestamps.length -1 ; i > 0 ; i--){ + var elapsedTime = sensorMeasurements.timestamps[i] - sensorMeasurements.timestamps[i-1]; elapsedTimeSum += elapsedTime ; } double averageIntervalInMilliseconds = elapsedTimeSum / (sensorMeasurements.values.length * 1.0); diff --git a/lib/model/glove_measurement.dart b/lib/model/glove_measurement.dart index 793fad7..a822900 100644 --- a/lib/model/glove_measurement.dart +++ b/lib/model/glove_measurement.dart @@ -34,18 +34,18 @@ class GloveMeasurement { final String deviceId; final int eventNum; - final double millis; + final int timestampMillis; final Finger thumb; final Finger index; final Finger middle; final Finger ring; final Finger pinky; - GloveMeasurement(this.deviceId, this.eventNum,this.millis,this.pinky, this.ring, this.middle, this.index, this.thumb); + GloveMeasurement(this.deviceId, this.eventNum,this.timestampMillis,this.pinky, this.ring, this.middle, this.index, this.thumb); GloveMeasurement.fromJson(Map json) : deviceId = json['device_id'], eventNum = json['event_num'], - millis = json['millis'], + timestampMillis = json['timestamp_millis'], pinky = Finger.fromJson(json['pinky'] as Map), ring = Finger.fromJson(json['ring'] as Map), middle = Finger.fromJson(json['middle'] as Map), @@ -54,7 +54,7 @@ class GloveMeasurement { Map toJson() => { 'device_id': deviceId, - 'millis': millis, + 'timestampMillis': timestampMillis, 'event_num': eventNum, 'pinky' : pinky.toJson(), 'ring': ring.toJson(), @@ -64,7 +64,7 @@ class GloveMeasurement { }; - static fromFingerMeasurementsList(int eventNum, double millis, String deviceId, List fingerMeasurements) { + static fromFingerMeasurementsList(int eventNum, int timestampMillis, String deviceId, List fingerMeasurements) { Map measurementsMap = new Map(); for (final item in fingerMeasurements) { @@ -80,7 +80,7 @@ class GloveMeasurement { Finger? middle = measurementsMap[middleLetter]; Finger? index = measurementsMap[indexLetter]; Finger? thumb = measurementsMap[thumbLetter]; - return new GloveMeasurement(deviceId, eventNum, millis, pinky!, ring!, middle!, index!, thumb!); + return new GloveMeasurement(deviceId, eventNum, timestampMillis, pinky!, ring!, middle!, index!, thumb!); } Finger getFinger(FingerValue fingerName) { diff --git a/lib/pages/ble_data_collection_page.dart b/lib/pages/ble_data_collection_page.dart index ff8fd81..8f15ecc 100644 --- a/lib/pages/ble_data_collection_page.dart +++ b/lib/pages/ble_data_collection_page.dart @@ -77,7 +77,7 @@ class _BleDataCollectionState extends State }); }), DataVisualizer( - key: Key("$_collections"), collector: _measurementsCollector), + key: Key("$_collections-$_isRecording"), collector: _measurementsCollector), Expanded( child: Align( alignment: FractionalOffset.bottomCenter, @@ -161,6 +161,7 @@ class _BleDataCollectionState extends State void _stopRecording(BluetoothBackend bluetoothBackend) async { developer.log('stopRecording'); bluetoothBackend.sendStopCommand(); + _isRecording = false; showDialog( context: context, @@ -313,10 +314,11 @@ class DataVisualizer extends StatefulWidget { class _DataVisualizerState extends State with MeasurementsListener { final MeasurementsCollector collector; + Map _stats; + + _DataVisualizerState(this.collector):_stats = Map(); - _DataVisualizerState(this.collector); - Map _stats = Map(); @override void initState() { @@ -350,23 +352,39 @@ class _DataVisualizerState extends State setState(() { if (!_stats.containsKey(measurement.deviceId)) { _stats[measurement.deviceId] = GloveStats(); - } else { - _stats[measurement.deviceId]?.update(measurement.millis); } + _stats[measurement.deviceId]?.update(measurement.eventNum, measurement.timestampMillis); }); } } class GloveStats { - double accumulatedTimeMs = 0; - int eventNumber = 0; - - void update(double elapsedTimeMs) { + static const String TAG = 'GloveStats'; + int initialMs = -1; + int accumulatedTimeMs = 1; + int eventNumber = 1; + + void update(int gloveEventNum, int timestampMillis) { + if(this.initialMs < 0 ){ + this.initialMs = timestampMillis; + developer.log("set initialMs -> $initialMs", name: TAG); + } + if(gloveEventNum != this.eventNumber ){ + developer.log("se perdieron eventos ?", name: TAG); + developer.log("eventNumber: $eventNumber gloveEventNum: $gloveEventNum", name: TAG); + } eventNumber++; - accumulatedTimeMs = accumulatedTimeMs + elapsedTimeMs; + accumulatedTimeMs = timestampMillis; } double getFrequency() { - return 1000 * eventNumber / accumulatedTimeMs; + double elapsedTime = ((accumulatedTimeMs - initialMs) * 1.0); + developer.log("elapsedTime = $accumulatedTimeMs - $initialMs= $elapsedTime", name: TAG); + if(elapsedTime < 1){ + return 0.0; + } + double frequency = 1000.0 * eventNumber / elapsedTime; + developer.log("frequency= 1000 * $eventNumber /$elapsedTime = $frequency", name: TAG); + return frequency; } } diff --git a/lib/pages/data_visualization_page.dart b/lib/pages/data_visualization_page.dart index 5e86038..fe11b9c 100644 --- a/lib/pages/data_visualization_page.dart +++ b/lib/pages/data_visualization_page.dart @@ -196,7 +196,7 @@ class _MeasurementsChartState extends State @override void onMeasurement(GloveMeasurement measurement) { measurementsBuffer.add(measurement); - lastTimestampMs += measurement.millis; + lastTimestampMs += measurement.timestampMillis; Vector3 sensorValues = measurement.getFinger(finger).getSensorValues(sensor); _measurementsX.add(SeriesEntry(lastTimestampMs, sensorValues.getX())); _measurementsY.add(SeriesEntry(lastTimestampMs, sensorValues.getY())); diff --git a/lib/pages/file_content_chart_page.dart b/lib/pages/file_content_chart_page.dart index be02a45..d26745d 100644 --- a/lib/pages/file_content_chart_page.dart +++ b/lib/pages/file_content_chart_page.dart @@ -131,12 +131,12 @@ class _MeasurementsChartState extends State { @override Widget build(BuildContext context) { - var initialTimestamp = 0.0; + double initialTimestamp = 0.0; for (var i = 0; i < this._measurements.values.length; i++) { if (i == 0) { - initialTimestamp = this._measurements.millis[i]; + initialTimestamp = this._measurements.timestamps[i] as double; } - var timestamp = (this._measurements.millis[i] - initialTimestamp); + var timestamp = (this._measurements.timestamps[i] - initialTimestamp); var fingerValues = getFingerValues(this._measurements.values[i]); var sensorValues = this.getSensorValues(fingerValues); _measurementsX.add(SeriesEntry(timestamp, sensorValues.getX())); From 9cd76351e10d84ad7dca9b84db119fb12865a95b Mon Sep 17 00:00:00 2001 From: Jazmin Ferreiro Date: Sat, 6 Nov 2021 20:39:19 -0300 Subject: [PATCH 6/6] fix cast --- lib/pages/file_content_chart_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/file_content_chart_page.dart b/lib/pages/file_content_chart_page.dart index d26745d..22bd043 100644 --- a/lib/pages/file_content_chart_page.dart +++ b/lib/pages/file_content_chart_page.dart @@ -134,9 +134,9 @@ class _MeasurementsChartState extends State { double initialTimestamp = 0.0; for (var i = 0; i < this._measurements.values.length; i++) { if (i == 0) { - initialTimestamp = this._measurements.timestamps[i] as double; + initialTimestamp = this._measurements.timestamps[i] * 1.0; } - var timestamp = (this._measurements.timestamps[i] - initialTimestamp); + var timestamp = (this._measurements.timestamps[i] - initialTimestamp) * 1.0; var fingerValues = getFingerValues(this._measurements.values[i]); var sensorValues = this.getSensorValues(fingerValues); _measurementsX.add(SeriesEntry(timestamp, sensorValues.getX()));