added gitingore
This commit is contained in:
@@ -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'
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user