How can i effectively compute a 15 mins time weighted moving average for a scientific data for the below data model and what data structure can be best utilized to perform the moving window calculations to prevent operations in multiple loops?
Below is the data model that i can query from database to get List results.
public class Readings{
private String sensor;
private int sequence;
private Float reading;
private int count;
}
The expected result is 15 mins data (900 seconds data ) which is ∑(last 15 min reading * count in seconds)/(15*60). For first 900 seconds, it is simple straight forward calculation. But after 900th seconds, from the below sequence #23, i need to do a moving weighted average on previous records in a 15 mins /900 s period window.
So 15 mins TWA for seq#23 will be = (15*90 +14*40+13*80+12*110+11*80+10*20+11*10+10*40+11*10+10*80+9*20+10*10+9*10+10*20+9*80+8*50+7*30+6*40+5*20+4*20+3*30+2*10)/900 = 10.22
The time window moves in the next 900s window.
Data
==================================
Sensor Sequence Reading count(s) 15Min TWA = ∑ last 15 min reading * count/(15*60)
GAS 1 1.00 30 0.03
GAS 2 2.00 30 0.10
GAS 3 3.00 30 0.20
GAS 4 4.00 20 0.29
GAS 5 5.00 20 0.40
GAS 6 6.00 40 0.67
GAS 7 7.00 30 0.90
GAS 8 8.00 50 1.34
GAS 9 9.00 80 2.14
GAS 10 10.00 20 2.37
GAS 11 9.00 10 2.47
GAS 12 10.00 10 2.58
GAS 13 9.00 20 2.78
GAS 14 10.00 80 3.67
GAS 15 11.00 10 3.79
GAS 16 10.00 40 4.23
GAS 17 11.00 10 4.36
GAS 18 10.00 20 4.58
GAS 19 11.00 80 5.56
GAS 20 12.00 110 7.02
GAS 21 13.00 80 8.18
GAS 22 14.00 40 8.80
GAS 23 15.00 90 10.22
GAS 24 16.00 30 10.67
GAS 25 17.00 40 11.24
GAS 26 18.00 30 11.66
GAS 27 17.00 50 12.23
GAS 28 18.00 20 12.46
GAS 29 19.00 60 13.16
GAS 30 20.00 100 14.34
I found the solution to complete the 15 mins moving window Time weighted average using Apache Common collections - CircularFifoQueue but wanted to know if this can be improved with a better solution as i need to run this same logic for multiple sensors and time periods every 15 mins once.
List<Readings> findBySensorSn = inetService.findBySensorSn(sensorSn, session);
Map<Short, List<Readings>> groups = findBySensorSn.stream()
.sorted(Comparator.comparing(Readings::getSequence))
.collect(Collectors.toList());
for (Map.Entry<Short, List<Readings>> entry : groups.entrySet() ) {
int count = 0;
Float sum = 0f;
for (Readings readings : entry.getValue()) {
count = count + readings.getCount();
Float sum = 0f;
Queue<Float> fifo = new CircularFifoQueue<Float>(90);
for (Readings readings : entry.getValue()) {
for (int i = 0; i < readings.getCount(); i++) {
//Add readings of 10 seconds in the queue till 900 seconds
fifo.add(readings.getReading() * 10);
}
System.out.println(fifo.stream().collect(Collectors.summingDouble(Float::floatValue)) / 900);
}