繁体   English   中英

垂直方向度-Android

[英]Vertical orientation degree - Android

有谁知道如何在Android中获得平滑的垂直方向度?

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

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

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

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

    }
};

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

  1. 传感器延迟 Android提供四种不同的传感器延迟模式:SENSOR_DELAY_UI,SENSOR_DELAY_NORMAL,SENSOR_DELAY_GAME,SENSOR_DELAY_FASTEST,其中SENSOR_DELAY_UI具有两个数据点之间的最长间隔和SENSOR_DELAY_FASTEST具有最短。 间隔越短,数据采样率(每秒采样数)越高。 较高的采样率可为您提供更多“响应”数据,但会带来更大的噪音,而较低的采样率可为您提供更多“延迟”数据,但更为平滑。

  2. 噪声过滤 考虑到以上几点,您需要确定要采取的路线。 您的应用程序需要快速响应吗? 如果是这样,您可能希望选择更高的采样率。 您的应用程序需要平滑的数据吗? 考虑到问题的上下文,我想这显然是肯定的,这意味着您需要进行噪声过滤。 对于传感器数据,噪声本质上多数是高频信号(噪声值会随时间快速振荡)。 因此, 低通滤波器(LPF)通常就足够了。

实现LPF的一种简单方法是指数平滑 要与您的代码集成:

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值定义

我在装置上显示人造视线时也遇到类似的问题。 低通滤波器(LPF)解决了此问题。

但是,您需要考虑以度为单位使用方向角并将LPF盲目地应用在其上时,当设备处于纵向模式并从左转为乘坐或相反时,结果将是错误的。 原因是在359度和0度之间转换。 因此,我建议将度数转换为弧度,并将LPF应用于方向角的正弦和余弦值。

此外,我建议对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));
    }
}

有关进一步的阅读,请参见此讨论

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM