我正在尝试编写一种方法,该方法在特定时间段内收集加速度计传感器值,并返回该时间段内传感器读数的平均值.
它应该是一个同步即阻塞方法,一旦被调用它将阻塞调用线程一段时间然后将返回传感器平均值
我确实检查了下面类似的问题,但似乎没有适合我的案例的正确解决方案:
我也试过使用类似于this question的Executors,但是无法按照我的意愿使用它.
下面是我的代码框架,其中方法sensorAverage是一种阻塞方法,它将计算加速度计传感器在一段时间内的平均值等于超时参数
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
解决方法:
我设法实现了一个完全符合我想要的解决方案.
一种阻塞方法,用于收集特定时间段的传感器值并返回所有传感器读数的统计数据,即均值和方差.
可以简单地存储所有传感器的值,然后计算均值和方差;但是,如果在长时间内收集高频传感器,可能会耗尽内存.
我找到了一个更好的解决方案,使用下面的RunningStat类实时计算数据流的均值和方差(即不存储传感器值)
示例代码:
// 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();
全班代码:
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 future = executor.submit(new SensorTask(context,
sensorType, timeout));
RunningStat[] stats = future.get();
return stats;
}
private static class SensorTask implements Callable {
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代码,它是一个非常方便的类,用于计算数据流的均值和方差而不存储数据本身(非常适合计算内存占用非常小的高频传感器的统计数据)
//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));
}
}
标签:java,android,multithreading,android-sensors
来源: https://codeday.me/bug/20190517/1120173.html