/**
* Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT
* All rights reserved. Use is subject to license terms. See LICENSE.TXT
*/
package org.diirt.datasource.sim;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.diirt.vtype.VDouble;
import static org.diirt.vtype.ValueFactory.*;
import org.diirt.util.time.TimeInterval;
/**
* Base class for all simulated functions. It provide constant rate data generation
* facilities.
*
* @author carcassi
*/
abstract class SimFunction<T> extends Simulation<T> {
private static final Logger log = Logger.getLogger(SimFunction.class.getName());
private Duration timeBetweenSamples;
/**
* Creates a new simulation function.
*
* @param secondsBeetwenSamples seconds between each samples
* @param classToken simulated class
*/
SimFunction(double secondsBeetwenSamples, Class<T> classToken) {
// The timer only accepts interval up to the millisecond.
// For intervals shorter than that, we calculate the extra samples
// we need to generate within each time execution.
super(Duration.ofMillis(Math.max((int) (secondsBeetwenSamples * 1000) / 2, 1)), classToken);
if (secondsBeetwenSamples <= 0.0) {
throw new IllegalArgumentException("Interval must be greater than zero (was " + secondsBeetwenSamples + ")");
}
if (secondsBeetwenSamples < 0.000001) {
throw new IllegalArgumentException("Interval must be greater than 0.000001 - no faster than 100KHz (was " + secondsBeetwenSamples + ")");
}
timeBetweenSamples = Duration.ofNanos((long) (secondsBeetwenSamples * 1000000000));
}
/**
* Calculates and returns the next value.
*
* @return the next value
*/
abstract T nextValue();
/**
* Computes all the new values in the given time slice by calling nextValue()
* appropriately.
*
* @param interval the interval where the data should be generated
* @return the new values
*/
@Override
List<T> createValues(TimeInterval interval) {
List<T> values = new ArrayList<T>();
Instant newTime;
if (lastTime != null) {
newTime = lastTime.plus(timeBetweenSamples);
} else {
newTime = Instant.now();
}
while (interval.contains(newTime)) {
lastTime = newTime;
values.add(nextValue());
newTime = lastTime.plus(timeBetweenSamples);
}
return values;
}
/**
* Creating new value based on the metadata from the old value.
*
* @param value new numeric value
* @param oldValue old VDouble
* @return new VDouble
*/
VDouble newValue(double value, VDouble oldValue) {
if (lastTime == null)
lastTime = Instant.now();
return newVDouble(value, timeNow(), oldValue);
}
/**
* Returns the time between each sample.
*
* @return a time duration
*/
public Duration getTimeBetweenSamples() {
return timeBetweenSamples;
}
}