package org.altbeacon.beacon.service; import android.os.SystemClock; import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo.Scope; import org.altbeacon.beacon.logging.LogManager; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; /** * Calculate a RSSI value on base of an arbitrary list of measured RSSI values * The list is clipped by a certain length at start and end and the average * is calculate by simple arithmetic average */ public class RunningAverageRssiFilter implements RssiFilter { private static final String TAG = "RunningAverageRssiFilter"; public static final long DEFAULT_SAMPLE_EXPIRATION_MILLISECONDS = 20000; /* 20 seconds */ private static long sampleExpirationMilliseconds = DEFAULT_SAMPLE_EXPIRATION_MILLISECONDS; private ArrayList<Measurement> mMeasurements = new ArrayList<Measurement>(); @Override public void addMeasurement(Integer rssi) { Measurement measurement = new Measurement(); measurement.rssi = rssi; measurement.timestamp = SystemClock.elapsedRealtime(); mMeasurements.add(measurement); } @Override public boolean noMeasurementsAvailable() { return mMeasurements.size() == 0; } @Override public int getMeasurementCount() { return mMeasurements.size(); } @Override public double calculateRssi() { refreshMeasurements(); int size = mMeasurements.size(); int startIndex = 0; int endIndex = size -1; if (size > 2) { startIndex = size/10+1; endIndex = size-size/10-2; } double sum = 0; for (int i = startIndex; i <= endIndex; i++) { sum += mMeasurements.get(i).rssi; } double runningAverage = sum/(endIndex-startIndex+1); LogManager.d(TAG, "Running average mRssi based on %s measurements: %s", size, runningAverage); return runningAverage; } private synchronized void refreshMeasurements() { ArrayList<Measurement> newMeasurements = new ArrayList<Measurement>(); Iterator<Measurement> iterator = mMeasurements.iterator(); while (iterator.hasNext()) { Measurement measurement = iterator.next(); if (SystemClock.elapsedRealtime() - measurement.timestamp < sampleExpirationMilliseconds ) { newMeasurements.add(measurement); } } mMeasurements = newMeasurements; Collections.sort(mMeasurements); } private class Measurement implements Comparable<Measurement> { Integer rssi; long timestamp; @Override public int compareTo(Measurement arg0) { return rssi.compareTo(arg0.rssi); } } public static void setSampleExpirationMilliseconds(long newSampleExpirationMilliseconds) { sampleExpirationMilliseconds = newSampleExpirationMilliseconds; } @RestrictTo(Scope.TESTS) static long getSampleExpirationMilliseconds() { return sampleExpirationMilliseconds; } }