puhh. this is a big commit

- change the complete file sending / receiving process between phone and watch, we now use channels instead of simple messages. this is recommentad by google, due to some changes in google play services.
- made some smaller changes in the ui, for file saving and saving of sensordata for evaluation purposes
- edited the manifest and gradle script for play store.
- made some change for a better performance for he huawei watch
This commit is contained in:
toni
2018-04-13 11:52:12 +02:00
parent 4dd9dde6fb
commit cad85f8593
22 changed files with 132 additions and 77 deletions

View File

@@ -11,8 +11,8 @@ android {
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 26 targetSdkVersion 26
//sdk 2 | product version 3 | build num 2 | multi-apk 2 //sdk 2 | product version 3 | build num 2 | multi-apk 2
versionCode 260120100 versionCode 260130300
versionName "0.1.2" versionName "0.1.3.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@@ -33,12 +33,12 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.google.android.support:wearable:2.1.0' implementation 'com.google.android.support:wearable:2.2.0'
implementation 'com.google.android.gms:play-services-wearable:11.8.0' implementation 'com.google.android.gms:play-services-wearable:11.8.0'
implementation 'com.android.support:percent:26.1.0' implementation 'com.android.support:percent:26.1.0'
implementation 'com.android.support:animated-vector-drawable:26.1.0' implementation 'com.android.support:animated-vector-drawable:26.1.0'
implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:support-v4:26.1.0' implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0'
compileOnly 'com.google.android.wearable:wearable:2.1.0' compileOnly 'com.google.android.wearable:wearable:2.2.0'
} }

View File

@@ -3,13 +3,12 @@
package="de.tonifetzer.conductorswatch"> package="de.tonifetzer.conductorswatch">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -9,8 +9,8 @@ android {
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 26 targetSdkVersion 26
//sdk 2 | product version 3 | build num 2 | multi-apk 2 //sdk 2 | product version 3 | build num 2 | multi-apk 2
versionCode 260120101 versionCode 260130301
versionName "0.1.2" versionName "0.1.3.2"
} }
buildTypes { buildTypes {
release { release {
@@ -22,6 +22,7 @@ android {
wear1 { wear1 {
dimension "minSdk" dimension "minSdk"
// Use the defaultConfig value // Use the defaultConfig value
minSdkVersion 23
} }
wear2 { wear2 {
dimension "minSdk" dimension "minSdk"
@@ -36,8 +37,8 @@ android {
} }
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.android.support:wearable:2.1.0' implementation 'com.google.android.support:wearable:2.2.0'
implementation 'com.google.android.gms:play-services-wearable:11.8.0' implementation 'com.google.android.gms:play-services-wearable:11.8.0'
implementation 'com.android.support:percent:26.1.0' implementation 'com.android.support:percent:26.1.0'
implementation 'com.android.support:animated-vector-drawable:26.1.0' implementation 'com.android.support:animated-vector-drawable:26.1.0'
@@ -45,6 +46,6 @@ dependencies {
implementation 'com.android.support:support-v4:26.1.0' implementation 'com.android.support:support-v4:26.1.0'
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.2.0'
compile 'com.github.wendykierp:JTransforms:3.1' compile 'com.github.wendykierp:JTransforms:3.1'
} }

View File

@@ -30,7 +30,7 @@ public class Estimator implements SensorEventListener {
private SensorManager mSensorManager; private SensorManager mSensorManager;
private Sensor mAccelerometer; private Sensor mAccelerometer;
private Sensor mGyroscope; private Sensor mRawAccelerometer;
private Context mContext; private Context mContext;
private AccelerometerWindowBuffer mAccelerometerWindowBuffer; private AccelerometerWindowBuffer mAccelerometerWindowBuffer;
private BpmEstimator mBpmEstimator; private BpmEstimator mBpmEstimator;
@@ -50,11 +50,11 @@ public class Estimator implements SensorEventListener {
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); mRawAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_FASTEST); mSensorManager.registerListener(this, mRawAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
mAccelerometerWindowBuffer = new AccelerometerWindowBuffer(1024, 256); mAccelerometerWindowBuffer = new AccelerometerWindowBuffer(6000, 1500);
mBpmEstimator = new BpmEstimator(mAccelerometerWindowBuffer, 0, 5000); mBpmEstimator = new BpmEstimator(mAccelerometerWindowBuffer, 0, 5000);
mTimer.scheduleAtFixedRate(new TimerTask() { mTimer.scheduleAtFixedRate(new TimerTask() {
@@ -110,9 +110,8 @@ public class Estimator implements SensorEventListener {
mByteStreamWriterAcc.reset(); mByteStreamWriterAcc.reset();
} }
if (se.sensor.getType() == Sensor.TYPE_GYROSCOPE) { if (se.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
//TODO: Rename AccelerometerData to SensorData3D mByteStreamWriterGyro.writeSensor3D(Sensor.TYPE_ACCELEROMETER, se.values[0], se.values[1], se.values[2]);
mByteStreamWriterGyro.writeSensor3D(Sensor.TYPE_GYROSCOPE, se.values[0], se.values[1], se.values[2]);
mStreamer.sendByteArray(mByteStreamWriterGyro.getByteArray()); mStreamer.sendByteArray(mByteStreamWriterGyro.getByteArray());
mByteStreamWriterGyro.reset(); mByteStreamWriterGyro.reset();

View File

@@ -12,35 +12,49 @@ public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
private int mOverlapSize; private int mOverlapSize;
private int mOverlapCounter; private int mOverlapCounter;
public AccelerometerWindowBuffer(int windowSize, int overlap){ public AccelerometerWindowBuffer(int windowSize_ms, int overlap_ms){
mWindowSize = windowSize; mWindowSize = windowSize_ms;
mOverlapSize = overlap; mOverlapSize = overlap_ms;
mOverlapCounter = 1; mOverlapCounter = 0;
} }
//TODO: add exception handling. falseArgument if ad has no numeric x,y,z //TODO: add exception handling. falseArgument if ad has no numeric x,y,z
public boolean add(AccelerometerData ad){ public boolean add(AccelerometerData ad){
synchronized (this){ synchronized (this){
//do not add duplicates! //do not add duplicates!
if (!isEmpty() && getYongest().equals(ad)) { if(!isEmpty() && getYongest().equals(ad)){
return false; return false;
} }
boolean r = super.add(ad); // current - last to increment overlap time
if (size() > mWindowSize) { if(!isEmpty()){
removeRange(0, size() - mWindowSize); mOverlapCounter += ad.ts - getYongest().ts;
} }
++mOverlapCounter; //add element
boolean r = super.add(ad);
if ((getYongest().ts - getOldest().ts) > mWindowSize){
long oldestTime = getYongest().ts - mWindowSize;
for(int i = 0; i < size(); ++i) {
if (get(i).ts > oldestTime) {
break;
}
remove(i);
}
}
return r; return r;
} }
} }
public boolean isNextWindowReady(){ public boolean isNextWindowReady(){
if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ if(!isEmpty()){
mOverlapCounter = 1; if(((getYongest().ts - getOldest().ts) > mWindowSize / 2) && mOverlapCounter > mOverlapSize){
mOverlapCounter = 0;
return true; return true;
}
} }
return false; return false;
} }

View File

@@ -58,13 +58,16 @@ public class BpmEstimator {
//just look at the newest 512 samples //just look at the newest 512 samples
//List<AccelerometerData> subBuffer = mBuffer.subList(mBuffer.size() - 512, mBuffer.size()); //List<AccelerometerData> subBuffer = mBuffer.subList(mBuffer.size() - 512, mBuffer.size());
double[] xAutoCorr = new AutoCorrelation(interp.getX(), 512).getCorr(); double[] xAutoCorr = new AutoCorrelation(interp.getX(), fixedWindow.size()).getCorr();
double[] yAutoCorr = new AutoCorrelation(interp.getY(), 512).getCorr(); double[] yAutoCorr = new AutoCorrelation(interp.getY(), fixedWindow.size()).getCorr();
double[] zAutoCorr = new AutoCorrelation(interp.getZ(), 512).getCorr(); double[] zAutoCorr = new AutoCorrelation(interp.getZ(), fixedWindow.size()).getCorr();
Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false);
Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false); //find a peak within range of 250 ms
Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); int peakWidth = (int) Math.round(250 / sampleRate);
Peaks pX = new Peaks(xAutoCorr, peakWidth, 0.1f, 0, false);
Peaks pY = new Peaks(yAutoCorr, peakWidth, 0.1f, 0, false);
Peaks pZ = new Peaks(zAutoCorr, peakWidth, 0.1f, 0, false);
mBpmHistory_X.add(pX.getBPM(sampleRate)); mBpmHistory_X.add(pX.getBPM(sampleRate));
mBpmHistory_Y.add(pY.getBPM(sampleRate)); mBpmHistory_Y.add(pY.getBPM(sampleRate));
@@ -88,7 +91,7 @@ public class BpmEstimator {
//mResetCounter = 0; //mResetCounter = 0;
} }
else { else {
int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate)); int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize()));
if(++mResetCounter > resetAfter){ if(++mResetCounter > resetAfter){
mBpmHistory.clear(); mBpmHistory.clear();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -3,8 +3,11 @@
buildscript { buildscript {
repositories { repositories {
google() maven {
url "https://maven.google.com"
}
jcenter() jcenter()
google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.android.tools.build:gradle:3.0.1'
@@ -17,8 +20,11 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() maven {
url "https://maven.google.com"
}
jcenter() jcenter()
google()
} }
} }

View File

@@ -10,6 +10,7 @@
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m org.gradle.jvmargs=-Xmx1536m
android.enableD8=true
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit

View File

@@ -16,7 +16,8 @@ import java.util.stream.IntStream;
public class Main { public class Main {
public static void main(String [ ] args) { public static void main(String [ ] args) {
File folder = new File("/home/toni/Documents/programme/dirigent/measurements/wearR"); //File folder = new File("/home/toni/Documents/programme/dirigent/measurements/lgWear");
File folder = new File("/home/toni/Documents/programme/dirigent/measurements/peter_failed");
File[] listOfFiles = folder.listFiles(); File[] listOfFiles = folder.listFiles();
Utils.ShowPNG windowRaw = new Utils.ShowPNG(); Utils.ShowPNG windowRaw = new Utils.ShowPNG();
@@ -30,7 +31,8 @@ public class Main {
for (File file : listOfFiles) { for (File file : listOfFiles) {
if (file.isFile() && file.getName().contains(".csv")) { if (file.isFile() && file.getName().contains(".csv")) {
AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(1024, 256); //TODO: mach Fenster genau 6 sekunden groß. Egal wie viele Samples.
AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(6000, 1500);
BpmEstimator bpmEstimator = new BpmEstimator(accWindowBuffer, 0, 5000); BpmEstimator bpmEstimator = new BpmEstimator(accWindowBuffer, 0, 5000);
//read the file line by line //read the file line by line
@@ -40,7 +42,7 @@ public class Main {
String[] measurement = line.split(";"); String[] measurement = line.split(";");
//if linear acc //if linear acc
if(measurement[1].equals("2")){ if(measurement[1].equals("10")){
long ts = Long.parseLong(measurement[0]); long ts = Long.parseLong(measurement[0]);
double x = Double.parseDouble(measurement[2]); double x = Double.parseDouble(measurement[2]);
double y = Double.parseDouble(measurement[3]); double y = Double.parseDouble(measurement[3]);
@@ -54,8 +56,9 @@ public class Main {
double curBpm = bpmEstimator.estimate(); double curBpm = bpmEstimator.estimate();
//System.out.println("BPM: " + curBpm); //System.out.println("BPM: " + curBpm);
double sampleRate = 20;
AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, 5); AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, sampleRate);
int peakWidth = (int) Math.round(250 / sampleRate);
//print raw x,y,z //print raw x,y,z
double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray(); double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray();
@@ -70,9 +73,9 @@ public class Main {
windowRaw.set(plotRaw.draw()); windowRaw.set(plotRaw.draw());
//auto corr //auto corr
double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 512).getCorr(); double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), accWindowBuffer.size()).getCorr();
double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 512).getCorr(); double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), accWindowBuffer.size()).getCorr();
double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 512).getCorr(); double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), accWindowBuffer.size()).getCorr();
//print autocorr //print autocorr
int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray(); int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray();
@@ -86,10 +89,11 @@ public class Main {
windowAuto.set(plotCorr.draw()); windowAuto.set(plotCorr.draw());
Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false); Peaks pX = new Peaks(xAutoCorr, peakWidth, 0.1f, 0, false);
int xOffset = xAutoCorr.length / 2;
LinkedList<Integer> peaksX = pX.getPeaksIdx(); LinkedList<Integer> peaksX = pX.getPeaksIdx();
double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - xOffset)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
double[] dPeaksXY = IntStream.range(0, peaksX.size()).mapToDouble(i -> (xAutoCorr[peaksX.get(i)])).toArray(); double[] dPeaksXY = IntStream.range(0, peaksX.size()).mapToDouble(i -> (xAutoCorr[peaksX.get(i)])).toArray();
Plot plotPeaksX = Plot.plot(Plot.plotOpts(). Plot plotPeaksX = Plot.plot(Plot.plotOpts().
title("Peak Detection on X"). title("Peak Detection on X").
@@ -100,10 +104,11 @@ public class Main {
windowPeaksX.set(plotPeaksX.draw()); windowPeaksX.set(plotPeaksX.draw());
Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false); Peaks pY = new Peaks(yAutoCorr, peakWidth, 0.1f, 0, false);
int yOffset = yAutoCorr.length / 2;
LinkedList<Integer> peaksY = pY.getPeaksIdx(); LinkedList<Integer> peaksY = pY.getPeaksIdx();
double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - yOffset)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
double[] dPeaksYY = IntStream.range(0, peaksY.size()).mapToDouble(i -> (yAutoCorr[peaksY.get(i)])).toArray(); double[] dPeaksYY = IntStream.range(0, peaksY.size()).mapToDouble(i -> (yAutoCorr[peaksY.get(i)])).toArray();
Plot plotPeaksY = Plot.plot(Plot.plotOpts(). Plot plotPeaksY = Plot.plot(Plot.plotOpts().
title("Peak Detection on Y"). title("Peak Detection on Y").
@@ -114,10 +119,11 @@ public class Main {
windowPeaksY.set(plotPeaksY.draw()); windowPeaksY.set(plotPeaksY.draw());
Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); Peaks pZ = new Peaks(zAutoCorr, peakWidth, 0.1f, 0, false);
int zOffset = zAutoCorr.length / 2;
LinkedList<Integer> peaksZ = pZ.getPeaksIdx(); LinkedList<Integer> peaksZ = pZ.getPeaksIdx();
double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - zOffset)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
double[] dPeaksZY = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (zAutoCorr[peaksZ.get(i)])).toArray(); double[] dPeaksZY = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (zAutoCorr[peaksZ.get(i)])).toArray();
Plot plotPeaksZ = Plot.plot(Plot.plotOpts(). Plot plotPeaksZ = Plot.plot(Plot.plotOpts().
title("Peak Detection on Z"). title("Peak Detection on Z").
@@ -142,10 +148,10 @@ public class Main {
} }
// line is not visible here. // line is not visible here.
double meanBPM = bpmEstimator.getMeanBpm(); //double meanBPM = bpmEstimator.getMeanBpm();
double medianBPM = bpmEstimator.getMedianBPM(); //double medianBPM = bpmEstimator.getMedianBPM();
//System.out.println("MEAN BPM: " + Math.round(meanBPM)); //System.out.println("MEAN BPM: " + Math.round(meanBPM));
System.out.println("MEDIAN BPM: " + Math.round(medianBPM)); //System.out.println("MEDIAN BPM: " + Math.round(medianBPM));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -8,14 +8,14 @@ import java.util.ArrayList;
*/ */
public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> { public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
private static int mWindowSize; private static int mWindowSize; // in ms
private static int mOverlapSize; private static int mOverlapSize; // in ms
private int mOverlapCounter; private long mOverlapCounter;
public AccelerometerWindowBuffer(int windowSize, int overlap){ public AccelerometerWindowBuffer(int windowSize, int overlap){
mWindowSize = windowSize; mWindowSize = windowSize;
mOverlapSize = overlap; mOverlapSize = overlap;
mOverlapCounter = 1; mOverlapCounter = 0;
} }
//TODO: add exception handling. falseArgument if ad has no numeric x,y,z //TODO: add exception handling. falseArgument if ad has no numeric x,y,z
@@ -26,20 +26,33 @@ public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
return false; return false;
} }
boolean r = super.add(ad); // current - last to increment overlap time
if (size() > mWindowSize){ if(!isEmpty()){
removeRange(0, size() - mWindowSize); mOverlapCounter += ad.ts - getYongest().ts;
} }
++mOverlapCounter; //add element
boolean r = super.add(ad);
if ((getYongest().ts - getOldest().ts) > mWindowSize){
long oldestTime = getYongest().ts - mWindowSize;
for(int i = 0; i < size(); ++i) {
if (get(i).ts > oldestTime) {
break;
}
remove(i);
}
}
return r; return r;
} }
public boolean isNextWindowReady(){ public boolean isNextWindowReady(){
if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ if(!isEmpty()){
mOverlapCounter = 1; if(((getYongest().ts - getOldest().ts) > mWindowSize / 2) && mOverlapCounter > mOverlapSize){
mOverlapCounter = 0;
return true; return true;
}
} }
return false; return false;
} }

View File

@@ -51,13 +51,15 @@ public class BpmEstimator {
AccelerometerInterpolator interp = new AccelerometerInterpolator(mBuffer, sampleRate); AccelerometerInterpolator interp = new AccelerometerInterpolator(mBuffer, sampleRate);
double[] xAutoCorr = new AutoCorrelation(interp.getX(), 1024).getCorr(); double[] xAutoCorr = new AutoCorrelation(interp.getX(), mBuffer.size()).getCorr();
double[] yAutoCorr = new AutoCorrelation(interp.getY(), 1024).getCorr(); double[] yAutoCorr = new AutoCorrelation(interp.getY(), mBuffer.size()).getCorr();
double[] zAutoCorr = new AutoCorrelation(interp.getZ(), 1024).getCorr(); double[] zAutoCorr = new AutoCorrelation(interp.getZ(), mBuffer.size()).getCorr();
Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false); //find a peak within range of 250 ms
Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false); int peakWidth = (int) Math.round(250 / sampleRate);
Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); Peaks pX = new Peaks(xAutoCorr, peakWidth, 0.1f, 0, false);
Peaks pY = new Peaks(yAutoCorr, peakWidth, 0.1f, 0, false);
Peaks pZ = new Peaks(zAutoCorr, peakWidth, 0.1f, 0, false);
mBpmHistory_X.add(pX.getBPM(sampleRate)); mBpmHistory_X.add(pX.getBPM(sampleRate));
mBpmHistory_Y.add(pY.getBPM(sampleRate)); mBpmHistory_Y.add(pY.getBPM(sampleRate));
@@ -80,9 +82,12 @@ public class BpmEstimator {
mResetCounter = 0; mResetCounter = 0;
} }
else { else {
int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate)); int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize()));
if(++mResetCounter > resetAfter){ if(++mResetCounter > resetAfter){
mBpmHistory.clear(); mBpmHistory.clear();
mBuffer.clear();
mMvg.clear();
mResetCounter = 0; mResetCounter = 0;
} }
return -1; return -1;

View File

@@ -30,4 +30,9 @@ public class MovingFilter {
public double getMedian() { public double getMedian() {
return Utils.median(mSamples); return Utils.median(mSamples);
} }
public void clear(){
mSamples.clear();
mTotal = 0d;
}
} }

View File

@@ -42,7 +42,8 @@
%files = dir(fullfile('../../measurements/lgWear/', '*.csv')); %files = dir(fullfile('../../measurements/lgWear/', '*.csv'));
files = dir(fullfile('../../measurements/wearR/', '*.csv')); %files = dir(fullfile('../../measurements/wearR/', '*.csv'));
files = dir(fullfile('../../measurements/peter_failed/', '*.csv'));
for file = files' for file = files'
@@ -51,7 +52,7 @@ for file = files'
%draw the raw acc data %draw the raw acc data
m_idx = []; m_idx = [];
m_idx = (measurements(:,2)==2); m_idx = (measurements(:,2)==10);
m = measurements(m_idx, :); m = measurements(m_idx, :);
%Interpolate to generate a constant sample rate to 250hz (4ms per sample) %Interpolate to generate a constant sample rate to 250hz (4ms per sample)
@@ -76,13 +77,15 @@ for file = files'
figure(3); figure(3);
plot(m(:,1),m(:,5)) %z plot(m(:,1),m(:,5)) %z
legend("z", "location", "eastoutside"); legend("z", "location", "eastoutside");
waitforbuttonpress();
%save timestamps %save timestamps
timestamps = m(:,1); timestamps = m(:,1);
data = m(:,3); %only z data = m(:,3); %only z
%TODO: Different window sizes for periods under 16.3 s %TODO: Different window sizes for periods under 16.3 s
window_size = 4096; %about 2 seconds using 2000hz, 16.3 s using 250hz window_size = 2048; %about 2 seconds using 2000hz, 16.3 s using 250hz
overlap = 256; overlap = 256;
bpm_per_window_ms = []; bpm_per_window_ms = [];
bpm_per_window = []; bpm_per_window = [];