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

来源:互联网 发布:淘宝秒杀器有用吗 编辑:程序博客网 时间:2024/06/07 09:51


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. */@Overridepublic 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);}@Overridepublic void onAccuracyChanged(Sensor arg0, int arg1) {// TODO Auto-generated method stub// Do nothing}/** * On sensor changed. */@Overridepublic void onSensorChanged(SensorEvent event) {// Low Pass Filterfloat 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 filterif (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() */@Overrideprotected 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 * ) */@Overridepublic 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) */@Overrideprotected 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];}}



 

原创粉丝点击