// 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 }