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):
1. 1.0表示一点也不平滑
2. 这个值取0则将不会移动
另外有一个阀值 THRESHOLD_VAL,该参数我取的是80,如果加速度波动超过这个范围,我则简单的舍弃(实际可根据需要进行判断)他表示用户急剧的改变方向。
针对High Pass Filter,使用采集样本的方式进行,判断,我的样本数为30个,这个是一个经验值,
根据样本的值,取出中间值,作为高频下加速度的一个修正:
全部代码如下:
实现了两个小球,一个小球为白色他使用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]; } }
相关文章推荐
- Android Studio精彩案例(六)《使用一个Demo涵盖补间动画所有知识》
- Android Studio精彩案例(六)《使用一个Demo涵盖补间动画所有知识》
- Android:注册一个方向传感器的回调,能够让app常驻内存不被杀死
- Android笔记 动画之tween(补间)动画demo
- 一个完整的Android ListView+网络接口读取+JSON处理的Demo
- 求一个android打开各种类型文件的demo
- Android方向传感器简单实用
- android之隐示意图--在一个 <intent-filter>意图中用两个action启动这个activity
- Android动画之补间动画(二)
- Android动画(一):View动画(补间动画)
- 一个Demo学完Android中所有的服务
- Android 百度地图 SDK v3.0.0 (二) 定位与结合方向传感器
- Android动画实现多个ImageView绕着一个ImageVIew转圈
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- Android动画机制(1):帧动画、补间动画详解及实战演练
- Android动画--逐帧动画和补间动画简单介绍和基本用法(一)
- Android 方向传感器
- Android 学习之补间(Tween)动画
- 【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)
- Android-传感器开发-方向判断