-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
924af9f
commit e4d241a
Showing
9 changed files
with
529 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.0.0\\\\","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2021-04-05 11:21:13.384456","version":"2.0.4"} | ||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.7.2\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\maxim\\\\Programming\\\\SDKs\\\\Flutter\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.0.0\\\\","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2021-04-05 14:30:33.034504","version":"2.0.4"} |
242 changes: 242 additions & 0 deletions
242
Mobile_app/smart_mask/lib/src/logic/blocs/analytics/Analytics_logic.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
import 'package:iirjdart/butterworth.dart'; | ||
import 'package:smart_mask/src/logic/database/models/sensor_model.dart'; | ||
import 'package:smart_mask/src/logic/repositories/sensor_data_repo.dart'; | ||
|
||
const MAX_TIME_TICKS = 1000; | ||
const MAX_ZOOM = 10; | ||
|
||
class AnalyticsLogic { | ||
late AnalyticsLogicState _state; | ||
late SensorDataRepository _sensorDataRepo; | ||
late Sensor _selectedSensor; | ||
late bool _transform; | ||
|
||
AnalyticsLogic() { | ||
_sensorDataRepo = SensorDataRepository(); | ||
_state = AnalyticsLogicState(); | ||
_state.lowPassFilter = 0.5; | ||
_state.highPassFilter = 0.01; | ||
_transform = false; | ||
_selectedSensor = Sensor.sensor_1; | ||
} | ||
|
||
Future<List<SensorData>> getSensorData(TimeInterval interval) async { | ||
final start = DateTime.fromMillisecondsSinceEpoch(interval.start); | ||
final end = DateTime.fromMillisecondsSinceEpoch(interval.end); | ||
List<SensorData> sensorData = await _sensorDataRepo.getSensorData( | ||
_selectedSensor, | ||
interval: [start, end], | ||
); | ||
return sensorData; | ||
} | ||
|
||
Future<TimeInterval> getAvailableInterval() async { | ||
final start = await _sensorDataRepo.getOldestSensorData(_selectedSensor); | ||
final end = await _sensorDataRepo.getNewestSensorData(_selectedSensor); | ||
if (start == null || end == null) { | ||
var now = DateTime.now().millisecondsSinceEpoch; | ||
return TimeInterval(now, now); | ||
} | ||
return TimeInterval(start.timeStamp, end.timeStamp); | ||
} | ||
|
||
Future<void> getLatestSensorData() async { | ||
final ti = await getAvailableInterval(); | ||
_state.dataRaw = await getSensorData(ti); | ||
_state.workTimeInterval = ti; | ||
_state.resetWorkInterval(); | ||
} | ||
|
||
List<SensorData> refreshAnalytics() { | ||
if (_transform) _calculateTransform(); | ||
calculateTimeWindow(); | ||
return _getDataWindow(); | ||
} | ||
|
||
_calculateTransform() { | ||
Butterworth butterworth = Butterworth(); | ||
int order = 2; | ||
double sampleRate = 1 / (200 / 1000); | ||
double leftFreq = _state.highPassFilter; | ||
double rightFreq = _state.lowPassFilter; | ||
double centerFreq = (rightFreq - leftFreq) / 2; | ||
double widthFreq = rightFreq - leftFreq; | ||
|
||
butterworth.bandPass(order, sampleRate, centerFreq, widthFreq); | ||
double val; | ||
SensorData sensorData; | ||
_state.dataProcessed.clear(); | ||
|
||
for (var s in _state.dataRaw) { | ||
val = butterworth.filter(s.value.toDouble()); | ||
sensorData = SensorData.fromSensorAndValue( | ||
_selectedSensor, val.toInt(), s.timeStamp); | ||
_state.dataProcessed.add(sensorData); | ||
} | ||
} | ||
|
||
void calculateTimeWindow() { | ||
final startMs = _state.workTimeInterval.start; | ||
final endMs = _state.workTimeInterval.end; | ||
final posInTicks = _state.timePosInTicks; | ||
|
||
final centerMs = | ||
startMs + (posInTicks * (endMs - startMs) ~/ MAX_TIME_TICKS); | ||
|
||
final zoomDelta = (endMs - startMs) ~/ pow(2, _state.zoomLevel); | ||
var windowLeftMs = centerMs - zoomDelta; | ||
windowLeftMs = windowLeftMs > startMs ? windowLeftMs : startMs; | ||
var windowRightMs = centerMs + zoomDelta; | ||
windowRightMs = windowRightMs < endMs ? windowRightMs : endMs; | ||
|
||
_state.timeWindow = TimeInterval(windowLeftMs, windowRightMs); | ||
} | ||
|
||
List<SensorData> _getDataWindow() { | ||
final leftMs = _state._timeWindow.start; | ||
final rightMs = _state._timeWindow.end; | ||
List<SensorData> winList = []; | ||
if (_transform) { | ||
winList = _state.dataProcessed | ||
.where((d) => d.timeStamp >= leftMs && d.timeStamp <= rightMs) | ||
.toList(); | ||
} else { | ||
winList = _state.dataRaw | ||
.where((d) => d.timeStamp >= leftMs && d.timeStamp <= rightMs) | ||
.toList(); | ||
} | ||
return winList; | ||
} | ||
|
||
Future<void> _changeSensor() async { | ||
final ti = await getAvailableInterval(); | ||
_state.dataRaw = await getSensorData(ti); | ||
} | ||
|
||
Future<void> setSelectedSensor(Sensor sensor) async { | ||
_selectedSensor = sensor; | ||
await _changeSensor(); | ||
} | ||
|
||
// toggleTransform() { | ||
// _transform = !_transform; | ||
// } | ||
|
||
setTransform(bool value) { | ||
_transform = value; | ||
} | ||
|
||
// bool isTransformEnabled() { | ||
// return _transform; | ||
// } | ||
|
||
// double get lowPassFilter => _state.lowPassFilter; | ||
|
||
setLowPassFilter(double value) { | ||
_state.lowPassFilter = value; | ||
} | ||
|
||
// double get highPassFilter => _state.highPassFilter; | ||
|
||
setHighPassFilter(double value) { | ||
_state.highPassFilter = value; | ||
} | ||
|
||
setTimefromInt(int value) { | ||
_state.timePosInTicks = value; | ||
} | ||
|
||
increaseZoomLevel() async { | ||
_state.zoomLevel += 1; | ||
} | ||
|
||
decreaseZoomLevel() { | ||
_state.zoomLevel -= 1; | ||
} | ||
} | ||
|
||
class TimeInterval { | ||
late int start; | ||
late int end; | ||
|
||
TimeInterval(this.start, this.end); | ||
} | ||
|
||
class AnalyticsLogicState { | ||
late List<SensorData> dataRaw; | ||
late List<SensorData> dataProcessed; | ||
late TimeInterval _workTimeInterval; | ||
late TimeInterval _timeWindow; | ||
late int _timePosInTicks; | ||
late int _zoomLevel; | ||
late double _lowPassFilter; | ||
late double _highPassFilter; | ||
|
||
AnalyticsLogicState() { | ||
dataRaw = []; | ||
dataProcessed = []; | ||
_lowPassFilter = 100.0; | ||
_highPassFilter = 0.2; | ||
_workTimeInterval = TimeInterval( | ||
DateTime.now().millisecondsSinceEpoch, | ||
DateTime.now().millisecondsSinceEpoch, | ||
); | ||
resetWorkInterval(); | ||
} | ||
|
||
double get lowPassFilter => _lowPassFilter; | ||
|
||
set lowPassFilter(double value) { | ||
if (value > 0 || value > _highPassFilter || value < 10000) | ||
_lowPassFilter = value; | ||
} | ||
|
||
double get highPassFilter => _highPassFilter; | ||
|
||
set highPassFilter(double value) { | ||
if (value > 0 || value < _lowPassFilter || value < 10000) | ||
_highPassFilter = value; | ||
} | ||
|
||
int get zoomLevel => _zoomLevel; | ||
|
||
set zoomLevel(int value) { | ||
if (value > 0 && value < MAX_ZOOM) _zoomLevel = value; | ||
} | ||
|
||
int get timePosInTicks => _timePosInTicks; | ||
|
||
set timePosInTicks(int value) { | ||
if (value > 0 && value <= MAX_TIME_TICKS) _timePosInTicks = value; | ||
} | ||
|
||
TimeInterval get workTimeInterval => _workTimeInterval; | ||
|
||
set workTimeInterval(TimeInterval ti) { | ||
var start = ti.start; | ||
var end = ti.end; | ||
// start is max one hour before end | ||
|
||
if (ti.start < (ti.end - Duration(hours: 1).inMilliseconds)) | ||
start = ti.end - Duration(hours: 1).inMilliseconds; | ||
|
||
_workTimeInterval = TimeInterval(start, end); | ||
} | ||
|
||
TimeInterval get timeWindow => _timeWindow; | ||
|
||
set timeWindow(TimeInterval interval) { | ||
final startMs = interval.start; | ||
final endMs = interval.end; | ||
final wStartMs = _workTimeInterval.start; | ||
final wEndMs = _workTimeInterval.end; | ||
|
||
if (startMs >= wStartMs && endMs <= wEndMs) _timeWindow = interval; | ||
} | ||
|
||
resetWorkInterval() { | ||
_timeWindow = _workTimeInterval; | ||
_zoomLevel = 0; | ||
_timePosInTicks = MAX_TIME_TICKS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
Mobile_app/smart_mask/lib/src/logic/blocs/analytics/analytics_bloc_new.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import 'package:bloc/bloc.dart'; | ||
import 'package:meta/meta.dart'; | ||
import 'package:smart_mask/src/logic/blocs/analytics/Analytics_logic.dart'; | ||
import 'package:smart_mask/src/logic/blocs/bloc.dart'; | ||
import 'package:smart_mask/src/logic/database/models/sensor_model.dart'; | ||
|
||
class AnalyticsBloc extends Bloc<AnalyticsEvent, AnalyticsState> { | ||
late AnalyticsLogic _logic; | ||
|
||
AnalyticsBloc() : super(InitialAnalyticsState()) { | ||
_logic = AnalyticsLogic(); | ||
} | ||
|
||
@override | ||
Stream<AnalyticsState> mapEventToState(AnalyticsEvent event) async* { | ||
if (event is DataRefreshAnalyticsEvent) { | ||
yield* _mapDataRefreshAnalyticsEvent(); | ||
} else if (event is ZoomIncAnalyticsEvent) { | ||
yield* _mapZoomIncAnalyticsEvent(); | ||
} else if (event is ZoomDecAnalyticsEvent) { | ||
yield* _mapZoomDecAnalyticsEvent(); | ||
} else if (event is TimeInTicksAnalyticsEvent) { | ||
yield* _mapTimeInTicksAnalyticsEvent(event); | ||
} else if (event is FilterEnabledAnalyticsEvent) { | ||
yield* _mapFilterEnabledAnalyticsEvent(event); | ||
} else if (event is LowPassAnalyticsEvent) { | ||
yield* _mapLowPassAnalyticsEvent(event); | ||
} else if (event is HighPassAnalyticsEvent) { | ||
yield* _mapHighPassAnalyticsEvent(event); | ||
} else if (event is SelectedSensorAnalyticsEvent) { | ||
yield* _mapSelectedSensorAnalyticsEvent(event); | ||
} | ||
} | ||
|
||
Stream<AnalyticsState> _mapDataRefreshAnalyticsEvent() async* { | ||
await _logic.getLatestSensorData(); | ||
yield* _refreshData(); | ||
} | ||
|
||
Stream<AnalyticsState> _mapZoomIncAnalyticsEvent() async* { | ||
_logic.increaseZoomLevel(); | ||
yield* _refreshData(); | ||
} | ||
|
||
Stream<AnalyticsState> _mapZoomDecAnalyticsEvent() async* { | ||
_logic.decreaseZoomLevel(); | ||
yield* _refreshData(); | ||
} | ||
|
||
Stream<AnalyticsState> _mapTimeInTicksAnalyticsEvent( | ||
TimeInTicksAnalyticsEvent event) async* { | ||
_logic.setTimefromInt(event.ticksIn1000); | ||
yield* _refreshData(); | ||
yield TimeInTicksAnalyticsState(ticksIn1000: event.ticksIn1000) | ||
} | ||
|
||
Stream<AnalyticsState> _mapFilterEnabledAnalyticsEvent( | ||
FilterEnabledAnalyticsEvent event) async* { | ||
_logic.setTransform(event.filterEnabled); | ||
yield* _refreshData(); | ||
yield FilterEnabledAnalyticsState(isEnable: event.filterEnabled); | ||
} | ||
|
||
Stream<AnalyticsState> _mapLowPassAnalyticsEvent( | ||
LowPassAnalyticsEvent event) async* { | ||
_logic.setLowPassFilter(event.lowPassValue); | ||
yield* _refreshData(); | ||
yield LowPassAnalyticsState(lowPassValue: event.lowPassValue); | ||
} | ||
|
||
Stream<AnalyticsState> _mapHighPassAnalyticsEvent( | ||
HighPassAnalyticsEvent event) async* { | ||
_logic.setHighPassFilter(event.highPassValue); | ||
yield* _refreshData(); | ||
yield HighPassAnalyticsState(highPassValue: event.highPassValue); | ||
} | ||
|
||
Stream<AnalyticsState> _mapSelectedSensorAnalyticsEvent( | ||
SelectedSensorAnalyticsEvent event) async* { | ||
await _logic.setSelectedSensor(event.selectedSensor); | ||
yield* _refreshData(); | ||
} | ||
|
||
/////////////////////////////////////////////////////// | ||
Stream<AnalyticsState> _refreshData() async* { | ||
List<SensorData> sensorData = _logic.refreshAnalytics(); | ||
var state = SensorDataAnalyticsState(data: sensorData); | ||
yield state; | ||
} | ||
} |
Oops, something went wrong.