swimtracker-app/SwimTracker/data_processing/DataProcessing.js

128 lines
5.4 KiB
JavaScript
Raw Permalink Normal View History

2020-06-02 17:19:09 +02:00
import DeviceHttpDataSource from './DeviceDataSource';
import { List } from 'immutable';
2020-06-23 21:36:14 +02:00
import { reportDeviceData, resetDeviceData } from '../state/ActionCreators';
import { PeakDetectorSimple } from './PeakDetection';
2020-06-02 17:19:09 +02:00
// todo: put in settings?
const NUM_MEASUREMENTS_PER_SECOND = 10;
const WINDOW_SIZE_SECS = 5;
2020-06-23 21:36:14 +02:00
2020-06-02 17:19:09 +02:00
class DataProcessing {
constructor(reduxStore) {
this.store = reduxStore;
this.store.subscribe(this.onStateChange);
this.state = this.store.getState();
this.dataSource = null;
this.peakDetectorSimple = new PeakDetectorSimple(this.state.settings.peakDetectorSimpleThreshold);
2020-06-23 21:36:14 +02:00
this.onDataSourceChanged(this.state.settings.deviceURL);
this.onRunningChanged(this.state.session.running, this.state.settings.deviceURL);
2020-06-02 17:19:09 +02:00
}
onStateChange = () => {
const newState = this.store.getState();
if (newState.settings.deviceURL !== this.state.settings.deviceURL)
this.onDataSourceChanged(newState.settings.deviceURL);
2020-06-02 22:43:48 +02:00
if (newState.session.running !== this.state.session.running) {
this.onRunningChanged(newState.session.running, newState.settings.deviceURL);
2020-06-02 17:19:09 +02:00
};
2020-06-23 21:36:14 +02:00
if (newState.settings.peakDetectorSimpleThreshold !== this.state.settings.peakDetectorSimpleThreshold) {
this.onAnalysisParameterChange();
2020-06-02 17:19:09 +02:00
};
this.state = newState;
}
2020-06-23 21:36:14 +02:00
resetAnalysis = () => {
this.peakDetectorSimple = new PeakDetectorSimple(this.state.settings.peakDetectorSimpleThreshold);
}
onAnalysisParameterChange = () => {
this.resetAnalysis();
this.peakDetectorSimple.addVector(this.state.session.rawData.toArray());
const analysis = this.analyzeNewMeasurements(data.values, List());
this.store.dispatch(reportDeviceData(this.state.session.sessionId, this.state.session.rawData.size, this.state.session.rawData, analysis));
}
2020-06-02 17:19:09 +02:00
onDataSourceChanged = (newDeviceURL) => {
if (this.dataSource !== null) {
this.dataSource.stop();
this.dataSource = null;
}
2020-06-02 22:43:48 +02:00
this.dataSource = new DeviceHttpDataSource(newDeviceURL + "/api/session/data", this.onNewData);
2020-06-02 17:19:09 +02:00
}
onRunningChanged = (running, deviceURL) => {
2020-06-02 22:43:48 +02:00
let req = new XMLHttpRequest();
2020-06-02 17:19:09 +02:00
if (running) {
2020-06-23 21:36:14 +02:00
//console.log("Starting session", deviceURL + "/api/session/start");
2020-06-02 17:19:09 +02:00
req.open("GET", deviceURL + "/api/session/start");
this.dataSource.startIndex = 0;
this.dataSource.start();
} else {
2020-06-23 21:36:14 +02:00
//console.log("Stopping session");
2020-06-02 17:19:09 +02:00
req.open("GET", deviceURL + "/api/session/stop");
this.dataSource.stop();
this.dataSource.startIndex = 0;
}
2020-06-04 18:46:15 +02:00
req.addEventListener("error", evt => console.log(evt));
req.addEventListener("abort", evt => console.log(evt));
req.send();
2020-06-02 17:19:09 +02:00
}
onNewData = (data) => {
2020-06-23 21:36:14 +02:00
if (data.sessionStartTime == this.state.session.sessionId &&
data.startIndex == this.state.session.rawData.size) {
2020-06-02 17:19:09 +02:00
// normal case, add received data to measurement array
2020-06-23 21:36:14 +02:00
const newData = this.state.session.rawData.concat(List(data.values));
const analysis = this.analyzeNewMeasurements(data.values, this.state.session.rawData);
this.store.dispatch(reportDeviceData(data.sessionStartTime, data.startIndex, newData, analysis));
2020-06-02 17:19:09 +02:00
}
else if (data.startIndex === 0) {
2020-06-23 21:36:14 +02:00
this.resetAnalysis();
const newData = List(data.values);
const analysis = this.analyzeNewMeasurements(data.values, this.state.session.rawData);
this.store.dispatch(reportDeviceData(data.sessionStartTime, data.startIndex, newData, analysis));
2020-06-02 17:19:09 +02:00
} else {
// missed some data -> re-query
2020-06-23 21:36:14 +02:00
console.log("Requery :(");
//console.log("Session times", data.sessionStartTime == this.state.session.sessionId, data.sessionStartTime, this.state.session.sessionId);
//console.log("Index ",data.startIndex == this.state.session.rawData.size, data.startIndex, this.state.session.rawData.size);
this.resetAnalysis();
2020-06-02 17:19:09 +02:00
this.dataSource.startIndex = 0;
2020-06-23 21:36:14 +02:00
this.store.dispatch(resetDeviceData());
2020-06-02 17:19:09 +02:00
}
}
2020-06-23 21:36:14 +02:00
analyzeNewMeasurements = (newData, oldData) => {
const newPeaks = this.peakDetectorSimple.addVector(newData);
const allPeaks = this.state.session.analysis.peaks.concat(List(newPeaks));
const allMeasurements = oldData.concat(List(newData));
const totalMomentum = allMeasurements.reduce((sum, x) => sum + x, 0);
const peakMax = allMeasurements.reduce((running, x) => Math.max(x, running), 0);
2020-06-02 17:19:09 +02:00
// windowed quantities
const windowSizeMeasurements = WINDOW_SIZE_SECS * NUM_MEASUREMENTS_PER_SECOND;
2020-06-23 21:36:14 +02:00
const windowedSeq = allMeasurements.slice(-windowSizeMeasurements);
2020-06-02 22:43:48 +02:00
const peakMaxWindow = windowedSeq.reduce((running, x) => Math.max(x, running), 0);
2020-06-02 17:19:09 +02:00
const momentumWindow = windowedSeq.reduce((sum, x) => sum + x, 0);
return {
2020-06-23 21:36:14 +02:00
peaks: allPeaks,
totalTime: allMeasurements.length / NUM_MEASUREMENTS_PER_SECOND,
2020-06-02 17:19:09 +02:00
activeTime: 0,
totalMomentum: totalMomentum,
peakFrequency: 0,
peakMax: peakMax,
// windowed quantities
momentumWindow: momentumWindow,
frequencyWindow: 0,
peakMaxWindow: peakMaxWindow,
}
};
2020-06-23 21:36:14 +02:00
}
2020-06-02 17:19:09 +02:00
export default DataProcessing;