|
| 1 | +package net.laprun.sustainability.power.measure; |
| 2 | + |
| 3 | +import java.time.Duration; |
| 4 | +import java.util.Arrays; |
| 5 | + |
| 6 | +public enum Cursor { |
| 7 | + ; |
| 8 | + |
| 9 | + public static PartialCursor cursorOver(long[] timestamps, long timestamp, Duration duration, long initialOffset, |
| 10 | + long averagePeriodHint) { |
| 11 | + // adjusted timestamp for modding |
| 12 | + System.out.println(Arrays.toString(timestamps)); |
| 13 | + System.out.println("timestamp = " + timestamp); |
| 14 | + final var timestampForDiv = timestamp - initialOffset; |
| 15 | + final var durationAsMs = duration.toMillis(); |
| 16 | + System.out.println("durationAsMs = " + durationAsMs); |
| 17 | + |
| 18 | + // cannot find an interval for a timestamp that is before the recording started |
| 19 | + if (timestampForDiv < 0) { |
| 20 | + return PartialCursor.empty; |
| 21 | + } |
| 22 | + |
| 23 | + if (timestamps.length < 2) { |
| 24 | + // if we don't have a sample period, use the full measure |
| 25 | + double ratio = 1.0; |
| 26 | + if (averagePeriodHint > 0) { |
| 27 | + ratio = (double) durationAsMs / averagePeriodHint; |
| 28 | + } |
| 29 | + return new PartialCursor(0, 0, ratio, ratio); |
| 30 | + } |
| 31 | + |
| 32 | + // estimate sample period based on 2 samples interval |
| 33 | + if (averagePeriodHint <= 0) { |
| 34 | + averagePeriodHint = timestamps[1] - timestamps[0]; |
| 35 | + } |
| 36 | + |
| 37 | + // first, find potential first sample based on timestamp |
| 38 | + int startIndex = (int) Math.floorDiv(timestampForDiv, averagePeriodHint); |
| 39 | + System.out.println("startIndex = " + startIndex); |
| 40 | + int endIndex = (int) Math.floorDiv(timestampForDiv + durationAsMs, averagePeriodHint); |
| 41 | + System.out.println("endIndex = " + endIndex); |
| 42 | + |
| 43 | + if (startIndex == endIndex) { |
| 44 | + final long previousTimestamp = startIndex == 0 ? initialOffset : timestamps[startIndex - 1]; |
| 45 | + final long slotDuration = timestamps[startIndex] - previousTimestamp; |
| 46 | + var ratio = (double) durationAsMs / slotDuration; |
| 47 | + return new PartialCursor(startIndex, endIndex, ratio, -1); |
| 48 | + } |
| 49 | + |
| 50 | + // get the index with the timestamp right after the one we're looking for since what we're interested in is the portion of the measure that gets recorded after the timestamp we want |
| 51 | + long afterTimestamp = timestamps[startIndex]; |
| 52 | + final long startOffset = afterTimestamp - timestamp; |
| 53 | + double startRatio = 0; |
| 54 | + if (startOffset > 0) { |
| 55 | + startRatio = (double) startOffset / (afterTimestamp - timestamps[startIndex - 1]); |
| 56 | + } |
| 57 | + |
| 58 | + // look for the index that records the first timestamp that's after the one we're looking for added to the duration |
| 59 | + afterTimestamp = timestamps[endIndex]; |
| 60 | + final long slotDuration = afterTimestamp - timestamps[endIndex - 1]; |
| 61 | + final long endOffset = slotDuration - (afterTimestamp - timestamp - durationAsMs); |
| 62 | + double endRatio = 0; |
| 63 | + if (endOffset > 0) { |
| 64 | + endRatio = (double) endOffset / slotDuration; |
| 65 | + } |
| 66 | + |
| 67 | + return new PartialCursor(startIndex, endIndex, startRatio, endRatio); |
| 68 | + } |
| 69 | + |
| 70 | + public record PartialCursor(int startIndex, int endIndex, double firstMeasureRatio, double lastMeasureRatio) { |
| 71 | + |
| 72 | + public static final PartialCursor empty = new PartialCursor(-1, -1, 0.0, 0.0); |
| 73 | + |
| 74 | + public double sum(double[] values) { |
| 75 | + if (values == null || values.length == 0 || this == empty || values.length < startIndex + endIndex) { |
| 76 | + return 0.0; |
| 77 | + } |
| 78 | + |
| 79 | + if (startIndex == endIndex) { |
| 80 | + return values[startIndex] * firstMeasureRatio; |
| 81 | + } |
| 82 | + |
| 83 | + double sum = values[startIndex] * firstMeasureRatio; |
| 84 | + for (int i = startIndex + 1; i < endIndex; i++) { |
| 85 | + sum += values[i]; |
| 86 | + } |
| 87 | + sum += values[endIndex] * lastMeasureRatio; |
| 88 | + |
| 89 | + return sum; |
| 90 | + } |
| 91 | + |
| 92 | + public double[] viewOf(double[] values) { |
| 93 | + if (values == null || values.length == 0 || this == empty || values.length < startIndex + endIndex) { |
| 94 | + return new double[0]; |
| 95 | + } |
| 96 | + |
| 97 | + if (startIndex == endIndex) { |
| 98 | + return new double[] { values[startIndex] * firstMeasureRatio }; |
| 99 | + } |
| 100 | + |
| 101 | + final int len = endIndex - startIndex + 1; |
| 102 | + final double[] view = new double[len]; |
| 103 | + view[0] = values[startIndex] * firstMeasureRatio; |
| 104 | + System.arraycopy(values, startIndex + 1, view, 1, len - 1 - 1); |
| 105 | + view[len - 1] = values[endIndex] * lastMeasureRatio; |
| 106 | + return view; |
| 107 | + } |
| 108 | + } |
| 109 | +} |
0 commit comments