- 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:
@@ -41,5 +41,5 @@ dependencies {
|
||||
implementation 'com.android.support:recyclerview-v7:26.1.0'
|
||||
implementation 'com.android.support:wear:26.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'
|
||||
}
|
||||
|
||||
@@ -1,39 +1,101 @@
|
||||
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.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import de.tonifetzer.conductorswatch.utilities.Utils;
|
||||
|
||||
/**
|
||||
* 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
|
||||
public void run() {
|
||||
while(mRunning){
|
||||
int randomNum = ThreadLocalRandom.current().nextInt(0, 240 + 1);
|
||||
private Handler mHandler;
|
||||
private int mUpdaterate_ms = 100;
|
||||
private boolean mSensorUpdateFlag = false;
|
||||
|
||||
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 {
|
||||
Thread.sleep(60000 / 60);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mSensorUpdateFlag = true;
|
||||
// The Runnable is posted to run again here:
|
||||
mHandler.postDelayed(this, mUpdaterate_ms);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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() {
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -121,6 +121,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
mHandler.removeCallbacks(mLongPressed);
|
||||
if(mLongPressHandlerActivated){
|
||||
mLongPressHandlerActivated = false;
|
||||
mPreviousMovePoint = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
||||
private BpmEstimator mBpmEstimator;
|
||||
private Metronome mMetronome;
|
||||
|
||||
private Thread mBpmThread;
|
||||
//private Thread mBpmThread;
|
||||
private Thread mMetronomeThread;
|
||||
|
||||
private Vibrator mVibrator;
|
||||
@@ -58,9 +58,9 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// init bpm estimator and listener
|
||||
mBpmEstimator = new BpmEstimator();
|
||||
mBpmEstimator = new BpmEstimator(getContext());
|
||||
mBpmEstimator.add(this);
|
||||
mBpmThread = new Thread(mBpmEstimator, "estThread");
|
||||
//mBpmThread = new Thread(mBpmEstimator, "estThread");
|
||||
mBpmList = new Vector<Float>();
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
||||
super.onStart();
|
||||
|
||||
// start the worker thread for bpm estimator
|
||||
mBpmThread.start();
|
||||
mBpmEstimator.start();
|
||||
|
||||
// start the worker thread for metronom
|
||||
mMetronomeThread.start();
|
||||
@@ -111,12 +111,12 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
||||
|
||||
// stop the worker thread for bpm estimator
|
||||
mBpmEstimator.stop();
|
||||
mBpmThread.interrupt();
|
||||
/*mBpmThread.interrupt();
|
||||
try {
|
||||
mBpmThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
|
||||
// stop the worker thread for metronom
|
||||
mMetronome.stop();
|
||||
|
||||
@@ -2,12 +2,13 @@ package de.tonifetzer.conductorswatch.utilities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
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 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%load file provided by the sensor readout app
|
||||
|
||||
%% 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_176606785.csv', ';');
|
||||
%measurements = dlmread('../measurements/lgWear/recording_48bpm_4-4_176696356.csv', ';');
|
||||
|
||||
Reference in New Issue
Block a user