垂直方向度 - Android

时间:2016-05-02 02:17:26

标签: android android-orientation

任何人都知道如何在Android中获得平滑的垂直方向度?

我已经尝试过OrientationEventListener,如下所示,但它非常嘈杂。已经尝试了所有费率,正常,延迟,游戏和最快,都显示相同的结果。

myOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {

    @Override
    public void onOrientationChanged(int arg0) {
         orientaion = arg0;

       Log.i("orientaion", "orientaion:" + orientaion);

    }
};

2 个答案:

答案 0 :(得分:1)

因此,有两件事情会影响您的需求。

  1. 传感器延迟。 Android提供四种不同的传感器延迟模式: SENSOR_DELAY_UI SENSOR_DELAY_NORMAL SENSOR_DELAY_GAME SENSOR_DELAY_FASTEST ,其中 SENSOR_DELAY_UI 两个数据点之间的间隔时间最长, SENSOR_DELAY_FASTEST 最短。间隔越短,数据采样率越高(每秒采样数)。较高的采样率可为您提供更多“响应”数据,但噪声更大,而较低的采样率可为您提供更多“滞后”数据,但更加流畅。

  2. 噪音过滤。考虑到上述情况,您需要确定要采用的路线。您的应用程序需要快速响应吗?如果是,您可能想要选择更高的采样率。您的应用程序需要流畅的数据吗鉴于问题的背景,我想这显然是肯定的,这意味着你需要噪音过滤。对于传感器数据,噪声本质上是高频率的(噪声值随时间振荡非常快)。所以low pass filter (LPF)通常就足够了。

  3. 实施LPF的一种简单方法是exponential smoothing。要与您的代码集成:

    int orientation = <init value>;
    float update_rate = <value between 0 to 1>;
    myOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
        @Override
        public void onOrientationChanged(int arg0) {
            orientation = (int)(orientation * (1f - update_rate) + arg0 * update_rate);
            Log.i("orientation", "orientation:" + orientation);
        }
    };
    

    较大的 update_value 表示结果数据不太流畅,应该很直观:如果 update_value == 1f ,则会回退到原始代码。关于 update_value 的另一个注意事项是它取决于更新之间的时间间隔(与传感器延迟模式有关)。您可能可以调整此值以找到适合您的值,但如果您想确切知道它是如何工作的,请检查电子低通滤波器下的alpha value definition - &gt;离散时间的实现。

答案 1 :(得分:0)

我遇到了类似的问题,在我的设备上显示出人为的视野。低通滤波器(LPF)解决了这个问题。

然而,您需要考虑何时使用度数角度并盲目地应用LPF,当设备处于纵向模式并从左转到骑行或相反时,结果是错误的。原因是359和0度之间的转换。因此,我建议将度数转换为弧度,并将LPF应用于方向角的sin和cos值。

此外,我建议对LPF使用动态alpha或更新速率。 alpha的静态值可能在您的设备上完美,但在其他任何设备上都不是。

以下类过滤基于弧度并使用动态alpha,如上所述:

import static java.lang.Math.*;

Filter {
    private static final float TIME_CONSTANT = .297f;
    private static final float NANOS = 1000000000.0f;
    private static final int MAX = 360;

    private double alpha;
    private float timestamp;
    private float timestampOld;

    private int count;

    private int values[];

    Filter() {
        timestamp = System.nanoTime();
        timestampOld = System.nanoTime();
        values = new int[0];
    }

    int filter(int input) {
        //there is no need to filter if we have only one
        if(values.length == 0) {
            values = new int[] {0, input};
           return input;
        }

        //filter based on last element from array and input
        int filtered = filter(values[1], input);
        //new array based on previous result and filter
        values = new int[] {values[1], filtered};
        return filtered;
    }

    private int filter(int previous, int current) {
        calculateAlpha();
        //convert to radians
        double radPrev = toRadians(previous);
        double radCurrent = toRadians(current);
        //filter based on sin & cos
        double sumSin = filter(sin(radPrev), sin(radCurrent));
        double sumCos = filter(cos(radPrev), cos(radCurrent));
        //calculate result angle
        double radRes = atan2(sumSin, sumCos);
        //convert radians to degree, round it and normalize (modulo of 360)
        long round = round(toDegrees(radRes));
        return (int) ((MAX + round) % MAX);
    }

    //dynamic alpha
    private void calculateAlpha() {
        timestamp = System.nanoTime();
        float diff = timestamp - timestampOld;
        double dt = 1 / (count / (diff / NANOS));
        count++;
        alpha = dt/(TIME_CONSTANT + dt);
    }

    private double filter(double previous, double current) {
        return (previous + alpha * (current - previous));
    }
}

如需进一步阅读,请参阅此discussion