@Override
    public double[] smoothDerivative(double[] input) {

        if (input.length < weights.length) {
            return averageDerivativeForVeryShortTrack(input);
        }

        double[] smoothed = new double[input.length];
        int halfWindowFloored = weights.length / 2; // we want to exclude the center point

        for (int i = halfWindowFloored; i < input.length - halfWindowFloored; i++) {
            for (int windowIndex = 0; windowIndex < smoothCoeff.length; windowIndex++) {
                smoothed[i] += derivCoeff[windowIndex] * input[i + windowIndex + offsetFromWindowCenter];
            }
            smoothed[i] = smoothed[i] / timeStep;
        }

        fillSmoothDerivativeLeftSide(smoothed, halfWindowFloored);
        fillSmoothDerivativeRightSide(smoothed, halfWindowFloored);

        return smoothed;
    }
@Test
    public void Derivative_FromShortTrack_ReturnAverageDerivative() {
        SavitzkyGolayFilter test = new SavitzkyGolayFilter(3.0); // note the time step

        double[] input = new double[]{10.0, 13.0, 16.0, 18.0, 21.0};
        double[] actual = test.smoothDerivative(input);

        assertThat(actual.length, equalTo(input.length));

        for (int i = 0; i < input.length; i++) {
            assertThat(actual[i], closeTo(0.9167, 1E-3));
        }
    }