added gitingore

This commit is contained in:
toni
2017-12-19 20:41:29 +01:00
parent e8dbaec6c4
commit 70cf17c479
12 changed files with 332 additions and 223 deletions

9
android/ConductorsPhone/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild

View File

@@ -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'

View File

@@ -19,10 +19,13 @@
<!--
Set to true if your app is Standalone, that is, it does not require the handheld
app to run.
-->
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
-->
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
android:name=".MainActivity"

View File

@@ -399,7 +399,7 @@ public class Croller extends View {
@Override
public boolean onTouchEvent(MotionEvent e) {
float distancePointToMiddle = Utils.getDistance(e.getX(), e.getY(), midx, midy);
double distancePointToMiddle = Utils.getDistance(e.getX(), e.getY(), midx, midy);
if ((distancePointToMiddle > touchCircleRadiusMax || distancePointToMiddle < touchCircleRadiusMin)) {
if (startEventSent && mCrollerChangeListener != null) {
mCrollerChangeListener.onStopTrackingTouch(this);

View File

@@ -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<OnBpmEstimatorListener> listeners = new CopyOnWriteArrayList<OnBpmEstimatorListener>();

View File

@@ -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<MessageApi.SendMessageResult>() {
@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<Float> bpmList) {
public void onFragmentStopped(Vector<Double> 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<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
for (Node node : nodes.getNodes()) {
mNode = node;
}
}
});
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Vector;
public class WorkerFragment extends Fragment implements Metronome.OnMetronomeListener, Estimator.OnBpmEstimatorListener{
private OnFragmentInteractionListener mListener;
private Vector<Float> mBpmList; //TODO save to file.
private Vector<Double> 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<Float>();
mBpmList = new Vector<Double>();
// 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<Float> bpmList);
void onFragmentStopped(Vector<Double> bpmList);
}
}

View File

@@ -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<Double> 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<Double> data){
return sum(data) / data.size();
}
public static double median(LinkedList<Double> 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<array.length; i++ )
{
if (array[i] != 0){
array[j++] = array[i];
}
}
double[] newArray = new double[j];
System.arraycopy( array, 0, newArray, 0, j );
return newArray;
}
public static double[] greaterZero(double[] array){
int j = 0;
for( int i=0; i < array.length; i++ )
{
if (array[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<AccelerometerData> {
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<array.length; i++ )
{
if (array[i] != 0)
array[j++] = array[i];
}
float[] newArray = new float[j];
System.arraycopy( array, 0, newArray, 0, j );
return newArray;
}
//TODO: errorhandling maxLag = 0;
//TODO: größeren Testcase schreiben
public static float[] fftAutoCorrelation(float[] data, int maxLag) {
int n = data.length;
float[] x = Arrays.copyOf(data, n);
int mxl = Math.min(maxLag, n - 1);
int ceilLog2 = nextPow2(2*n -1);
int n2 = (int) Math.pow(2,ceilLog2);
// x - mean(x) (pointwise)
float x_mean = mean(x);
for(int i = 0; i < x.length; ++i){
x[i] -= x_mean;
}
// double the size of x and fill up with zeros. if x is not even, add additional 0
float[] x2 = new float[n2 * 2]; //need double the size for fft.realForwardFull (look into method description)
Arrays.fill(x2, 0);
System.arraycopy(x,0, x2, 0, x.length);
// x_fft calculate fft 1D
FloatFFT_1D fft = new FloatFFT_1D(n2);
fft.realForwardFull(x2);
// Cr = abs(x_fft).^2 (absolute with complex numbers is (r^2) + (i^2)
float[] Cr = new float[n2 * 2];
int j = 0;
for(int i = 0; i < x2.length; ++i){
Cr[j++] = sqr(x2[i]) + sqr(x2[i+1]);
++i; //skip the complex part
}
// ifft(Cr,[],1)
FloatFFT_1D ifft = new FloatFFT_1D(n2);
ifft.realInverseFull(Cr, true);
// remove complex part and scale/normalize
float[] c1 = new float[n2];
j = 0;
for(int i = 0; i < Cr.length; ++i){
c1[j++] = Cr[i] / Cr[0];
++i; //skip the complex part
}
// Keep only the lags we want and move negative lags before positive lags.
float[] c = new float[(mxl * 2) + 1];
System.arraycopy(c1, 0, c, mxl, mxl + 1); // +1 to place the 1.0 in the middle of correlation
System.arraycopy(c1, n2 - mxl, c, 0, mxl);
return c;
}
//TODO: findPeaks
}

View File

@@ -1,11 +1,3 @@
<resources>
<string name="app_name">Conductor\'s Watch</string>
<!--
This string is used for square devices and overridden by hello_world in
values-round/strings.xml for round devices.
-->
<string name="hello_world">Hello Square World!</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>

View File

@@ -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<Integer> 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<Integer> 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<Integer> 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;
}
}

View File

@@ -36,7 +36,7 @@ public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
}
public boolean isNextWindowReady(){
if((size() == mWindowSize || size() == mWindowSize / 2 || size() == mWindowSize / 4) && mOverlapCounter > mOverlapSize){
if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){
mOverlapCounter = 1;
return true;

View File

@@ -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;
}