closes #7 - sensoren könne ausgelesen werden closes #12

- bug gefixed! die letzte bekannte position des fingers auf dem display musste zurückgesetzt werden
ref #6 - angefangen matlab code zu portieren
- auto correlationsmethode implementiert
This commit is contained in:
toni
2017-11-25 18:09:16 +01:00
parent 4b21120d2b
commit d0f0d0aa0b
6 changed files with 172 additions and 26 deletions

View File

@@ -41,5 +41,5 @@ dependencies {
implementation 'com.android.support:recyclerview-v7:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support:wear:26.1.0' implementation 'com.android.support:wear:26.1.0'
compileOnly 'com.google.android.wearable:wearable:2.1.0' compileOnly 'com.google.android.wearable:wearable:2.1.0'
//compile 'com.sdsmdg.harjot:croller:1.0.7' compile 'com.github.wendykierp:JTransforms:3.1'
} }

View File

@@ -1,39 +1,101 @@
package de.tonifetzer.conductorswatch; package de.tonifetzer.conductorswatch;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import de.tonifetzer.conductorswatch.utilities.Utils;
/** /**
* Created by toni on 13/11/17. * Created by toni on 13/11/17.
*/ */
public class BpmEstimator implements Runnable { //TODO: diesen estimator testen. kommen alle messungen? wie sind die messungen zeitlich voneinander verschieden?
//TODO: klapp das wirklich mit den 4ms. passt der buffer? gehen auch höhere zeiten?
//TODO: einfügen der logik autoCorr + FindPeaks
public class BpmEstimator implements SensorEventListener {
private volatile boolean mRunning = true; private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Context mContext;
private Utils.AccelerometerWindowBuffer mAccelerometerWindowBuffer;
@Override private Handler mHandler;
public void run() { private int mUpdaterate_ms = 100;
while(mRunning){ private boolean mSensorUpdateFlag = false;
int randomNum = ThreadLocalRandom.current().nextInt(0, 240 + 1);
for (OnBpmEstimatorListener listener:listeners) {
listener.onNewDataAvailable((float) randomNum); private final Runnable mProcessSensors = new Runnable() {
@Override
public void run() {
if(mAccelerometerWindowBuffer.isNextWindowReady()){
//int randomNum = ThreadLocalRandom.current().nextInt(0, 240 + 1);
long diff = mAccelerometerWindowBuffer.getYongest().ts - mAccelerometerWindowBuffer.getOldest().ts;
for (OnBpmEstimatorListener listener:listeners) {
listener.onNewDataAvailable((float) diff);
}
} }
try { mSensorUpdateFlag = true;
Thread.sleep(60000 / 60); // The Runnable is posted to run again here:
} catch (InterruptedException e) { mHandler.postDelayed(this, mUpdaterate_ms);
e.printStackTrace();
}
} }
};
public BpmEstimator(Context mContext){
this.mContext = mContext;
} }
public void start() {
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
mAccelerometerWindowBuffer = new Utils.AccelerometerWindowBuffer(4096, 256);
mHandler = new Handler();
mHandler.post(mProcessSensors); //start runnable
}
public void stop() { public void stop() {
mRunning = false; mHandler.removeCallbacks(mProcessSensors); //remove runnable
mSensorManager.unregisterListener(this);
} }
@Override
public void onSensorChanged(SensorEvent se) {
// einkommentieren, falls die updaterate beschränkt werden soll. aktuell maximum speed
//if(mSensorUpdateFlag) {
//ca 200hz, every 5 to 6 ms we have an update
if (se.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
mAccelerometerWindowBuffer.add(new Utils.AccelerometerData(System.currentTimeMillis(), se.values[0], se.values[1], se.values[2]));
}
// mSensorUpdateFlag = false;
//}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
// do nothin
}
/** /**
* Interface for callback calculated bpm * Interface for callback calculated bpm
*/ */

View File

@@ -121,6 +121,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
mHandler.removeCallbacks(mLongPressed); mHandler.removeCallbacks(mLongPressed);
if(mLongPressHandlerActivated){ if(mLongPressHandlerActivated){
mLongPressHandlerActivated = false; mLongPressHandlerActivated = false;
mPreviousMovePoint = null;
return true; return true;
} }
return false; return false;

View File

@@ -29,7 +29,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
private BpmEstimator mBpmEstimator; private BpmEstimator mBpmEstimator;
private Metronome mMetronome; private Metronome mMetronome;
private Thread mBpmThread; //private Thread mBpmThread;
private Thread mMetronomeThread; private Thread mMetronomeThread;
private Vibrator mVibrator; private Vibrator mVibrator;
@@ -58,9 +58,9 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// init bpm estimator and listener // init bpm estimator and listener
mBpmEstimator = new BpmEstimator(); mBpmEstimator = new BpmEstimator(getContext());
mBpmEstimator.add(this); mBpmEstimator.add(this);
mBpmThread = new Thread(mBpmEstimator, "estThread"); //mBpmThread = new Thread(mBpmEstimator, "estThread");
mBpmList = new Vector<Float>(); mBpmList = new Vector<Float>();
@@ -99,7 +99,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
super.onStart(); super.onStart();
// start the worker thread for bpm estimator // start the worker thread for bpm estimator
mBpmThread.start(); mBpmEstimator.start();
// start the worker thread for metronom // start the worker thread for metronom
mMetronomeThread.start(); mMetronomeThread.start();
@@ -111,12 +111,12 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
// stop the worker thread for bpm estimator // stop the worker thread for bpm estimator
mBpmEstimator.stop(); mBpmEstimator.stop();
mBpmThread.interrupt(); /*mBpmThread.interrupt();
try { try {
mBpmThread.join(); mBpmThread.join();
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }*/
// stop the worker thread for metronom // stop the worker thread for metronom
mMetronome.stop(); mMetronome.stop();

View File

@@ -2,12 +2,13 @@ package de.tonifetzer.conductorswatch.utilities;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.MotionEvent;
import de.tonifetzer.conductorswatch.Croller; import org.jtransforms.fft.DoubleFFT_1D;
import java.util.ArrayList;
import java.util.Queue;
public class Utils { public class Utils {
public static float getDistance(float x1, float y1, float x2, float y2) { public static float getDistance(float x1, float y1, float x2, float y2) {
@@ -26,4 +27,86 @@ public class Utils {
return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
} }
public static class AccelerometerData {
public float x,y,z;
public long ts;
public AccelerometerData(long ts, float x, float y, float z){
this.ts = ts;
this.x = x;
this.y = y;
this.z = z;
}
}
//TODO: implement methods providing x,y,z and ts as solo vectors
//TODO: implement sliding window counter
public static class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
private int mWindowSize;
private int mOverlapSize;
private int mOverlapCounter;
public AccelerometerWindowBuffer(int windowSize, int overlap){
this.mWindowSize = windowSize;
this.mOverlapSize = overlap;
mOverlapCounter = 1;
}
public boolean add(AccelerometerData ad){
boolean r = super.add(ad);
if (size() > mWindowSize){
removeRange(0, size() - mWindowSize);
}
++mOverlapCounter;
return r;
}
public boolean isNextWindowReady(){
if(size() == mWindowSize && mOverlapCounter > mOverlapSize){
mOverlapCounter = 1;
return true;
}
return false;
}
public AccelerometerData getYongest() {
return get(size() - 1);
}
public AccelerometerData getOldest() {
return get(0);
}
}
public static double sqr(double x) {
return x * x;
}
//TODO: implement maxLag as input
//TODO: implement positive and negative lag output
public void fftAutoCorrelation(double [] x, double [] ac) {
int n = x.length;
// Assumes n is even.
DoubleFFT_1D fft = new DoubleFFT_1D(n);
fft.realForward(x);
//ac[0] = sqr(x[0]); // For normal xcov
ac[0] = 0; // For statistical convention, zero out the mean
ac[1] = sqr(x[1]);
for (int i = 2; i < n; i += 2) {
ac[i] = sqr(x[i]) + sqr(x[i+1]);
ac[i+1] = 0;
}
DoubleFFT_1D ifft = new DoubleFFT_1D(n);
ifft.realInverse(ac, true);
//For statistical convention, normalize by dividing through with variance
for (int i = 1; i < n; i++){
ac[i] /= ac[0];
}
ac[0] = 1;
}
} }

View File

@@ -6,7 +6,7 @@
%load file provided by the sensor readout app %load file provided by the sensor readout app
%% SMARTWATCH LG WEAR ------> 100 hz - 1000hz %% SMARTWATCH LG WEAR ------> 100 hz - 1000hz
measurements = dlmread('../measurements/lgWear/PR_recording_80bpm_4-4_177596720.csv', ';'); %* measurements = dlmread('../../measurements/lgWear/PR_recording_80bpm_4-4_177596720.csv', ';'); %*
%measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176527527.csv', ';'); %measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176527527.csv', ';');
%measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176606785.csv', ';'); %measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176606785.csv', ';');
%measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176696356.csv', ';'); %measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176696356.csv', ';');