您的位置:首页 > 移动开发 > Android开发

Android 方向传感器 + Low Pass Filter +补间动画的一个Demo

2012-03-06 17:37 357 查看
Android 方向传感器 Low Pass Filter 和 High Pass Filter的实现

 

实现了两个小球,一个小球为白色他使用Low Pass Filter 过滤掉高频,一个小球为蓝色,过滤掉低频,根据加速度方向移动。

在摇晃手机的时候,可以看到两个小球的运动,白色的小球运动比较平滑,蓝色的小球运动比较跳跃,在针对开发的问题,High Pass Filter 可以侦测到用户摇晃手机。Low Pass Filter 可以侦测用户往哪个方向有加速度。

 

针对Low Pass Filter,有一个参数为 SMOOTHING,该参数的范围从(1.0-0):

 

// Low Pass Filter key parameter this value should be from 0 to 1,
// when 1 means the least smoothness and 0 means no move at all, my
// value is 0.3f.
private static float SMOOTHING = 0.3f;
private static float THRESHOLD_VAL = 80f;


1.  1.0表示一点也不平滑

2.  这个值取0则将不会移动

另外有一个阀值 THRESHOLD_VAL,该参数我取的是80,如果加速度波动超过这个范围,我则简单的舍弃(实际可根据需要进行判断)他表示用户急剧的改变方向。

 

针对High Pass Filter,使用采集样本的方式进行,判断,我的样本数为30个,这个是一个经验值,

 // Sample count.
 private static final int ELEMENT_COUNT = 30;

 

根据样本的值,取出中间值,作为高频下加速度的一个修正:

private float getMedian(float[] values) {

float[] tmp = values.clone();

Arrays.sort(tmp);

int len = tmp.length;

int first = 0;
for (int i = 0; i < tmp.length; i++) {
first = i;
if (tmp[i] != BLANK) {
break;
}
}
return tmp[(len - first) / 2 + first];
}


 

 全部代码如下:

package com.hubert.demo;

import java.util.Arrays;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;

public class SensorDemoActivity extends Activity implements
SensorEventListener {

// Log tag.
private static final String TAG = "SensorDemoActivity";

// Sample count.
private static final int ELEMENT_COUNT = 30;

// X coordinate and Y coordinate.
private float CURRENT_WHITE_CY = 500;
private float CURRENT_WHITE_CX = 200;
private float CURRENT_BLUE_CY = 500;
private float CURRENT_BLUE_CX = 300;
private static int INITIAL_R = 50;

// Sample data.
private float[] samplingX = new float[ELEMENT_COUNT];
private float[] samplingY = new float[ELEMENT_COUNT];
private float[] samplingZ = new float[ELEMENT_COUNT];

private static final float BLANK = -9999f;

// Sample cursor.
private int position;

// Low Pass Filter key parameter this value should be from 0 to 1,
// when 1 means the least smoothness and 0 means no move at all, my
// value is 0.3f.
private static float SMOOTHING = 0.3f;
private static float THRESHOLD_VAL = 80f;
private float oldX = 0f;
private float oldY = 0f;

/**
* Sensor manager
*/
private SensorManager mSensorManager;
private Sensor mSensor;
private Handler mHandler;
private Animation mAnimation;
private CircleView cv;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cv = new CircleView(this);
setContentView(cv);
init();

}

/**
* Initial variables.
*/
private void init() {
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
// Normal accuracy.
mSensorManager.registerListener(this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);

Arrays.fill(samplingX, BLANK);
Arrays.fill(samplingY, BLANK);
Arrays.fill(samplingZ, BLANK);
}

@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
// Do nothing
}

/**
* On sensor changed.
*/
@Override
public void onSensorChanged(SensorEvent event) {

// Low Pass Filter
float x = event.values[SensorManager.DATA_X];
float y = event.values[SensorManager.DATA_Y];
float z = event.values[SensorManager.DATA_Z];
// If the change greater than the threshold value assign it to the old
// value immediately.
setWhiteBall(lowPassFilter(x, oldX), lowPassFilter(y, oldY));

// High Pass Filter.
float[] values = highPassFilter(event.values);
setBlueBall(values[0],	values[1]);

cv.invalidate();
}

/**
*
* @param inputVal
* @return
*/
public float[] highPassFilter(float inputVal[]){
// High Pass filter
if (position == ELEMENT_COUNT - 1) {
position = 0;
} else {
position++;
}
float x = inputVal[0];
float y = inputVal[1];
float z = inputVal[2];

samplingX[position] = x;
samplingY[position] = y;
samplingZ[position] = z;

float valueX = x - getMedian(samplingX);
float valueY = y - getMedian(samplingY);
float valueZ = z - getMedian(samplingZ);

return new float[]{valueX, valueY, valueZ};
}

/**
* Low Pass Filter
* @param inputVal
* @param outputVal
* @return
*/
public float lowPassFilter(float inputVal, float outputVal) {
if (Math.abs(inputVal - outputVal) < THRESHOLD_VAL) {
outputVal = outputVal + SMOOTHING * (inputVal - outputVal);
return outputVal;
}
return outputVal;
}

/*
* (non-Javadoc)
*
* @see android.app.Activity#onDestroy()
*/
@Override
protected void onDestroy() {

if (mSensorManager != null) {
mSensorManager.unregisterListener(this, mSensor);
}

super.onDestroy();
}

/**
* Move the ball according to x-axis and y-axis.
*
* @param x
* @param y
*/
public void setWhiteBall(float x, float y) {
Log.d(TAG, "x-axis: " + x + "y-axis: " + y);
// cv.clearAnimation();
// mAnimation = new TranslateAnimation(CURRENT_CX, CURRENT_CX + x,
// CURRENT_CY, CURRENT_CY + y);
// mAnimation.setDuration(500);
// cv.startAnimation(mAnimation);
CURRENT_WHITE_CX -= x * 50f;
CURRENT_WHITE_CY += y * 50f;

}

private void setBlueBall(float x, float y) {
CURRENT_BLUE_CX -= x * 50f;
CURRENT_BLUE_CY += y * 50f;
}

/*
* (non-Javadoc)
*
* @see
* android.app.Activity#onConfigurationChanged(android.content.res.Configuration
* )
*/
@Override
public void onConfigurationChanged(Configuration newConfig) {

}

class CircleView extends View {

private Context mContext;

public CircleView(Context context) {
super(context);
mContext = context;
}

/*
* (non-Javadoc)
*
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
canvas.drawCircle(CURRENT_WHITE_CX, CURRENT_WHITE_CY, INITIAL_R, mPaint);

mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true);
canvas.drawCircle(CURRENT_BLUE_CX, CURRENT_BLUE_CY, INITIAL_R, mPaint);
super.onDraw(canvas);
}

}

private float getMedian(float[] values) {

float[] tmp = values.clone();

Arrays.sort(tmp);

int len = tmp.length;

int first = 0;
for (int i = 0; i < tmp.length; i++) {
first = i;
if (tmp[i] != BLANK) {
break;
}
}
return tmp[(len - first) / 2 + first];
}

}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息