@Override public Double apply(SensorEvent<T> event) { long eventTime = event.getTimestamp(); if (event.getValue()==null) { return null; } values.addLast(event.getValue()); timestamps.addLast(eventTime); if (eventTime>0) { ConfidenceQualifiedNumber average = getAverage(eventTime, 0); if (average.confidence > getConfig(CONFIDENCE_REQUIRED_TO_PUBLISH)) { // without confidence, we might publish wildly varying estimates, // causing spurious resizes, so allow it to be configured, and // by default require a high value // TODO would be nice to include timestamp, etc return average.value; } } return null; } };
@Override public void setEntity(EntityLocal entity) { super.setEntity(entity); // Check that sourceSensor has been set (rather than triggerSensors) getRequiredConfig(SOURCE_SENSOR); }
@Test public void testSingleValueTimeAverage() { averager.onEvent(newDeltaSensorEvent(10, 1000)); average = averager.getAverage(1000, 0); assertEquals(average.confidence, 0d); }
@Test public void testDefaultAverageWhenEmpty() { ConfidenceQualifiedNumber average = averager.getAverage(0, 0); assertEquals(average.value, 0d); assertEquals(average.confidence, 0.0d); }
pruneValues(now); Duration timePeriod = getConfig(WINDOW_DURATION); long windowStart = Math.max(now-timePeriod.toMilliseconds(), firstTimestamp); long windowEnd = Math.max(now-timePeriod.toMilliseconds(), lastTimestamp);
/** * Discards out-of-date values, but keeps at least one value. */ private void pruneValues(long now) { // keep one value from before the period, so that we can tell the window's start time Duration timePeriod = getConfig(WINDOW_DURATION); while(timestamps.size() > 1 && timestamps.get(1) < (now - timePeriod.toMilliseconds())) { timestamps.removeFirst(); values.removeFirst(); } } }
@Test public void testTwoValueAverageForPeriod() { averager.onEvent(newDeltaSensorEvent(10, 1000)); averager.onEvent(newDeltaSensorEvent(10, 2000)); average = averager.getAverage(2000, 0); assertEquals(average.value, 10 /1d); assertEquals(average.confidence, 1d); }
@Test public void testWeightedAverage() { averager.onEvent(newDeltaSensorEvent(10, 1000)); averager.onEvent(newDeltaSensorEvent(20, 1100)); averager.onEvent(newDeltaSensorEvent(30, 1300)); averager.onEvent(newDeltaSensorEvent(40, 1600)); averager.onEvent(newDeltaSensorEvent(50, 2000)); average = averager.getAverage(2000, 0); assertEquals(average.value, (20*0.1d)+(30*0.2d)+(40*0.3d)+(50*0.4d)); assertEquals(average.confidence, 1d); }
@Test public void testMonospacedAverage() { averager.onEvent(newDeltaSensorEvent(10, 1000)); averager.onEvent(newDeltaSensorEvent(20, 1250)); averager.onEvent(newDeltaSensorEvent(30, 1500)); averager.onEvent(newDeltaSensorEvent(40, 1750)); averager.onEvent(newDeltaSensorEvent(50, 2000)); average = averager.getAverage(2000, 0); assertEquals(average.value, (20+30+40+50)/4d); assertEquals(average.confidence, 1d); }
@Test public void testNoRecentValuesAverage() { averager.onEvent(newDeltaSensorEvent(10, 0)); average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0); assertEquals(average.value, 10d); assertEquals(average.confidence, 0d); }
@Test public void testNoRecentValuesUsesLastForAverage() { averager.onEvent(newDeltaSensorEvent(10, 0)); averager.onEvent(newDeltaSensorEvent(20, 10)); average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0); assertEquals(average.value, 20d); assertEquals(average.confidence, 0d); }
@Test public void testConfidenceDecay() { averager.onEvent(newDeltaSensorEvent(10, 1000)); averager.onEvent(newDeltaSensorEvent(20, 1250)); averager.onEvent(newDeltaSensorEvent(30, 1500)); averager.onEvent(newDeltaSensorEvent(40, 1750)); averager.onEvent(newDeltaSensorEvent(50, 2000)); average = averager.getAverage(2250, 0); assertEquals(average.value, (30+40+50)/3d); assertEquals(average.confidence, 0.75d); average = averager.getAverage(2500, 0); assertEquals(average.value, (40+50)/2d); assertEquals(average.confidence, 0.5d); average = averager.getAverage(2750, 0); assertEquals(average.value, 50d); assertEquals(average.confidence, 0.25d); average = averager.getAverage(3000, 0); assertEquals(average.value, 50d); assertEquals(average.confidence, 0d); }