diff --git a/android/ConductorsPhone/app/build.gradle b/android/ConductorsPhone/app/build.gradle index 993b6df..550f728 100644 --- a/android/ConductorsPhone/app/build.gradle +++ b/android/ConductorsPhone/app/build.gradle @@ -11,8 +11,8 @@ android { minSdkVersion 24 targetSdkVersion 26 //sdk 2 | product version 3 | build num 2 | multi-apk 2 - versionCode 260120100 - versionName "0.1.2" + versionCode 260130300 + versionName "0.1.3.2" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -33,12 +33,12 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.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.android.support:percent: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:support-v4: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' } diff --git a/android/ConductorsPhone/app/src/main/AndroidManifest.xml b/android/ConductorsPhone/app/src/main/AndroidManifest.xml index 4c4f298..2f506e6 100644 --- a/android/ConductorsPhone/app/src/main/AndroidManifest.xml +++ b/android/ConductorsPhone/app/src/main/AndroidManifest.xml @@ -3,13 +3,12 @@ package="de.tonifetzer.conductorswatch"> - diff --git a/android/ConductorsPhone/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/ConductorsPhone/app/src/main/res/mipmap-hdpi/ic_launcher.png index a2f5908..3ed96df 100644 Binary files a/android/ConductorsPhone/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/ConductorsPhone/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/ConductorsPhone/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/ConductorsPhone/app/src/main/res/mipmap-mdpi/ic_launcher.png index ff10afd..ad5136b 100644 Binary files a/android/ConductorsPhone/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/ConductorsPhone/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/ConductorsPhone/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/ConductorsPhone/app/src/main/res/mipmap-xhdpi/ic_launcher.png index dcd3cd8..0989114 100644 Binary files a/android/ConductorsPhone/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/ConductorsPhone/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/ConductorsPhone/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/ConductorsPhone/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 8ca12fe..a46541b 100644 Binary files a/android/ConductorsPhone/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/ConductorsPhone/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/ConductorsPhone/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/ConductorsPhone/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index b824ebd..2f2c97c 100644 Binary files a/android/ConductorsPhone/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/ConductorsPhone/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/ConductorsWatch/app/build.gradle b/android/ConductorsWatch/app/build.gradle index 129c2f4..51b4425 100644 --- a/android/ConductorsWatch/app/build.gradle +++ b/android/ConductorsWatch/app/build.gradle @@ -9,8 +9,8 @@ android { minSdkVersion 23 targetSdkVersion 26 //sdk 2 | product version 3 | build num 2 | multi-apk 2 - versionCode 260120101 - versionName "0.1.2" + versionCode 260130301 + versionName "0.1.3.2" } buildTypes { release { @@ -22,6 +22,7 @@ android { wear1 { dimension "minSdk" // Use the defaultConfig value + minSdkVersion 23 } wear2 { dimension "minSdk" @@ -36,8 +37,8 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.google.android.support:wearable:2.1.0' + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.google.android.support:wearable:2.2.0' implementation 'com.google.android.gms:play-services-wearable:11.8.0' implementation 'com.android.support:percent: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:recyclerview-v7: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' } diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Estimator.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Estimator.java index 5bb93f0..c63e38e 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Estimator.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Estimator.java @@ -30,7 +30,7 @@ public class Estimator implements SensorEventListener { private SensorManager mSensorManager; private Sensor mAccelerometer; - private Sensor mGyroscope; + private Sensor mRawAccelerometer; private Context mContext; private AccelerometerWindowBuffer mAccelerometerWindowBuffer; private BpmEstimator mBpmEstimator; @@ -50,11 +50,11 @@ public class Estimator implements SensorEventListener { mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); 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, 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); mTimer.scheduleAtFixedRate(new TimerTask() { @@ -110,9 +110,8 @@ public class Estimator implements SensorEventListener { mByteStreamWriterAcc.reset(); } - if (se.sensor.getType() == Sensor.TYPE_GYROSCOPE) { - //TODO: Rename AccelerometerData to SensorData3D - mByteStreamWriterGyro.writeSensor3D(Sensor.TYPE_GYROSCOPE, se.values[0], se.values[1], se.values[2]); + if (se.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { + mByteStreamWriterGyro.writeSensor3D(Sensor.TYPE_ACCELEROMETER, se.values[0], se.values[1], se.values[2]); mStreamer.sendByteArray(mByteStreamWriterGyro.getByteArray()); mByteStreamWriterGyro.reset(); diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/AccelerometerWindowBuffer.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/AccelerometerWindowBuffer.java index 5f666a9..f9ec264 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/AccelerometerWindowBuffer.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/AccelerometerWindowBuffer.java @@ -12,35 +12,49 @@ public class AccelerometerWindowBuffer extends ArrayList { private int mOverlapSize; private int mOverlapCounter; - public AccelerometerWindowBuffer(int windowSize, int overlap){ - mWindowSize = windowSize; - mOverlapSize = overlap; - mOverlapCounter = 1; + public AccelerometerWindowBuffer(int windowSize_ms, int overlap_ms){ + mWindowSize = windowSize_ms; + mOverlapSize = overlap_ms; + mOverlapCounter = 0; } //TODO: add exception handling. falseArgument if ad has no numeric x,y,z public boolean add(AccelerometerData ad){ synchronized (this){ + //do not add duplicates! - if (!isEmpty() && getYongest().equals(ad)) { + if(!isEmpty() && getYongest().equals(ad)){ return false; } - boolean r = super.add(ad); - if (size() > mWindowSize) { - removeRange(0, size() - mWindowSize); + // current - last to increment overlap time + if(!isEmpty()){ + 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; } } public boolean isNextWindowReady(){ - if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ - mOverlapCounter = 1; + if(!isEmpty()){ + if(((getYongest().ts - getOldest().ts) > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ + mOverlapCounter = 0; - return true; + return true; + } } return false; } diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/BpmEstimator.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/BpmEstimator.java index e9dac56..824687e 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/BpmEstimator.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/bpmEstimation/BpmEstimator.java @@ -58,13 +58,16 @@ public class BpmEstimator { //just look at the newest 512 samples //List subBuffer = mBuffer.subList(mBuffer.size() - 512, mBuffer.size()); - double[] xAutoCorr = new AutoCorrelation(interp.getX(), 512).getCorr(); - double[] yAutoCorr = new AutoCorrelation(interp.getY(), 512).getCorr(); - double[] zAutoCorr = new AutoCorrelation(interp.getZ(), 512).getCorr(); + double[] xAutoCorr = new AutoCorrelation(interp.getX(), fixedWindow.size()).getCorr(); + double[] yAutoCorr = new AutoCorrelation(interp.getY(), fixedWindow.size()).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); - Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); + + //find a peak within range of 250 ms + 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_Y.add(pY.getBPM(sampleRate)); @@ -88,7 +91,7 @@ public class BpmEstimator { //mResetCounter = 0; } else { - int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate)); + int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize())); if(++mResetCounter > resetAfter){ mBpmHistory.clear(); diff --git a/android/ConductorsWatch/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/ConductorsWatch/app/src/main/res/mipmap-hdpi/ic_launcher.png index cde69bc..f6efd77 100644 Binary files a/android/ConductorsWatch/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/ConductorsWatch/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/ConductorsWatch/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/ConductorsWatch/app/src/main/res/mipmap-mdpi/ic_launcher.png index c133a0c..004197e 100644 Binary files a/android/ConductorsWatch/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/ConductorsWatch/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/ConductorsWatch/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/ConductorsWatch/app/src/main/res/mipmap-xhdpi/ic_launcher.png index bfa42f0..ec1d0fe 100644 Binary files a/android/ConductorsWatch/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/ConductorsWatch/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/ConductorsWatch/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/ConductorsWatch/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 324e72c..10388b5 100644 Binary files a/android/ConductorsWatch/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/ConductorsWatch/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/ConductorsWatch/build.gradle b/android/ConductorsWatch/build.gradle index e6b32bc..3c64aec 100644 --- a/android/ConductorsWatch/build.gradle +++ b/android/ConductorsWatch/build.gradle @@ -3,8 +3,11 @@ buildscript { repositories { - google() + maven { + url "https://maven.google.com" + } jcenter() + google() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' @@ -17,8 +20,11 @@ buildscript { allprojects { repositories { - google() + maven { + url "https://maven.google.com" + } jcenter() + google() } } diff --git a/android/ConductorsWatch/gradle.properties b/android/ConductorsWatch/gradle.properties index aac7c9b..7abc0b5 100644 --- a/android/ConductorsWatch/gradle.properties +++ b/android/ConductorsWatch/gradle.properties @@ -10,6 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m +android.enableD8=true # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/java/src/main/java/Main.java b/java/src/main/java/Main.java index 659a841..f5f124a 100644 --- a/java/src/main/java/Main.java +++ b/java/src/main/java/Main.java @@ -16,7 +16,8 @@ import java.util.stream.IntStream; public class Main { 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(); Utils.ShowPNG windowRaw = new Utils.ShowPNG(); @@ -30,7 +31,8 @@ public class Main { for (File file : listOfFiles) { 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); //read the file line by line @@ -40,7 +42,7 @@ public class Main { String[] measurement = line.split(";"); //if linear acc - if(measurement[1].equals("2")){ + if(measurement[1].equals("10")){ long ts = Long.parseLong(measurement[0]); double x = Double.parseDouble(measurement[2]); double y = Double.parseDouble(measurement[3]); @@ -54,8 +56,9 @@ public class Main { double curBpm = bpmEstimator.estimate(); //System.out.println("BPM: " + curBpm); - - AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, 5); + double sampleRate = 20; + AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, sampleRate); + int peakWidth = (int) Math.round(250 / sampleRate); //print raw x,y,z 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()); //auto corr - double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 512).getCorr(); - double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 512).getCorr(); - double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 512).getCorr(); + double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), accWindowBuffer.size()).getCorr(); + double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), accWindowBuffer.size()).getCorr(); + double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), accWindowBuffer.size()).getCorr(); //print autocorr int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray(); @@ -86,10 +89,11 @@ public class Main { 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 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(); Plot plotPeaksX = Plot.plot(Plot.plotOpts(). title("Peak Detection on X"). @@ -100,10 +104,11 @@ public class Main { 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 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(); Plot plotPeaksY = Plot.plot(Plot.plotOpts(). title("Peak Detection on Y"). @@ -114,10 +119,11 @@ public class Main { 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 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(); Plot plotPeaksZ = Plot.plot(Plot.plotOpts(). title("Peak Detection on Z"). @@ -142,10 +148,10 @@ public class Main { } // line is not visible here. - double meanBPM = bpmEstimator.getMeanBpm(); - double medianBPM = bpmEstimator.getMedianBPM(); + //double meanBPM = bpmEstimator.getMeanBpm(); + //double medianBPM = bpmEstimator.getMedianBPM(); //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) { e.printStackTrace(); diff --git a/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java b/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java index 889ce95..09103a8 100644 --- a/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java +++ b/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java @@ -8,14 +8,14 @@ import java.util.ArrayList; */ public class AccelerometerWindowBuffer extends ArrayList { - private static int mWindowSize; - private static int mOverlapSize; - private int mOverlapCounter; + private static int mWindowSize; // in ms + private static int mOverlapSize; // in ms + private long mOverlapCounter; public AccelerometerWindowBuffer(int windowSize, int overlap){ mWindowSize = windowSize; mOverlapSize = overlap; - mOverlapCounter = 1; + mOverlapCounter = 0; } //TODO: add exception handling. falseArgument if ad has no numeric x,y,z @@ -26,20 +26,33 @@ public class AccelerometerWindowBuffer extends ArrayList { return false; } - boolean r = super.add(ad); - if (size() > mWindowSize){ - removeRange(0, size() - mWindowSize); + // current - last to increment overlap time + if(!isEmpty()){ + 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; } public boolean isNextWindowReady(){ - if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ - mOverlapCounter = 1; + if(!isEmpty()){ + if(((getYongest().ts - getOldest().ts) > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ + mOverlapCounter = 0; - return true; + return true; + } } return false; } diff --git a/java/src/main/java/bpmEstimation/BpmEstimator.java b/java/src/main/java/bpmEstimation/BpmEstimator.java index ac90867..8440bdd 100644 --- a/java/src/main/java/bpmEstimation/BpmEstimator.java +++ b/java/src/main/java/bpmEstimation/BpmEstimator.java @@ -51,13 +51,15 @@ public class BpmEstimator { AccelerometerInterpolator interp = new AccelerometerInterpolator(mBuffer, sampleRate); - double[] xAutoCorr = new AutoCorrelation(interp.getX(), 1024).getCorr(); - double[] yAutoCorr = new AutoCorrelation(interp.getY(), 1024).getCorr(); - double[] zAutoCorr = new AutoCorrelation(interp.getZ(), 1024).getCorr(); + double[] xAutoCorr = new AutoCorrelation(interp.getX(), mBuffer.size()).getCorr(); + double[] yAutoCorr = new AutoCorrelation(interp.getY(), mBuffer.size()).getCorr(); + double[] zAutoCorr = new AutoCorrelation(interp.getZ(), mBuffer.size()).getCorr(); - Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false); - Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false); - Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); + //find a peak within range of 250 ms + 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_Y.add(pY.getBPM(sampleRate)); @@ -80,9 +82,12 @@ public class BpmEstimator { mResetCounter = 0; } else { - int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate)); + int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize())); if(++mResetCounter > resetAfter){ mBpmHistory.clear(); + + mBuffer.clear(); + mMvg.clear(); mResetCounter = 0; } return -1; diff --git a/java/src/main/java/utilities/MovingFilter.java b/java/src/main/java/utilities/MovingFilter.java index e4f883d..5263ed9 100644 --- a/java/src/main/java/utilities/MovingFilter.java +++ b/java/src/main/java/utilities/MovingFilter.java @@ -30,4 +30,9 @@ public class MovingFilter { public double getMedian() { return Utils.median(mSamples); } + + public void clear(){ + mSamples.clear(); + mTotal = 0d; + } } diff --git a/matlab/AutoCorrMethodNew_Watch.m b/matlab/AutoCorrMethodNew_Watch.m index 90f9c5a..ed967e9 100644 --- a/matlab/AutoCorrMethodNew_Watch.m +++ b/matlab/AutoCorrMethodNew_Watch.m @@ -42,7 +42,8 @@ %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' @@ -51,7 +52,7 @@ for file = files' %draw the raw acc data m_idx = []; - m_idx = (measurements(:,2)==2); + m_idx = (measurements(:,2)==10); m = measurements(m_idx, :); %Interpolate to generate a constant sample rate to 250hz (4ms per sample) @@ -76,13 +77,15 @@ for file = files' figure(3); plot(m(:,1),m(:,5)) %z legend("z", "location", "eastoutside"); + + waitforbuttonpress(); %save timestamps timestamps = m(:,1); data = m(:,3); %only z %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; bpm_per_window_ms = []; bpm_per_window = [];