closes #17 testumgebung für mathe methoden
This commit is contained in:
@@ -6,12 +6,8 @@ import android.hardware.SensorEvent;
|
|||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
import de.tonifetzer.conductorswatch.utilities.Utils;
|
import de.tonifetzer.conductorswatch.utilities.Utils;
|
||||||
|
|
||||||
|
|||||||
9
java/.gitignore
vendored
Normal file
9
java/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
20
java/pom.xml
Normal file
20
java/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>de.toni.bpm</groupId>
|
||||||
|
<artifactId>bpm</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.wendykierp</groupId>
|
||||||
|
<artifactId>JTransforms</artifactId>
|
||||||
|
<version>3.1</version>
|
||||||
|
<classifier>with-dependencies</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
97
java/src/main/java/Main.java
Normal file
97
java/src/main/java/Main.java
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import java.awt.*;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by toni on 04/12/17.
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
|
||||||
|
// iterate trough files in measurements folder
|
||||||
|
for (File file : listOfFiles) {
|
||||||
|
if (file.isFile() && file.getName().contains(".csv")) {
|
||||||
|
|
||||||
|
Utils.AccelerometerWindowBuffer accWindowBuffer = new Utils.AccelerometerWindowBuffer(4096, 256);
|
||||||
|
|
||||||
|
|
||||||
|
//read the file line by line
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
|
||||||
|
for (String line; (line = br.readLine()) != null; ) {
|
||||||
|
// process the line.
|
||||||
|
String[] measurement = line.split(";");
|
||||||
|
|
||||||
|
//if linear acc
|
||||||
|
if(measurement[1].equals("2")){
|
||||||
|
long ts = Long.parseLong(measurement[0]);
|
||||||
|
float x = Float.parseFloat(measurement[2]);
|
||||||
|
float y = Float.parseFloat(measurement[3]);
|
||||||
|
float z = Float.parseFloat(measurement[4]);
|
||||||
|
accWindowBuffer.add(new Utils.AccelerometerData(ts, x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
//do calculation stuff
|
||||||
|
if(accWindowBuffer.isNextWindowReady()){
|
||||||
|
|
||||||
|
//print raw x,y,z
|
||||||
|
double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray();
|
||||||
|
double[] dX = IntStream.range(0, accWindowBuffer.getX().length).mapToDouble(i -> accWindowBuffer.getX()[i]).toArray();
|
||||||
|
double[] dY = IntStream.range(0, accWindowBuffer.getY().length).mapToDouble(i -> accWindowBuffer.getY()[i]).toArray();
|
||||||
|
double[] dZ = IntStream.range(0, accWindowBuffer.getZ().length).mapToDouble(i -> accWindowBuffer.getZ()[i]).toArray();
|
||||||
|
|
||||||
|
Plot plotRaw = Plot.plot(Plot.plotOpts().
|
||||||
|
title("Raw Acc Data").
|
||||||
|
legend(Plot.LegendFormat.BOTTOM)).
|
||||||
|
series("x", Plot.data().xy(dTs, dX), Plot.seriesOpts().color(Color.RED)).
|
||||||
|
series("y", Plot.data().xy(dTs, dY), Plot.seriesOpts().color(Color.BLUE)).
|
||||||
|
series("z", Plot.data().xy(dTs, dZ), Plot.seriesOpts().color(Color.GREEN));
|
||||||
|
|
||||||
|
windowRaw.set(plotRaw.draw());
|
||||||
|
|
||||||
|
//auto corr
|
||||||
|
float[] xAutoCorr = Utils.fftAutoCorrelation(accWindowBuffer.getX(), 1024);
|
||||||
|
float[] yAutoCorr = Utils.fftAutoCorrelation(accWindowBuffer.getY(), 1024);
|
||||||
|
float[] zAutoCorr = Utils.fftAutoCorrelation(accWindowBuffer.getZ(), 1024);
|
||||||
|
|
||||||
|
//print autocorr
|
||||||
|
int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray();
|
||||||
|
double[] rangeAuto = IntStream.range(0, tmp.length).mapToDouble(i -> tmp[i]).toArray();
|
||||||
|
double[] dXAuto = IntStream.range(0, xAutoCorr.length).mapToDouble(i -> xAutoCorr[i]).toArray();
|
||||||
|
double[] dYAuto = IntStream.range(0, yAutoCorr.length).mapToDouble(i -> yAutoCorr[i]).toArray();
|
||||||
|
double[] dZAuto = IntStream.range(0, zAutoCorr.length).mapToDouble(i -> zAutoCorr[i]).toArray();
|
||||||
|
|
||||||
|
Plot plotCorr = Plot.plot(Plot.plotOpts().
|
||||||
|
title("Auto Correlation").
|
||||||
|
legend(Plot.LegendFormat.BOTTOM)).
|
||||||
|
series("x", Plot.data().xy(rangeAuto, dXAuto), Plot.seriesOpts().color(Color.RED)).
|
||||||
|
series("y", Plot.data().xy(rangeAuto, dYAuto), Plot.seriesOpts().color(Color.BLUE)).
|
||||||
|
series("z", Plot.data().xy(rangeAuto, dZAuto), Plot.seriesOpts().color(Color.GREEN));
|
||||||
|
|
||||||
|
windowAuto.set(plotCorr.draw());
|
||||||
|
|
||||||
|
//find peaks
|
||||||
|
|
||||||
|
//fill hols improve peaks
|
||||||
|
|
||||||
|
//estimate bpm between detected peaks
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// line is not visible here.
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1027
java/src/main/java/Plot.java
Normal file
1027
java/src/main/java/Plot.java
Normal file
File diff suppressed because it is too large
Load Diff
210
java/src/main/java/Utils.java
Normal file
210
java/src/main/java/Utils.java
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import org.jtransforms.fft.FloatFFT_1D;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public static class ShowPNG extends JFrame
|
||||||
|
{
|
||||||
|
JLabel mLabel;
|
||||||
|
ImageIcon mIcon;
|
||||||
|
|
||||||
|
public ShowPNG(){
|
||||||
|
mLabel = new JLabel();
|
||||||
|
this.setLayout(new GridLayout(1,1));
|
||||||
|
this.setSize(800, 640);
|
||||||
|
this.add(mLabel);
|
||||||
|
this.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(BufferedImage bi){
|
||||||
|
|
||||||
|
mIcon = new ImageIcon(bi);
|
||||||
|
mLabel.setVisible(false);
|
||||||
|
mLabel.setIcon(mIcon);
|
||||||
|
mLabel.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user