收集机器人传感器为特定的期间并计算平均 [英] Collecting android sensor for a specific period and calculating the average

查看:136
本文介绍了收集机器人传感器为特定的期间并计算平均的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写在一个特定的时间内收集加速传感器值,并返回传感器读数该期间的平均的方法。

I am trying to write a method that collects accelerometer sensor values over a specific time period and returns the average of the sensor readings for that period.

它应该是,一旦它被称为会阻塞调用线程的某个时候,然后将返回传感器平均同步即阻断法

It should be a synchronous i.e. blocking method that once it is called will block the calling thread for sometime and then will return the sensor average

我做检查以下类似的问题,但似乎并没有对我的情况下,适当的工作方案:

I did check the below similar questions but does not seem to have a proper working solution for my case:

<一个href="http://stackoverflow.com/questions/3286815/sensoreventlistener-in-separate-thread">SensorEventListener在单独的线程

<一个href="http://stackoverflow.com/questions/19256929/android-how-to-run-your-sensor-service-thread-activity">Android - 如何运行你的传感器(服务,螺纹,活动)

Android的传感器和线

一种等待传感器数据方法

我也试过用执行人类似的这个问题,但不能让它的工作,因为我想要的。

I've also tried to use Executors similar to this question, but could not get it to work as I want.

下面是我的code骨架,其中该方法 sensorAverage 是一个阻塞方法,将计算出加速度传感器一般经过一段等于该暂停参数

Below is my code skeleton, where the method sensorAverage is a blocking method that will calculate the accelerometer sensor average over a period equals to the timeout parameter

Average average = new Average(); // Some class to calculate the mean

double sensorAverage(long timeout){
    Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
    sensorManager.registerListener(this, sensor,SensorManager.SENSOR_DELAY_NORMAL);

    // This does not work
    Thread.sleep(timeout);

    sensorManager.unregisterListener(this);

    return average.value();
}

public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
        double x2 = Math.pow(event.values[0], 2);
        double y2 = Math.pow(event.values[1], 2);
        double z2 = Math.pow(event.values[2], 2);
        average.add(Math.sqrt((x2 + y2 + z2)));
    }
}

修改: 我知道,我需要另一个线程,但我需要的的问题,运行一段特定时期的只是,到目前为止,我无法找到一个合适的工作方案。因为当我用另一个线程我得到的传感器的平均总 0

Edit: I am aware that I need another thread, but the problem that I need to run it for a specific period only and so far I cannot find a proper working solution. Because when I use another thread I get the sensor average always 0

推荐答案

我成功地实现一个解决方案,正是我想要做什么。

I managed to implement a solution which exactly does what I want.

这是为收集特定时期传感器数值并返回所有传感器读数的统计数据,即均值和方差。

A blocking method that collects sensor values for specific period and returns the statistics of all sensor readings i.e. mean and variance.

这是可以简单地存储所有传感器的值,然后计算出均值和方差;然而,你可能的情况下收集高频传感器在较长一段时间内的运行内存不足。

It is possible to simply store all the sensor's values and then calculate the mean and variance; however you might run out of memory in case of collecting high frequency sensor over extended period of time.

我找到了一个更好的解决方案来计算的均值和方差的实时数据流(即不带存储传感器值),使用下面的 RunningStat

I found a better solution to calculate the mean and variance for a stream of data in real-time (i.e. without storing the sensor values) using the below RunningStat class

示例code:

// Calculate statistics of accelerometer values over 300 ms (a blocking method)
RunningStat[] stats = SensorUtils.sensorStats(context, 
                                                  Sensor.TYPE_ACCELEROMETER, 300)
double xMean = stats[0].mean();
double xVar  = stats[0].variance();

满级code

public class SensorUtils {

// Collect sensors data for specific period and return statistics of 
// sensor values e.g. mean and variance for x, y and z-axis
public static RunningStat[] sensorStats(Context context, int sensorType,
        long timeout) throws Exception {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<RunningStat[]> future = executor.submit(new SensorTask(context,
            sensorType, timeout));

    RunningStat[] stats = future.get();
    return stats;

}

private static class SensorTask implements Callable<RunningStat[]> {
    private final Context context;
    private final long timeout;
    private final int sensorType;
    // We need a dedicated handler for the onSensorChanged
    HandlerThread handler = new HandlerThread("SensorHandlerThread");

    public SensorTask(Context context, int sensorType, long timeout) {
        this.context = context;
        this.timeout = timeout;
        this.sensorType = sensorType;
    }

    @Override
    public RunningStat[] call() throws Exception {
        final SensorCollector collector = new SensorCollector(context);
        handler.start();
        Thread sensorThread = new Thread() {
            public void run() {
                collector.start(sensorType,
                        new Handler(handler.getLooper()));
            };
        };
        sensorThread.start();
        Thread.sleep(timeout);
        return collector.finishWithResult();
    }
}

private static class SensorCollector implements SensorEventListener {
    protected Context context;
    protected RunningStat[] runningStat;
    protected SensorManager sensorManager;
    protected int sensorType;

    public SensorCollector(Context context) {
        this.context = context;
    }

    protected void start(int sensorType, Handler handle) {
        if (runningStat == null) {
            runningStat = new RunningStat[3];
            runningStat[0] = new RunningStat(3);
            runningStat[1] = new RunningStat(3);
            runningStat[2] = new RunningStat(3);
        } else {
            runningStat[0].clear();
            runningStat[1].clear();
            runningStat[2].clear();
        }
        this.sensorType = sensorType;
        sensorManager = (SensorManager) context
                .getSystemService(Context.SENSOR_SERVICE);
        Sensor sensor = sensorManager.getDefaultSensor(sensorType);
        sensorManager.registerListener(this, sensor,
                SensorManager.SENSOR_DELAY_NORMAL, handle);
    }

    public RunningStat[] finishWithResult() {
        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }
        return runningStat;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == sensorType) {
            runningStat[0].push(event.values[0]);
            runningStat[1].push(event.values[1]);
            runningStat[2].push(event.values[2]);
        }
    }
}

}

下面是 RunningStat code,这是一个非常方便的类来计算的均值和方差的数据流,而不存储数据本身(适合计算高频传感器的统计数据非常小的内存占用)

Here is the RunningStat code, which is a very handy class to calculate the mean and variance for stream of data without storing the data itself (perfect for calculating statistics of high frequency sensors with very small memory footprint)

//See Knuth TAOCP vol 2, 3rd edition, page 232
public class RunningStat {
private int n;
private double oldM, newM, oldS, newS;
private int precision = -1;

// An estimate for the t-value (can be read from the t-distribution table)
private static final double T_THRESHOLD = 1.68;

public RunningStat(int precision) {
    this.precision = precision;
}

public RunningStat() {
}

public void clear() {
    n = 0;
}

public void push(double x) {
    n++;


    if (n == 1) {
        oldM = newM = x;
        oldS = 0.0;
    } else {
        newM = oldM + (x - oldM) / n;
        newS = oldS + (x - oldM) * (x - newM);

        // set up for next iteration
        oldM = newM;
        oldS = newS;
    }
}

public int count() {
    return n;
}

public double mean() {
    double mean = (n > 0) ? newM : 0.0;
    if (precision > 0) {
        return round(mean, precision);
    }
    return mean;
}

// The upper bound of the mean confidence interval
public double meanUpper() {
    double mean = (n > 0) ? newM : 0.0;
    double stdError = stdDeviation() / Math.sqrt(n);
    double upperMean = mean + T_THRESHOLD * stdError;
    if (precision > 0) {
        return round((n > 0) ? upperMean : 0.0, precision);
    }
    return upperMean;
}

// The lower bound of the mean confidence interval
public double meanLower() {
    double mean = (n > 0) ? newM : 0.0;
    double stdError = stdDeviation() / Math.sqrt(n);
    double lowerMean = mean - T_THRESHOLD * stdError;
    if (precision > 0) {
        return round((n > 0) ? lowerMean : 0.0, precision);
    }
    return lowerMean;
}

public double variance() {
    if (precision > 0) {
        return round(((n > 1) ? newS / (n - 1) : 0.0), precision);
    }
    return ((n > 1) ? newS / (n - 1) : 0.0);
}

public double stdDeviation() {
    if (precision > 0) {
        return round(Math.sqrt(variance()), precision);
    }
    return Math.sqrt(variance());
}

public void setPrecision(int precision) {
    this.precision = precision;
}

    public static double round(double value, int precision) {
         BigDecimal num = new BigDecimal(value);
         num = num.round(new MathContext(precision, RoundingMode.HALF_UP));
         return num.doubleValue();
    }

// A small test case
public static void main(String[] args) {
    int n = 100;
    RunningStat runningStat = new RunningStat();
    double[] data = new double[n];
    double sum = 0.0;
    for (int i = 0; i < n; i++) {
        data[i] = i * i;
        sum += data[i];
        runningStat.push(data[i]);
        System.out.println(runningStat.mean() + " - "
                + runningStat.variance() + " - "
                + runningStat.stdDeviation());
    }

    double mean = sum / n;
    double sum2 = 0.0;

    for (int i = 0; i < n; i++) {
        sum2 = sum2 + (data[i] - mean) * (data[i] - mean);
    }

    double variance = sum2 / (n - 1);
    System.out.println("\n\n" + mean + " - " + variance + " - "
            + Math.sqrt(variance));
}
}

这篇关于收集机器人传感器为特定的期间并计算平均的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆