ExponentialWelfordIntervalForecaster implements IntervalForecaster { @Override public IntervalForecast forecast(MetricData metricData, double pointForecast) { val observed = metricData.getValue(); val residual = observed - pointForecast; val incr = params.getAlpha() * residual; this.variance = (1.0 - params.getAlpha()) * (this.variance + residual * incr); val stdev = Math.sqrt(variance); val weakWidth = params.getWeakSigmas() * stdev; val strongWidth = params.getStrongSigmas() * stdev; return new IntervalForecast( pointForecast + strongWidth, pointForecast + weakWidth, pointForecast - weakWidth, pointForecast - strongWidth); } ExponentialWelfordIntervalForecaster();  ExponentialWelfordIntervalForecaster(ExponentialWelfordIntervalForecasterParams params); @Override IntervalForecast forecast(MetricData metricData, double pointForecast);  }
@Test public void testForecast() { val metricDef = TestObjectMother.metricDefinition(); val secondBase = Instant.now().getEpochSecond(); var secondOffset = 0; for (val testRow : testData) { val metricData = new MetricData(metricDef, testRow.getObservation(), secondBase + secondOffset); val actual = forecasterUnderTest.forecast(metricData, testRow.getPointForecast()); assertEquals(testRow.getUpperStrong(), actual.getUpperStrong(), TOLERANCE); assertEquals(testRow.getUpperWeak(), actual.getUpperWeak(), TOLERANCE); assertEquals(testRow.getLowerWeak(), actual.getLowerWeak(), TOLERANCE); assertEquals(testRow.getLowerStrong(), actual.getLowerStrong(), TOLERANCE); } }