44import java .util .HashSet ;
55import java .util .Set ;
66
7+ import org .apache .commons .math3 .util .FastMath ;
8+
79import net .laprun .sustainability .power .SensorMetadata ;
810
911public class OngoingPowerMeasure implements PowerMeasure {
1012 private final SensorMetadata sensorMetadata ;
11- private final MeasureStore measures ;
13+ private final ComponentMeasure [] measures ;
1214 private final long startedAt ;
1315 private final double [] averages ;
1416 private final Set <Integer > nonZeroComponents ;
1517 private final int [] totalComponents ;
18+ private final int totalIndex ;
1619 private double minTotal = Double .MAX_VALUE ;
1720 private double maxTotal ;
21+ private double accumulatedTotal ;
1822 private int samples ;
1923
20- public OngoingPowerMeasure (SensorMetadata sensorMetadata , Duration duration , Duration frequency ) {
24+ public OngoingPowerMeasure (SensorMetadata sensorMetadata , ComponentMeasure . Factory <?> componentMeasureFactory ) {
2125 this .sensorMetadata = sensorMetadata ;
2226 startedAt = System .currentTimeMillis ();
23- final var numComponents = metadata ().componentCardinality ();
24- averages = new double [numComponents ];
25-
26- final var initialWindow = (int ) (duration .toMillis () / frequency .toMillis ());
27- measures = new DescriptiveStatisticsMeasureStore (numComponents , initialWindow );
2827
28+ final var numComponents = sensorMetadata .componentCardinality ();
29+ // we also record the aggregated total for each component participating in the aggregated value
30+ final var measuresNb = numComponents + 1 ;
31+ measures = new ComponentMeasure [measuresNb ];
32+ for (int i = 0 ; i < measuresNb ; i ++) {
33+ measures [i ] = componentMeasureFactory .create ();
34+ }
35+ totalIndex = numComponents ;
36+ averages = new double [measuresNb ];
37+ // we don't need to record the total component as a non-zero component since it's almost never zero and we compute the std dev separately
2938 nonZeroComponents = new HashSet <>(numComponents );
3039 totalComponents = sensorMetadata .totalComponents ();
3140 }
@@ -49,14 +58,17 @@ public void recordMeasure(double[] components) {
4958 if (componentValue != 0 ) {
5059 nonZeroComponents .add (component );
5160 }
52- measures .recordComponentValue (component , componentValue );
61+ measures [ component ] .recordComponentValue (componentValue );
5362 averages [component ] = averages [component ] == 0 ? componentValue
5463 : (previousSize * averages [component ] + componentValue ) / samples ;
5564 }
5665
5766 // record min / max totals
5867 final var recordedTotal = PowerMeasure .sumOfSelectedComponents (components , totalComponents );
59- measures .recordTotal (recordedTotal );
68+ measures [totalIndex ].recordComponentValue (recordedTotal );
69+ accumulatedTotal += recordedTotal ;
70+ averages [components .length ] = averages [components .length ] == 0 ? recordedTotal
71+ : (previousSize * averages [components .length ] + recordedTotal ) / samples ;
6072 if (recordedTotal < minTotal ) {
6173 minTotal = recordedTotal ;
6274 }
@@ -67,7 +79,7 @@ public void recordMeasure(double[] components) {
6779
6880 @ Override
6981 public double total () {
70- return measures . getMeasuredTotal () ;
82+ return accumulatedTotal ;
7183 }
7284
7385 public Duration duration () {
@@ -94,13 +106,28 @@ public StdDev standardDeviations() {
94106 final var stdDevs = new double [cardinality ];
95107 nonZeroComponents .stream ()
96108 .parallel ()
97- .forEach (component -> stdDevs [component ] = measures . getComponentStandardDeviation (component ));
109+ .forEach (component -> stdDevs [component ] = standardDeviation (component ));
98110
99- return new StdDev (measures .getTotalStandardDeviation (), stdDevs );
111+ final double aggregate = maxTotal == 0 ? 0 : standardDeviation (totalIndex );
112+ return new StdDev (aggregate , stdDevs );
113+ }
114+
115+ private double standardDeviation (int component ) {
116+ final var values = measures [component ].getComponentRawValues ();
117+ if (samples <= 1 ) {
118+ return 0.0 ;
119+ }
120+ final double mean = averages [component ];
121+ double geometric_deviation_total = 0.0 ;
122+ for (double value : values ) {
123+ double deviation = value - mean ;
124+ geometric_deviation_total += (deviation * deviation );
125+ }
126+ return FastMath .sqrt (geometric_deviation_total / (samples - 1 ));
100127 }
101128
102129 @ Override
103130 public double [] getMeasuresFor (int component ) {
104- return measures .getComponentRawValues (component );
131+ return measures [ component ] .getComponentRawValues ();
105132 }
106133}
0 commit comments