Example #1
0
// Interpolate takes a counter value sampled at variable intervals and aligns each value with a <duration> ms boundary.
// The initial value is not output unless it appears exactly on a ms boundary.
// Runs of two or more missing values will be filled by NaN
func Interpolate(duration uint64, input *oproto.ValueStream) *oproto.ValueStream {
	output := &oproto.ValueStream{}
	var previousValue *oproto.Value
	var timestamp uint64
	for _, v := range input.Value {
		if previousValue == nil {
			if v.Timestamp%duration == 0 {
				// Value is exactly on a timestamp
				output.Value = append(output.Value, v)
				previousValue = v
				timestamp = v.Timestamp + duration
			} else {
				previousValue = v
				previousValue.Timestamp = v.Timestamp / duration * duration
				timestamp = previousValue.Timestamp + duration
			}
			continue
		}
		if v.Timestamp >= timestamp {
			// Fill in any missing values before this one
			rate := float64((v.DoubleValue - previousValue.DoubleValue))
			for ; timestamp <= v.Timestamp; timestamp += duration {
				pct := float64(timestamp-previousValue.Timestamp) / float64(v.Timestamp-previousValue.Timestamp)
				newValue := previousValue.DoubleValue + (rate * pct)
				output.Value = append(output.Value, &oproto.Value{
					Timestamp:   timestamp,
					DoubleValue: newValue,
				})
			}
			if previousValue.Timestamp < v.Timestamp {
				if v.Timestamp%duration == 0 {
					// Value is exactly on a timestamp
					output.Value = append(output.Value, v)
					previousValue = v
					timestamp += duration
				} else {
					previousValue = v
				}
			}
		}
	}
	return output
}