https://blog.youkuaiyun.com/warren288/article/details/43274647
package com.shark.angletest.angletest;
import android.app.Activity;
import android.content.Context;import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static final String TAG = "sharkAngle";
static final int SAMPLE_COUNT = 5;
static final float MOVE_THRESHOLD = 1.0f;
SensorCenter mSC;
TextView mTV;
float[] mAngles = new float[SAMPLE_COUNT];
int mIndex = 0;
//定义接口
public interface IListener <T>{
public void onCall(T obj);//(float value);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.textAngle);
}
@Override
protected void onResume() {
super.onResume();
mSC = new SensorCenter();
mSC.init(this);
mSC.registerOrientationListener(new IListener() {
@Override
public void onCall(Object value) {
// TODO Auto-generated method stub
boolean isMove = false;
mAngles [mIndex++] = (float)value;
//Log.d(TAG, "onCall value:" + mAngles[mIndex-1]);
if (mIndex >= SAMPLE_COUNT) {
for (int i = 0; i < mIndex - 1; i++) {
float cur = Math.abs(mAngles[i + 1] - mAngles[i]);
//Log.d(TAG, "cur diff " + cur);
if (Math.abs(mAngles[i + 1] - mAngles[i]) > MOVE_THRESHOLD) {
isMove = true;
} else {
isMove = false;
}
}
mIndex = 0;
String result = isMove ? "moving....." : "standstill...";
mTV.setText(result/*String.valueOf((float)value)*/);
}
}
}
);
}
@Override
protected void onStop() {
super.onStop();
if (mSC != null) {
mSC.unregister();
}
}
/* 方向传感器中心。<br>
* 使用方法为:创建对象后使用 {@link #init(Activity)} 初始化上下文环境,使用
* {@link #registerOrientationListener(IListener)} 注册
* 方向变化监听器,使用完毕后(一般在 {@link #init(Activity)}中所使用 {@link Activity}
* 销毁时), {@link #unregister()}取消本类内部注册的 {@link SensorEventListener}
* @author yangsheng
* @date 2015年1月28日
*/
private static class SensorCenter {
private float[] accelerValues = new float[3];
private float[] magneticValues = new float[3];
private final SensorEventListener sensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
// 深度复制,可避免部分设备下 SensorManager.getRotationMatrix 返回false的问题
case Sensor.TYPE_ACCELEROMETER:
for (int i = 0; i < 3; i++) {
accelerValues[i] = event.values[i];
}
if (listener != null) {
listener.onCall(getAngle());
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for (int i = 0; i < 3; i++) {
magneticValues[i] = event.values[i];
}
break;
case Sensor.TYPE_GYROSCOPE:
break;
default:
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
private SensorManager sensorManager;
private Activity activity;
private IListener<Float> listener;
private int axis_x;
private int axis_y;
public SensorCenter init(Activity activity) {
this.activity = activity;
this.sensorManager = (SensorManager) this.activity
.getSystemService(Context.SENSOR_SERVICE);
// 注册三个传感器监听,加速度传感器、磁场传感器、陀螺仪传感器。
// 陀螺仪传感器是可选的,也没有实际用处,但是在部分设备上,如果没注册它,会导致
// SensorManager.getRotationMatrix 返回false
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_UI);
initIn();
return this;
}
private void initIn() {
// 根据当前上下文的屏幕方向调整与自然方向的相对关系。
// 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向),而应用是横屏时,
// 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display dis = wm.getDefaultDisplay();
int rotation = dis.getRotation();
axis_x = SensorManager.AXIS_X;
axis_y = SensorManager.AXIS_Y;
switch (rotation) {
case Surface.ROTATION_0:
break;
case Surface.ROTATION_90:
axis_x = SensorManager.AXIS_Y;
axis_y = SensorManager.AXIS_MINUS_X;
break;
case Surface.ROTATION_180:
axis_x = SensorManager.AXIS_X;
axis_y = SensorManager.AXIS_MINUS_Y;
break;
case Surface.ROTATION_270:
axis_x = SensorManager.AXIS_MINUS_Y;
axis_y = SensorManager.AXIS_X;
break;
default:
break;
}
}
/**
* 注册方向变换监听
* @param listener, {@link IListener#onCall(Object)}
* 中的参数为相对正北方向的方位角,范围:-180~180
*/
public void registerOrientationListener(IListener<Float> listener) {
this.listener = listener;
}
/**
* 取方位角
* @return
*/
private float getAngle() {
float[] inR = new float[9];
// 第一个是方向角度参数,第二个参数是倾斜角度参数
SensorManager.getRotationMatrix(inR, null, accelerValues, magneticValues);
float[] outR = new float[9];
float[] orientationValues = new float[3];
// 根据当前上下文的屏幕方向调整与自然方向的相对关系。
// 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向,而有些平板的自然方向是水平方向),而应用是横屏时,
// 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
SensorManager.remapCoordinateSystem(inR, axis_x, axis_y, outR);
SensorManager.getOrientation(outR, orientationValues);
return (float) Math.toDegrees(orientationValues[0]);
}
/**
* 取消注册的传感器监听
*/
public void unregister() {
try {
sensorManager.unregisterListener(sensorListener);
} catch (Exception e) {
//LogTool.exception(e);
Log.d(TAG, "error:" +e.toString());
}
}
}
}
利用傅里叶变换,效果好点
package com.shark.angletest.angletest;
import android.util.Log;
/**
* Created by root on 7/12/18.
*/
public class MyFft {
/* public MyFft() {
}
*//*
*实现倒码
**//*
public static Complex[] changedLow(Complex[] a, int length) {
int mr = 0;
for (int m = 1; m < length; ++m) {
int l = length / 2;
while (mr + l >= length) {
l = l >> 1; //右移相当于,l除以2
}
mr = mr % l + l;
if (mr > m) {
Complex t = new Complex();
t = a[m];
a[m] = a[mr];
a[mr] = t;
}
}
return a;
}
*//*
*乘积因子
**//*
public Complex complex_exp(Complex z) {
Complex r = new Complex();
double expx = Math.exp(z.r);
r.r = expx * Math.cos(z.i);
r.i = expx * Math.sin(z.i);
return r;
}
*//*
*基-2 fft蝶形变换
*fft_tepy=1正变换, -1反变换
**//*
public Complex[] fft_2(Complex[] a, int length, int fft_tepy) {
double pisign = fft_tepy * Math.PI;
// System.out.print(" pisign:"+pisign+"\n");
Complex t = new Complex();
int l = 1;
while (l < length) {
for (int m = 0; m < l; ++m) {
int temp_int = l * 2; //左移相当于,l乘以2
for (int i = m; temp_int < 0 ? i >= (length - 1) : i < length; i += temp_int) {
Complex temp = new Complex(0.0, m * pisign / l);
Complex temp_exp = complex_exp(temp);
t.r = a[i + l].r * temp_exp.r - a[i + l].i * temp_exp.i;
t.i = a[i + l].r * temp_exp.i + a[i + l].i * temp_exp.r;
a[i + l].r = a[i].r - t.r;
a[i + l].i = a[i].i - t.i;
a[i].r = a[i].r + t.r;
a[i].i = a[i].i + t.i;
} // end for i
} // end for m
Log.d(MainActivity.TAG, "\n now is the loop and l=" + l + "\n");
for (int c = 0; c < length; c++) {
Log.d(MainActivity.TAG, a[c].r + "+j" + a[c].i + "\n");
}
l = l * 2;
}//end while
//左移相当于,l乘以2
return a;
}*/
public Complex[] fft(Complex[] x) {
int n = x.length;
// 因为exp(-2i*n*PI)=1,n=1时递归原点
if (n == 1){
return x;
}
// 如果信号数为奇数,使用dft计算
if (n % 2 != 0) {
return dft(x);
}
// 提取下标为偶数的原始信号值进行递归fft计算
Complex[] even = new Complex[n / 2];
for (int k = 0; k < n / 2; k++) {
even[k] = x[2 * k];
}
Complex[] evenValue = fft(even);
// 提取下标为奇数的原始信号值进行fft计算
// 节约内存
Complex[] odd = even;
for (int k = 0; k < n / 2; k++) {
odd[k] = x[2 * k + 1];
}
Complex[] oddValue = fft(odd);
// 偶数+奇数
Complex[] result = new Complex[n];
for (int k = 0; k < n / 2; k++) {
// 使用欧拉公式e^(-i*2pi*k/N) = cos(-2pi*k/N) + i*sin(-2pi*k/N)
double p = -2 * k * Math.PI / n;
Complex m = new Complex(Math.cos(p), Math.sin(p));
result[k] = evenValue[k].add(m.multiply(oddValue[k]));
// exp(-2*(k+n/2)*PI/n) 相当于 -exp(-2*k*PI/n),其中exp(-n*PI)=-1(欧拉公式);
result[k + n / 2] = evenValue[k].minus(m.multiply(oddValue[k]));
}
return result;
}
public Complex[] dft(Complex[] x) {
int n = x.length;
// 1个信号exp(-2i*n*PI)=1
if (n == 1)
return x;
Complex[] result = new Complex[n];
for (int i = 0; i < n; i++) {
result[i] = new Complex(0, 0);
for (int k = 0; k < n; k++) {
//使用欧拉公式e^(-i*2pi*k/N) = cos(-2pi*k/N) + i*sin(-2pi*k/N)
double p = -2 * k * Math.PI / n;
Complex m = new Complex(Math.cos(p), Math.sin(p));
result[i]=result[i].add(x[k].multiply(m));
//Log.d(MainActivity.TAG, "dft,p:"+String.valueOf(p)+";xk:"+x[k]+";m:"+m.toString()+";ret:"+result[i].toString());
}
}
return result;
}
}
package com.shark.angletest.angletest;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static final String TAG = "sharkAngle";
static final int SAMPLE_COUNT = 6;
static final float MOVE_THRESHOLD = 0.6f;
SensorCenter mSC;
TextView mTV;
float[] mAngles = new float[SAMPLE_COUNT];
int mIndex = 0;
//定义接口
public interface IListener <T>{
public void onCall(T obj);//(float value);
public void xonCall(boolean moving);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.textAngle);
}
@Override
protected void onResume() {
super.onResume();
mSC = new SensorCenter();
mSC.init(this);
mSC.registerOrientationListener(new IListener() {
@Override
public void onCall(Object value) {
// TODO Auto-generated method stub
int standstillCnt = 0;
boolean isMove = true;
mAngles [mIndex++] = (float)value;
Log.d(TAG, "onCall value:" + mAngles[mIndex-1]);
if (mIndex >= SAMPLE_COUNT) {
for (int i = 0; i < mIndex - 1; i++) {
float cur = Math.abs(mAngles[i + 1] - mAngles[i]);
Log.d(TAG, "cur:"+cur);
if (Math.abs(mAngles[i + 1] - mAngles[i]) < MOVE_THRESHOLD) {
standstillCnt++;
}
}
mIndex = 0;
if (standstillCnt >= (SAMPLE_COUNT+1)/2) isMove = false;
Log.d(TAG, "standstillCnt: " + standstillCnt);
String result = isMove ? "moving....." : "standstill...";
mTV.setText(result/*String.valueOf((float)value)*/);
}
}
@Override
public void xonCall(boolean moving) {
String result = moving ? "moving....." : "standstill...";
mTV.setText(result);
}
}
);
}
@Override
protected void onStop() {
super.onStop();
if (mSC != null) {
mSC.unregister();
}
}
/* 方向传感器中心。<br>
* 使用方法为:创建对象后使用 {@link #init(Activity)} 初始化上下文环境,使用
* {@link #registerOrientationListener(IListener)} 注册
* 方向变化监听器,使用完毕后(一般在 {@link #init(Activity)}中所使用 {@link Activity}
* 销毁时), {@link #unregister()}取消本类内部注册的 {@link SensorEventListener}
* @author yangsheng
* @date 2015年1月28日
*/
private static class SensorCenter {
private float[] accelerValues = new float[3];
private float[] magneticValues = new float[3];
//private float[] xarrays = new float[SAMPLE_COUNT];
//private float[] yarrays = new float[SAMPLE_COUNT];
//private float[] zarrays = new float[SAMPLE_COUNT];
Complex []xb= new Complex[SAMPLE_COUNT];
Complex []yb= new Complex[SAMPLE_COUNT];
Complex []zb= new Complex[SAMPLE_COUNT];
private int mIdx = 0;
private int mStillCnt = 0;
private final SensorEventListener sensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
// 深度复制,可避免部分设备下 SensorManager.getRotationMatrix 返回false的问题
case Sensor.TYPE_ACCELEROMETER:
xb[mIdx] = new Complex(event.values[0], 0);
yb[mIdx] = new Complex(event.values[1], 0);
zb[mIdx] = new Complex(event.values[2], 0);
mIdx++;
/*for (int i = 0; i < 3; i++) {
accelerValues[i] = event.values[i];
}
xb[mIdx] = accelerValues[0];
yarrays[mIdx] = accelerValues[1];
zarrays[mIdx] = accelerValues[2];
mIdx++;
*/
if (mIdx >= SAMPLE_COUNT) {
mIdx = 0;
int i;
MyFft mf = new MyFft();
final int n = SAMPLE_COUNT;
/*
int dd[] = new int[n];
for(i=0;i<n;i++){ //轮流赋值
xb[i] = new Complex(xarrays[i], 0);
yb[i] = new Complex(yarrays[i], 0);
zb[i] = new Complex(zarrays[i], 0);
}*/
Log.d(TAG, "-------------------------");
xb = mf.fft(xb);
for(i=0;i<n;i++){ Log.d(TAG, "fft xb["+i+"]"+xb[i].toString()); }
if(ismoving(xb)) {
mStillCnt=0;
listener.xonCall(true);
return;
}
yb = mf.fft(yb);
for(i=0;i<n;i++){ Log.d(TAG, "fft yb["+i+"]"+yb[i].toString()); }
if(ismoving(yb)) {
mStillCnt=0;
listener.xonCall(true);
return;
}
zb = mf.fft(zb);
for(i=0;i<n;i++){ Log.d(TAG, "fft zb["+i+"]"+zb[i].toString()); }
if(ismoving(zb)) {
mStillCnt=0;
listener.xonCall(true);
return;
}
if (listener != null) {
mStillCnt++;
if (mStillCnt > 3)
listener.xonCall(false);
}
Log.d(TAG, "-------------------------");
/*b=mf.changedLow(b,n);
for(i=0; i<n; i++) Log.d(TAG, b[i].toString());
b=mf.fft_2(b,n,-1);
for(i=0; i<n; i++) Log.d(TAG, b[i].toString());*/
/*float xcount = 0f, xavg = 0f;
float ycount = 0f, yavg = 0f;
float zcount = 0f, zavg = 0f;
for (i=0; i<SAMPLE_COUNT; i++) {
xcount += xarrays[i];
ycount += yarrays[i];
zcount += zarrays[i];
}
xavg = xcount / SAMPLE_COUNT;
yavg = ycount / SAMPLE_COUNT;
zavg = zcount / SAMPLE_COUNT;
float xspow=0f, yspow=0f, zspow=0f;
for (i=0; i<SAMPLE_COUNT; i++){
xspow += (xarrays[i] - xavg) * (xarrays[i] - xavg);
yspow += (yarrays[i] - xavg) * (yarrays[i] - yavg);
zspow += (zarrays[i] - xavg) * (zarrays[i] - zavg);
}
Log.d(TAG, "xshark xspow:"+xspow+";yspow:"+yspow+";zspow:"+zspow);*/
}
if (listener != null) {
//listener.onCall(getAngle());
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for (int i = 0; i < 3; i++) {
magneticValues[i] = event.values[i];
}
break;
case Sensor.TYPE_GYROSCOPE:
break;
default:
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
boolean ismoving(Complex[] x) {
int i, t = 0,n = x.length;
for(i=0;i<n;i++){
if (Math.abs(x[i].getM()) > 0.05f &&
Math.abs(x[i].getN()) > 0.05f) {
t++;
}
}
return t > (n/2+1);
}
};
private SensorManager sensorManager;
private Activity activity;
private IListener<Float> listener;
private int axis_x;
private int axis_y;
public SensorCenter init(Activity activity) {
this.activity = activity;
this.sensorManager = (SensorManager) this.activity
.getSystemService(Context.SENSOR_SERVICE);
// 注册三个传感器监听,加速度传感器、磁场传感器、陀螺仪传感器。
// 陀螺仪传感器是可选的,也没有实际用处,但是在部分设备上,如果没注册它,会导致
// SensorManager.getRotationMatrix 返回false
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(sensorListener,
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_UI);
initIn();
return this;
}
private void initIn() {
// 根据当前上下文的屏幕方向调整与自然方向的相对关系。
// 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向),而应用是横屏时,
// 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display dis = wm.getDefaultDisplay();
int rotation = dis.getRotation();
axis_x = SensorManager.AXIS_X;
axis_y = SensorManager.AXIS_Y;
switch (rotation) {
case Surface.ROTATION_0:
break;
case Surface.ROTATION_90:
axis_x = SensorManager.AXIS_Y;
axis_y = SensorManager.AXIS_MINUS_X;
break;
case Surface.ROTATION_180:
axis_x = SensorManager.AXIS_X;
axis_y = SensorManager.AXIS_MINUS_Y;
break;
case Surface.ROTATION_270:
axis_x = SensorManager.AXIS_MINUS_Y;
axis_y = SensorManager.AXIS_X;
break;
default:
break;
}
}
/**
* 注册方向变换监听
* @param listener, {@link IListener#onCall(Object)}
* 中的参数为相对正北方向的方位角,范围:-180~180
*/
public void registerOrientationListener(IListener<Float> listener) {
this.listener = listener;
}
/**
* 取方位角
* @return
*/
private float getAngle() {
float[] inR = new float[9];
// 第一个是方向角度参数,第二个参数是倾斜角度参数
SensorManager.getRotationMatrix(inR, null, accelerValues, magneticValues);
float[] outR = new float[9];
float[] orientationValues = new float[3];
// 根据当前上下文的屏幕方向调整与自然方向的相对关系。
// 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向,而有些平板的自然方向是水平方向),而应用是横屏时,
// 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
SensorManager.remapCoordinateSystem(inR, axis_x, axis_y, outR);
SensorManager.getOrientation(outR, orientationValues);
return (float) Math.toDegrees(orientationValues[0]);
}
/**
* 取消注册的传感器监听
*/
public void unregister() {
try {
sensorManager.unregisterListener(sensorListener);
} catch (Exception e) {
//LogTool.exception(e);
Log.d(TAG, "error:" +e.toString());
}
}
}
}
package com.shark.angletest.angletest;
/**
* Created by root on 7/12/18.
*/
class Complex{
private double m;// 实部
private double n;// 虚部
public Complex(double m, double n) {
this.m = m;
this.n = n;
}
// add
public Complex add(Complex c) {
return new Complex(m + c.m, n + c.n);
}
// minus
public Complex minus(Complex c) {
return new Complex(m - c.m, n - c.n);
}
// multiply
public Complex multiply(Complex c) {
return new Complex(m * c.m - n * c.n, m * c.n + n * c.m);
}
// divide
public Complex divide(Complex c) {
double d = Math.sqrt(c.m * c.m) + Math.sqrt(c.n * c.n);
return new Complex((m * c.m + n * c.n) / d, Math.round((m * c.n - n * c.m) / d));
}
public double getM() { return m;}
public double getN() { return n;}
public String toString() {
String rtr_str = "";
if (n > 0)
rtr_str = "(" + m + "+" + n + "i" + ")";
if (n == 0)
rtr_str = "(" + m + ")";
if (n < 0)
rtr_str = "(" + m + n + "i" + ")";
return rtr_str;
}
}