CyclicSubSeriesSmoother { public void smoothSeasonal(double[] rawData, double[] smoothedData, double[] weights) { extractRawSubSeriesAndWeights(rawData, weights); computeSmoothedSubSeries(weights != null); reconstructExtendedDataFromSubSeries(smoothedData); } CyclicSubSeriesSmoother(int width, int degree, int jump,
	                        int dataLength, int periodicity,
	                        int numPeriodsToExtrapolateBackward, int numPeriodsToExtrapolateForward); void smoothSeasonal(double[] rawData, double[] smoothedData, double[] weights);  }
@Test public void TrendingSinusoidExtrapolationTest() { final int period = 24; double[] data = new double[2 * period]; final double dx = 2 * PI / period; for (int i = 0; i < data.length; ++i) { final int amplitude = 10 - i / period; data[i] = amplitude * Math.sin(i * dx); } double[] extendedData = new double[4 * period]; Builder builder = new Builder(); builder.setWidth(7); CyclicSubSeriesSmoother sssmoother = builder.setDataLength(data.length).setPeriodicity(period) .extrapolateForwardAndBack(1).build(); sssmoother.smoothSeasonal(data, extendedData, null); for (int i = 0; i < extendedData.length; ++i) { final int amplitude = 11 - i / period; final double value = amplitude * Math.sin(i * dx); assertEquals(String.format("test point %d", i), value, extendedData[i], 1.0e-11); } }
@Test public void shouldExtrapolateFourPeriodsForwards() { final int period = 24; double[] data = new double[2 * period]; final double dx = 2 * PI / period; for (int i = 0; i < data.length; ++i) { final int amplitude = 10 - i / period; data[i] = amplitude * Math.sin(i * dx); } double[] extendedData = new double[6 * period]; Builder builder = new Builder(); builder = builder.setWidth(7); builder = builder.extrapolateForwardOnly(4); CyclicSubSeriesSmoother sssmoother = builder.setDataLength(data.length).setPeriodicity(period).build(); sssmoother.smoothSeasonal(data, extendedData, null); for (int i = 0; i < extendedData.length; ++i) { final int amplitude = 10 - i / period; final double value = amplitude * Math.sin(i * dx); assertEquals(String.format("test point %d", i), value, extendedData[i], 1.0e-11); } }
@Test public void shouldExtrapolateTwoPeriodsBackwardAndTwoPeriodsForward() { final int period = 24; double[] data = new double[2 * period]; final double dx = 2 * PI / period; for (int i = 0; i < data.length; ++i) { final int amplitude = 10 - i / period; data[i] = amplitude * Math.sin(i * dx); } double[] extendedData = new double[6 * period]; Builder builder = new Builder(); builder = builder.setWidth(7); builder = builder.setNumPeriodsForward(2).setNumPeriodsBackward(2); CyclicSubSeriesSmoother sssmoother = builder.setDataLength(data.length).setPeriodicity(period).build(); sssmoother.smoothSeasonal(data, extendedData, null); for (int i = 0; i < extendedData.length; ++i) { final int amplitude = 12 - i / period; final double value = amplitude * Math.sin(i * dx); assertEquals(String.format("test point %d", i), value, extendedData[i], 1.0e-11); } }