/*
* Copyright (c) 2015 Spotify AB.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.spotify.heroic.generator.sine;
import com.google.common.collect.ImmutableList;
import com.spotify.heroic.common.DateRange;
import com.spotify.heroic.common.Duration;
import com.spotify.heroic.common.Series;
import com.spotify.heroic.generator.Generator;
import com.spotify.heroic.metric.MetricCollection;
import com.spotify.heroic.metric.Point;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Random;
public class SineGenerator implements Generator {
final Random random = new Random();
/**
* The magnitude (height) of the sine-wave.
*/
private final double magnitude;
/**
* How many milliseconds should be a full period (2 * PI).
*/
private final long period;
/**
* Frequency of data points in hertz.
*/
private final long step;
private final double jitter;
private final double offset;
@Inject
public SineGenerator(
@Named("magnitude") double magnitude, @Named("period") Duration period,
@Named("step") Duration step, @Named("jitter") double jitter, @Named("offset") double offset
) {
this.magnitude = magnitude;
this.period = period.toMilliseconds();
this.step = step.toMilliseconds();
this.jitter = jitter;
this.offset = offset;
}
@Override
public MetricCollection generate(
final Series series, final DateRange range
) {
// calculate a consistent drift depending on which series is being fetched.
double drift = Math.abs((double) series.hashCode() / (double) Integer.MAX_VALUE) * period;
final ImmutableList.Builder<Point> data = ImmutableList.builder();
final DateRange rounded = range.rounded(1000);
final double fixed = random.nextDouble() * this.offset;
for (long time = rounded.getStart(); time < rounded.getEnd(); time += step) {
double offset = ((double) (time % period)) / (double) period;
final double jitter;
if (this.jitter != 0D) {
jitter = random.nextDouble() * this.jitter;
} else {
jitter = 0D;
}
double value = fixed + jitter + Math.sin(Math.PI * 2 * (offset + drift)) * magnitude;
data.add(new Point(time, value));
}
return MetricCollection.points(data.build());
}
}