From 70cf17c479350743fee0ff5488dc4b62d3253d0b Mon Sep 17 00:00:00 2001 From: toni Date: Tue, 19 Dec 2017 20:41:29 +0100 Subject: [PATCH] added gitingore --- android/ConductorsPhone/.gitignore | 9 + android/ConductorsWatch/app/build.gradle | 6 +- .../app/src/main/AndroidManifest.xml | 5 +- .../tonifetzer/conductorswatch/Croller.java | 2 +- .../tonifetzer/conductorswatch/Estimator.java | 20 +- .../conductorswatch/MainActivity.java | 123 ++++++- .../conductorswatch/WorkerFragment.java | 17 +- .../conductorswatch/utilities/Utils.java | 328 ++++++++---------- .../app/src/main/res/values/strings.xml | 8 - java/src/main/java/Main.java | 26 +- .../AccelerometerWindowBuffer.java | 2 +- .../main/java/bpmEstimation/BpmEstimator.java | 9 +- 12 files changed, 332 insertions(+), 223 deletions(-) create mode 100644 android/ConductorsPhone/.gitignore diff --git a/android/ConductorsPhone/.gitignore b/android/ConductorsPhone/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/android/ConductorsPhone/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/android/ConductorsWatch/app/build.gradle b/android/ConductorsWatch/app/build.gradle index 7eec5f0..3379d81 100644 --- a/android/ConductorsWatch/app/build.gradle +++ b/android/ConductorsWatch/app/build.gradle @@ -28,12 +28,16 @@ android { } } + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.google.android.support:wearable:2.1.0' - implementation 'com.google.android.gms:play-services-wearable:11.6.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' diff --git a/android/ConductorsWatch/app/src/main/AndroidManifest.xml b/android/ConductorsWatch/app/src/main/AndroidManifest.xml index 5cff24e..6593bfa 100644 --- a/android/ConductorsWatch/app/src/main/AndroidManifest.xml +++ b/android/ConductorsWatch/app/src/main/AndroidManifest.xml @@ -19,10 +19,13 @@ + --> + + touchCircleRadiusMax || distancePointToMiddle < touchCircleRadiusMin)) { if (startEventSent && mCrollerChangeListener != null) { mCrollerChangeListener.onStopTrackingTouch(this); 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 2c738c1..b672320 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 @@ -9,6 +9,9 @@ import android.os.Handler; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import de.tonifetzer.conductorswatch.bpmEstimation.AccelerometerData; +import de.tonifetzer.conductorswatch.bpmEstimation.AccelerometerWindowBuffer; +import de.tonifetzer.conductorswatch.bpmEstimation.BpmEstimator; import de.tonifetzer.conductorswatch.utilities.Utils; /** @@ -21,7 +24,8 @@ public class Estimator implements SensorEventListener { private SensorManager mSensorManager; private Sensor mAccelerometer; private Context mContext; - private Utils.AccelerometerWindowBuffer mAccelerometerWindowBuffer; + private AccelerometerWindowBuffer mAccelerometerWindowBuffer; + private BpmEstimator mBpmEstimator; private Handler mHandler; private int mUpdaterate_ms = 100; @@ -34,13 +38,10 @@ public class Estimator implements SensorEventListener { if(mAccelerometerWindowBuffer.isNextWindowReady()){ - //TODO: calculate average samplerate using the window - interpolation of sensordata would be better i think - - //int randomNum = ThreadLocalRandom.current().nextInt(0, 240 + 1); - long diff = mAccelerometerWindowBuffer.getYongest().ts - mAccelerometerWindowBuffer.getOldest().ts; + double bpm = mBpmEstimator.estimate(); for (OnBpmEstimatorListener listener:listeners) { - listener.onNewDataAvailable((float) diff); + listener.onNewDataAvailable(bpm); } } @@ -61,7 +62,8 @@ public class Estimator implements SensorEventListener { mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST); - mAccelerometerWindowBuffer = new Utils.AccelerometerWindowBuffer(4096, 256); + mAccelerometerWindowBuffer = new AccelerometerWindowBuffer(1024, 256); + mBpmEstimator = new BpmEstimator(mAccelerometerWindowBuffer, 0, 5000); mHandler = new Handler(); mHandler.post(mProcessSensors); //start runnable @@ -81,7 +83,7 @@ public class Estimator implements SensorEventListener { //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])); + mAccelerometerWindowBuffer.add(new AccelerometerData(System.currentTimeMillis(), se.values[0], se.values[1], se.values[2])); } // mSensorUpdateFlag = false; @@ -98,7 +100,7 @@ public class Estimator implements SensorEventListener { * Interface for callback calculated bpm */ public interface OnBpmEstimatorListener { - void onNewDataAvailable(float bpm); + void onNewDataAvailable(double bpm); } private List listeners = new CopyOnWriteArrayList(); diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java index 64d0c7e..6bf9bce 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java @@ -7,18 +7,31 @@ import android.graphics.Point; import android.os.Bundle; import android.os.Handler; import android.os.Vibrator; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.wearable.activity.WearableActivity; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.TextView; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.wearable.MessageApi; +import com.google.android.gms.wearable.Node; +import com.google.android.gms.wearable.NodeApi; +import com.google.android.gms.wearable.Wearable; + import java.sql.Time; +import java.util.List; import java.util.Vector; +import java.util.concurrent.TimeUnit; import de.tonifetzer.conductorswatch.utilities.Utils; -public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener, TapBpm.OnTapBpmListener{ +public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener, TapBpm.OnTapBpmListener, GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener{ // member private TextView mTextView; @@ -26,6 +39,13 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF private GestureDetector mDetector; private boolean mModeRecord; + // connection to phone stuff + private static final String START_ACTIVITY_PATH = "/start-activity"; + public static final String TAG = "DataLayerListenerService"; + private GoogleApiClient mGoogleApiClient; + private Node mNode; + private boolean mResolvingError = false; + // display center private int mDisplayWidth; private int mDisplayHeight; @@ -47,6 +67,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF private int mLongPressDelay = 1200; // in Milliseconds private boolean mLongPressHandlerActivated = false; private final Handler mHandler = new Handler(); + private Runnable mLongPressed = new Runnable() { public void run() { Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); @@ -91,7 +112,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); //make sure the longPress only works within the maincircle of the scroller - float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, (float) (mDisplayWidth / 2.0f), (float) (mDisplayHeight / 2.0f)); + double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, (mDisplayWidth / 2.0f), (mDisplayHeight / 2.0f)); if ((distancePointToMiddle > mCroller.getMainCircleRadius())){ mHandler.removeCallbacks(mLongPressed); return false; @@ -134,7 +155,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); //only works within the maincircle of the scroller - float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y); + double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y); if ((distancePointToMiddle > mCroller.getMainCircleRadius())){ //if we are outside the area of interest and the animation is already running, we need to reset @@ -170,7 +191,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); //only works within the maincircle of the scroller - float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y); + double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y); if ((distancePointToMiddle > mCroller.getMainCircleRadius())){ mCroller.setProgress(mCroller.getProgress()); @@ -204,6 +225,14 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + //init GoogleApiClient and get nodeid (phone) + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Wearable.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + + //get display infos mDisplayWidth= this.getResources().getDisplayMetrics().widthPixels; mDisplayHeight= this.getResources().getDisplayMetrics().heightPixels; mDisplayCenter = new Point((mDisplayWidth / 2), (mDisplayHeight / 2)); @@ -224,6 +253,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF public void onProgressChanged(int progress) { // use the progress mTextView.setText(String.valueOf(progress)); + sendMessage(Integer.toString(progress)); } }); @@ -242,6 +272,29 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF setAmbientEnabled(); } + private void sendMessage(String Key) { + + if (mNode != null && mGoogleApiClient!= null && mGoogleApiClient.isConnected()) { + Log.d(TAG, "-- " + mGoogleApiClient.isConnected()); + Wearable.MessageApi.sendMessage( + mGoogleApiClient, mNode.getId(), Key, new byte[0]).setResultCallback( + + new ResultCallback() { + @Override + public void onResult(MessageApi.SendMessageResult sendMessageResult) { + + Log.d(TAG, "--- " + sendMessageResult.getStatus().getStatusCode()); + if (!sendMessageResult.getStatus().isSuccess()) { + Log.e(TAG, "Failed to send message with status code: " + + sendMessageResult.getStatus().getStatusCode()); + } + } + } + ); + } + + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { @@ -265,14 +318,33 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF @Override - public void onFragmentStopped(Vector bpmList) { + public void onFragmentStopped(Vector bpmList) { //TODO: save the bpmList into a file + //TODO: send bpmList and all other data to phone Log.d("FragmentListener", "Received bpmList"); } + @Override + protected void onStart() { + super.onStart(); + if (!mResolvingError) { + mGoogleApiClient.connect(); + } + + + //start app on phone + //TODO: bissle cleverer machen. starten und auf antwort warten. falls er sagt "bin schon an" nicht mehr senden + // ansonsten nochmal versuchen.bzw. auch von anderen stellen (bei click etc) aufrufen. + + + + + //TODO: disconnect or own class for this stuff + } + @Override public void onNewEstimation(int bpm) { mTapBpmEstimation = bpm; @@ -310,4 +382,45 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF e.printStackTrace(); } } + + @Override + public void onConnected(@Nullable Bundle bundle) { + resolveNode(); + + + new Thread(new Runnable() { + @Override + public void run() { + + while(mNode == null){ + + } + sendMessage(START_ACTIVITY_PATH); + } + }).start(); + + } + + @Override + public void onConnectionSuspended(int i) { + + } + + @Override + public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { + + } + + private void resolveNode() { + + Wearable.NodeApi.getConnectedNodes(mGoogleApiClient) + .setResultCallback(new ResultCallback() { + @Override + public void onResult(NodeApi.GetConnectedNodesResult nodes) { + for (Node node : nodes.getNodes()) { + mNode = node; + } + } + }); + } } diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java index 3148786..5a13fee 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java @@ -22,7 +22,7 @@ import java.util.Vector; public class WorkerFragment extends Fragment implements Metronome.OnMetronomeListener, Estimator.OnBpmEstimatorListener{ private OnFragmentInteractionListener mListener; - private Vector mBpmList; //TODO save to file. + private Vector mBpmList; //TODO save to file. private Estimator mEstimator; private Metronome mMetronome; @@ -59,7 +59,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis mEstimator = new Estimator(getContext()); mEstimator.add(this); //mBpmThread = new Thread(mEstimator, "estThread"); - mBpmList = new Vector(); + mBpmList = new Vector(); // init metronome and listener @@ -138,17 +138,22 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis */ @Override public void onNewClick() { - mVibrator.vibrate(10); + //mVibrator.vibrate(10); } /** * Callback function for Bpm estimation update */ @Override - public void onNewDataAvailable(float bpm) { + public void onNewDataAvailable(double bpm) { //TODO: what if multiple threads access mBpmList? put into synchronized? @frank fragen :D //TODO: send this to smartphone + + if(bpm == -1){ + //to stuff with UI. Write Text or make XX or something like that + } + mBpmList.add(bpm); // we need this here, since ui elements can only be changed within activity thread and @@ -160,7 +165,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis public void run() { mTextView.setText(String.valueOf(mBpmList.lastElement())); - mCroller.setProgress((Math.round(mBpmList.lastElement()))); + mCroller.setProgress((int)(Math.round(mBpmList.lastElement()))); } }); } @@ -170,7 +175,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis * Interface for connecting to WorkerFragment */ public interface OnFragmentInteractionListener { - void onFragmentStopped(Vector bpmList); + void onFragmentStopped(Vector bpmList); } } diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java index f4b0909..bb76e58 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java @@ -3,14 +3,162 @@ package de.tonifetzer.conductorswatch.utilities; import android.content.Context; import android.content.res.Resources; import android.util.DisplayMetrics; -import org.jtransforms.fft.FloatFFT_1D; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedList; +//TODO: change from double to generic type public class Utils { - public static float getDistance(float x1, float y1, float x2, float y2) { - return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + public static double getDistance(double x1, double y1, double x2, double y2) { + return (double) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + + public static double sqr(double x) { + return x * x; + } + + public static int nextPow2(int a){ + return a == 0 ? 0 : 32 - Integer.numberOfLeadingZeros(a - 1); + } + + public static double sum(double[] data){ + double sum = 0; + for (int i = 0; i < data.length; i++) { + sum += data[i]; + } + return sum; + } + + public static long sum(long[] data){ + long sum = 0; + for (int i = 0; i < data.length; i++) { + sum += data[i]; + } + return sum; + } + + public static double sum (LinkedList data){ + double sum = 0; + for (int i = 0; i < data.size(); i++) { + sum += data.get(i).doubleValue(); + } + return sum; + } + + //TODO: Could be slow.. faster method? + public static double rms(double[] nums) { + double sum = 0.0f; + for (double num : nums) + sum += num * num; + return Math.sqrt(sum / nums.length); + } + + public static double[] diff(double[] data){ + double[] diff = new double[data.length - 1]; + int i=0; + for(int j = 1; j < data.length; ++j){ + diff[i] = data[j] - data[i]; + ++i; + } + return diff; + } + + public static long[] diff(long[] data){ + long[] diff = new long[data.length - 1]; + int i=0; + for(int j = 1; j < data.length; ++j){ + diff[i] = data[j] - data[i]; + ++i; + } + return diff; + } + + public static double mean(double[] data){ + return sum(data) / data.length; + } + + public static double mean(long[] data){ + return (double) sum(data) / (double) data.length; + } + + public static double mean(LinkedList data){ + return sum(data) / data.size(); + } + + public static double median(LinkedList data){ + data.sort(Comparator.naturalOrder()); + + double median; + if (data.size() % 2 == 0) + median = (data.get(data.size()/2) + data.get(data.size()/2 - 1))/2; + else + median = data.get(data.size()/2); + + return median; + } + + //TODO: Could be slow.. faster method? + public static double geometricMean(double[] data) { + double sum = data[0]; + for (int i = 1; i < data.length; i++) { + sum *= data[i]; + } + return Math.pow(sum, 1.0 / data.length); + } + + public static int intersectionNumber(double[] signal, double border){ + int cnt = 0; + boolean isSmallerValue = false; + boolean isBiggerValue = false; + + for(double value : signal){ + if(value < border){ + if(isBiggerValue){ + cnt++; + } + + isSmallerValue = true; + isBiggerValue = false; + } + else { + if(isSmallerValue){ + cnt++; + } + + isSmallerValue = false; + isBiggerValue = true; + } + } + + return cnt; + } + + public static double[] removeZero(double[] array){ + int j = 0; + for( int i=0; i 0){ + array[j++] = array[i]; + } + } + double[] newArray = new double[j]; + System.arraycopy( array, 0, newArray, 0, j ); + + return newArray; } public static float convertDpToPixel(float dp, Context context) { @@ -25,174 +173,4 @@ 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; - } - } - - public static class AccelerometerWindowBuffer extends ArrayList { - - private int mWindowSize; - private int mOverlapSize; - private int mOverlapCounter; - private float[] mX; - private float[] mY; - private float[] mZ; - private long[] mTs; - - public AccelerometerWindowBuffer(int windowSize, int overlap){ - this.mWindowSize = windowSize; - this.mOverlapSize = overlap; - mOverlapCounter = 1; - - mX = new float[this.mWindowSize]; - mY = new float[this.mWindowSize]; - mZ = new float[this.mWindowSize]; - mTs = new long[this.mWindowSize]; - } - - public boolean add(AccelerometerData ad){ - boolean r = super.add(ad); - if (size() > mWindowSize){ - removeRange(0, size() - mWindowSize); - } - - //update the double arrays. - for (int i = 0; i < size(); ++i) { - mX[i] = get(i).x; - mY[i] = get(i).y; - mZ[i] = get(i).z; - mTs[i] = get(i).ts; - } - - ++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 float[] getX(){ - return mX; - } - - public float[] getY(){ - return mY; - } - - public float[] getZ(){ - return mZ; - } - - public long[] getTs(){ - return mTs; - } - } - - - public static float sqr(float x) { - return x * x; - } - - public static int nextPow2(int a){ - return a == 0 ? 0 : 32 - Integer.numberOfLeadingZeros(a - 1); - } - - public static float mean(float[] data){ - float sum = 0; - for (int i = 0; i < data.length; i++) { - sum += data[i]; - } - return sum / data.length; - } - - public static float[] removeZero(float[] array){ - int j = 0; - for( int i=0; i Conductor\'s Watch - - Hello Square World! - - - Hello blank fragment diff --git a/java/src/main/java/Main.java b/java/src/main/java/Main.java index 583ff1e..659a841 100644 --- a/java/src/main/java/Main.java +++ b/java/src/main/java/Main.java @@ -6,6 +6,8 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.util.LinkedList; +import java.util.stream.IntStream; /** @@ -16,19 +18,19 @@ public class Main { public static void main(String [ ] args) { File folder = new File("/home/toni/Documents/programme/dirigent/measurements/wearR"); File[] listOfFiles = folder.listFiles(); -/* + Utils.ShowPNG windowRaw = new Utils.ShowPNG(); Utils.ShowPNG windowAuto = new Utils.ShowPNG(); Utils.ShowPNG windowPeaksX = new Utils.ShowPNG(); Utils.ShowPNG windowPeaksY = new Utils.ShowPNG(); Utils.ShowPNG windowPeaksZ = new Utils.ShowPNG(); -*/ + // iterate trough files in measurements folder for (File file : listOfFiles) { if (file.isFile() && file.getName().contains(".csv")) { - AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(4096, 256); + AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(1024, 256); BpmEstimator bpmEstimator = new BpmEstimator(accWindowBuffer, 0, 5000); //read the file line by line @@ -51,9 +53,9 @@ public class Main { double curBpm = bpmEstimator.estimate(); //System.out.println("BPM: " + curBpm); -/* - AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, bpmEstimator.getSampleRate_ms()); + + AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, 5); //print raw x,y,z double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray(); @@ -68,9 +70,9 @@ public class Main { windowRaw.set(plotRaw.draw()); //auto corr - double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 1024).getCorr(); - double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 1024).getCorr(); - double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 1024).getCorr(); + double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 512).getCorr(); + double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 512).getCorr(); + double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 512).getCorr(); //print autocorr int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray(); @@ -87,7 +89,7 @@ public class Main { Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false); LinkedList peaksX = pX.getPeaksIdx(); - double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); + double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - 512)).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"). @@ -101,7 +103,7 @@ public class Main { Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false); LinkedList peaksY = pY.getPeaksIdx(); - double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); + double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - 512)).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"). @@ -115,7 +117,7 @@ public class Main { Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false); LinkedList peaksZ = pZ.getPeaksIdx(); - double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray(); + double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - 512)).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"). @@ -134,7 +136,7 @@ public class Main { //System.out.println("BPM-Z: " + pZ.getBPM(bpmEstimator.getSampleRate_ms())); //todo: kleiner fenstergrößen testen. so ist doch etwas langsam auf der Uhr. -*/ + int dummyForBreakpoint = 0; } } diff --git a/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java b/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java index f1d846b..889ce95 100644 --- a/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java +++ b/java/src/main/java/bpmEstimation/AccelerometerWindowBuffer.java @@ -36,7 +36,7 @@ public class AccelerometerWindowBuffer extends ArrayList { } public boolean isNextWindowReady(){ - if((size() == mWindowSize || size() == mWindowSize / 2 || size() == mWindowSize / 4) && mOverlapCounter > mOverlapSize){ + if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){ mOverlapCounter = 1; return true; diff --git a/java/src/main/java/bpmEstimation/BpmEstimator.java b/java/src/main/java/bpmEstimation/BpmEstimator.java index 21c98a8..ac90867 100644 --- a/java/src/main/java/bpmEstimation/BpmEstimator.java +++ b/java/src/main/java/bpmEstimation/BpmEstimator.java @@ -77,6 +77,7 @@ public class BpmEstimator { //kalman filter (lohnt dann, wenn wir konstantes tempo haben, mit startangabe!) mBpmHistory.add(estimatedBPM); + mResetCounter = 0; } else { int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate)); @@ -102,9 +103,9 @@ public class BpmEstimator { private double getBestBpmEstimation(Peaks peaksX, Peaks peaksY, Peaks peaksZ) throws IllegalArgumentException { int cntNumAxis = 0; - double sumCorr = 1; //to prevent division by zero - double sumRms = 1; - double sumNumInter = 1; + double sumCorr = 0; //to prevent division by zero + double sumRms = 0; + double sumNumInter = 0; double corrMeanX = 0, corrRmsX = 0; int corrNumInterX = 0; @@ -167,7 +168,7 @@ public class BpmEstimator { //values to low, reject //TODO: this is a pretty simple assumption. first shot! - if(corrRmsX < 0.2 && corrRmsY < 0.2 && corrRmsZ < 0.2){ + if(corrRmsX < 0.25 && corrRmsY < 0.25 && corrRmsZ < 0.25){ return -1; }