keep reference time for cached values

This commit is contained in:
Milos Kozak 2020-07-03 20:09:57 +02:00
parent 9c57e6b9b9
commit 888e7f4ab6
3 changed files with 63 additions and 40 deletions

View file

@ -2,7 +2,8 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
class InMemoryGlucoseValue constructor(var timestamp: Long = 0L, var value: Double = 0.0) { class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated : Boolean = false) {
constructor(gv: BgReading) : this(gv.date, gv.value) constructor(gv: BgReading) : this(gv.date, gv.value)
// var generated : value doesn't correspond to real value with timestamp close to real BG
} }

View file

@ -79,6 +79,11 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
// we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values
// once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
private Long referenceTime = null;
private Boolean lastUsed5minCalculation = null; // true if used 5min bucketed data
private volatile List<BgReading> bgReadings = null; // newest at index 0 private volatile List<BgReading> bgReadings = null; // newest at index 0
private volatile List<InMemoryGlucoseValue> bucketed_data = null; private volatile List<InMemoryGlucoseValue> bucketed_data = null;
@ -135,9 +140,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
.subscribe(event -> { .subscribe(event -> {
stopCalculation("onEventConfigBuilderChange"); stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) { synchronized (dataLock) {
getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of configuration change.");
iobTable = new LongSparseArray<>(); resetData();
autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, event); runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, event);
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
@ -152,10 +156,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
stopCalculation("onNewProfile"); stopCalculation("onNewProfile");
synchronized (dataLock) { synchronized (dataLock) {
getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of new profile.");
iobTable = new LongSparseArray<>(); resetData();
autosensDataTable = new LongSparseArray<>();
basalDataTable = new LongSparseArray<>();
} }
runCalculation("onNewProfile", System.currentTimeMillis(), false, true, event); runCalculation("onNewProfile", System.currentTimeMillis(), false, true, event);
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
@ -185,10 +187,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
) { ) {
stopCalculation("onEventPreferenceChange"); stopCalculation("onEventPreferenceChange");
synchronized (dataLock) { synchronized (dataLock) {
getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records" + " BasalData: " + basalDataTable.size() + " records"); getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data because of preference change.");
iobTable = new LongSparseArray<>(); resetData();
autosensDataTable = new LongSparseArray<>();
basalDataTable = new LongSparseArray<>();
} }
runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, true, event); runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, true, event);
} }
@ -248,6 +248,19 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
return rounded; return rounded;
} }
long adjustToReferenceTime(long someTime) {
if (referenceTime == null) {
referenceTime = someTime;
return someTime;
}
long diff = Math.abs(someTime - referenceTime);
diff %= T.mins(5).msecs();
if (diff > T.mins(2).plus(T.secs(30)).msecs())
diff = diff - T.mins(5).msecs();
long newTime = someTime + diff;
return newTime;
}
void loadBgData(long to) { void loadBgData(long to) {
Profile profile = profileFunction.getProfile(to); Profile profile = profileFunction.getProfile(to);
double dia = Constants.defaultDIA; double dia = Constants.defaultDIA;
@ -291,7 +304,23 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
} }
private void resetData() {
synchronized (dataLock) {
iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>();
basalDataTable = new LongSparseArray<>();
absIobTable = new LongSparseArray<>();
}
}
public void createBucketedData() { public void createBucketedData() {
boolean fiveMinData = isAbout5minData();
if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) {
// changing mode => clear cache
getAapsLogger().debug("Invalidating cached data because of changed mode.");
resetData();
}
lastUsed5minCalculation = fiveMinData;
if (isAbout5minData()) if (isAbout5minData())
createBucketedData5min(); createBucketedData5min();
else else
@ -332,6 +361,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
long currentTime = bgReadings.get(0).date - bgReadings.get(0).date % T.mins(5).msecs(); long currentTime = bgReadings.get(0).date - bgReadings.get(0).date % T.mins(5).msecs();
currentTime = adjustToReferenceTime(currentTime);
getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime));
//log.debug("First reading: " + new Date(currentTime).toLocaleString()); //log.debug("First reading: " + new Date(currentTime).toLocaleString());
while (true) { while (true) {
@ -348,9 +379,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
long timeDiffToNew = newer.date - currentTime; long timeDiffToNew = newer.date - currentTime;
double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta; double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(currentTime, Math.round(currentBg), true);
newBgreading.setTimestamp(currentTime);
newBgreading.setValue(Math.round(currentBg));
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
} }
@ -388,12 +417,10 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
while (elapsed_minutes > 5) { while (elapsed_minutes > 5) {
nextbgTime = lastbgTime - 5 * 60 * 1000; nextbgTime = lastbgTime - 5 * 60 * 1000;
j++; j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue();
newBgreading.setTimestamp(nextbgTime);
double gapDelta = bgReadings.get(i).value - lastbg; double gapDelta = bgReadings.get(i).value - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes); //console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta); double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
newBgreading.setValue(Math.round(nextbg)); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(nextbgTime, Math.round(nextbg), true);
//console.error("Interpolated", bucketed_data[j]); //console.error("Interpolated", bucketed_data[j]);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
@ -403,16 +430,12 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
lastbgTime = nextbgTime; lastbgTime = nextbgTime;
} }
j++; j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value);
newBgreading.setValue(bgReadings.get(i).value);
newBgreading.setTimestamp(bgTime);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else if (Math.abs(elapsed_minutes) > 2) { } else if (Math.abs(elapsed_minutes) > 2) {
j++; j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value);
newBgreading.setValue(bgReadings.get(i).value);
newBgreading.setTimestamp(bgTime);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else { } else {
@ -422,12 +445,15 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
// Normalize bucketed data // Normalize bucketed data
InMemoryGlucoseValue oldest = bucketed_data.get(bucketed_data.size() - 1);
oldest.setTimestamp(adjustToReferenceTime(oldest.getTimestamp()));
getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(oldest.getTimestamp()));
for (int i = bucketed_data.size() - 2; i >= 0; i--) { for (int i = bucketed_data.size() - 2; i >= 0; i--) {
InMemoryGlucoseValue current = bucketed_data.get(i); InMemoryGlucoseValue current = bucketed_data.get(i);
InMemoryGlucoseValue previous = bucketed_data.get(i + 1); InMemoryGlucoseValue previous = bucketed_data.get(i + 1);
long msecDiff = current.getTimestamp() - previous.getTimestamp(); long msecDiff = current.getTimestamp() - previous.getTimestamp();
long adjusted = (msecDiff - T.mins(5).msecs()) / 1000; long adjusted = (msecDiff - T.mins(5).msecs()) / 1000;
getAapsLogger().debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + DateUtil.toISOString(current.getTimestamp()) + " to: " + DateUtil.toISOString(previous.getTimestamp() + T.mins(5).msecs()) + " by " + adjusted + " sec"); getAapsLogger().debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.getTimestamp()) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.getTimestamp() + T.mins(5).msecs()) + " by " + adjusted + " sec");
if (Math.abs(adjusted) > 90) { if (Math.abs(adjusted) > 90) {
// too big adjustment, fallback to non 5 min data // too big adjustment, fallback to non 5 min data
getAapsLogger().debug(LTag.AUTOSENS, "Fallback to non 5 min data"); getAapsLogger().debug(LTag.AUTOSENS, "Fallback to non 5 min data");
@ -450,7 +476,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
if (limitDataToOldestAvailable) { if (limitDataToOldestAvailable) {
getBGDataFrom = Math.max(oldestDataAvailable, (long) (from - T.hours(1).msecs() * (24 + dia))); getBGDataFrom = Math.max(oldestDataAvailable, (long) (from - T.hours(1).msecs() * (24 + dia)));
if (getBGDataFrom == oldestDataAvailable) if (getBGDataFrom == oldestDataAvailable)
getAapsLogger().debug(LTag.AUTOSENS, "Limiting data to oldest available temps: " + dateUtil.dateAndTimeString(oldestDataAvailable)); getAapsLogger().debug(LTag.AUTOSENS, "Limiting data to oldest available temps: " + dateUtil.dateAndTimeAndSecondsString(oldestDataAvailable));
} else } else
getBGDataFrom = (long) (from - T.hours(1).msecs() * (24 + dia)); getBGDataFrom = (long) (from - T.hours(1).msecs() * (24 + dia));
return getBGDataFrom; return getBGDataFrom;
@ -685,7 +711,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
return null; return null;
} }
if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + dateUtil.dateAndTimeString(data.time)); getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + dateUtil.dateAndTimeAndSecondsString(data.time));
return null; return null;
} else { } else {
getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA (" + reason + ") " + data.toString()); getAapsLogger().debug(LTag.AUTOSENS, "AUTOSENSDATA (" + reason + ") " + data.toString());
@ -696,7 +722,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
@Override @Override
public String lastDataTime() { public String lastDataTime() {
if (autosensDataTable.size() > 0) if (autosensDataTable.size() > 0)
return dateUtil.dateAndTimeString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time); return dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time);
else else
return "autosensDataTable empty"; return "autosensDataTable empty";
} }
@ -817,7 +843,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
public void runCalculation(String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) { public void runCalculation(String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
getAapsLogger().debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeString(end)); getAapsLogger().debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end));
if (thread == null || thread.getState() == Thread.State.TERMINATED) { if (thread == null || thread.getState() == Thread.State.TERMINATED) {
if (sensitivityOref1Plugin.isEnabled()) if (sensitivityOref1Plugin.isEnabled())
thread = new IobCobOref1Thread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause); thread = new IobCobOref1Thread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause);
@ -834,10 +860,10 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
synchronized (dataLock) { synchronized (dataLock) {
// clear up 5 min back for proper COB calculation // clear up 5 min back for proper COB calculation
long time = ev.getTime() - 5 * 60 * 1000L; long time = ev.getTime() - 5 * 60 * 1000L;
getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeString(time)); getAapsLogger().debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeAndSecondsString(time));
for (int index = iobTable.size() - 1; index >= 0; index--) { for (int index = iobTable.size() - 1; index >= 0; index--) {
if (iobTable.keyAt(index) > time) { if (iobTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from iobTable: " + dateUtil.dateAndTimeString(iobTable.keyAt(index))); getAapsLogger().debug(LTag.AUTOSENS, "Removing from iobTable: " + dateUtil.dateAndTimeAndSecondsString(iobTable.keyAt(index)));
iobTable.removeAt(index); iobTable.removeAt(index);
} else { } else {
break; break;
@ -845,7 +871,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
for (int index = absIobTable.size() - 1; index >= 0; index--) { for (int index = absIobTable.size() - 1; index >= 0; index--) {
if (absIobTable.keyAt(index) > time) { if (absIobTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from absIobTable: " + dateUtil.dateAndTimeString(absIobTable.keyAt(index))); getAapsLogger().debug(LTag.AUTOSENS, "Removing from absIobTable: " + dateUtil.dateAndTimeAndSecondsString(absIobTable.keyAt(index)));
absIobTable.removeAt(index); absIobTable.removeAt(index);
} else { } else {
break; break;
@ -853,7 +879,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
for (int index = autosensDataTable.size() - 1; index >= 0; index--) { for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
if (autosensDataTable.keyAt(index) > time) { if (autosensDataTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeString(autosensDataTable.keyAt(index))); getAapsLogger().debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index)));
autosensDataTable.removeAt(index); autosensDataTable.removeAt(index);
} else { } else {
break; break;
@ -861,7 +887,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
for (int index = basalDataTable.size() - 1; index >= 0; index--) { for (int index = basalDataTable.size() - 1; index >= 0; index--) {
if (basalDataTable.keyAt(index) > time) { if (basalDataTable.keyAt(index) > time) {
getAapsLogger().debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeString(basalDataTable.keyAt(index))); getAapsLogger().debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)));
basalDataTable.removeAt(index); basalDataTable.removeAt(index);
} else { } else {
break; break;

View file

@ -215,18 +215,14 @@ public class DateUtil {
return dateString(mills) + " " + timeStringWithSeconds(mills); return dateString(mills) + " " + timeStringWithSeconds(mills);
} }
public static String dateAndTimeFullString(long mills) {
return dateString(mills) + " " + timeFullString(mills);
}
public static String minAgo(ResourceHelper resourceHelper, long time) { public static String minAgo(ResourceHelper resourceHelper, long time) {
int mins = (int) ((now() - time) / 1000 / 60); int mins = (int) ((now() - time) / 1000 / 60);
return resourceHelper.gs(R.string.minago, mins); return resourceHelper.gs(R.string.minago, mins);
} }
public static String minAgoShort(long time) { public static String minAgoShort(long time) {
Integer mins = (int) ((time - now()) / 1000 / 60); int mins = (int) ((time - now()) / 1000 / 60);
return (mins > 0 ? "+" : "") + mins.toString(); return (mins > 0 ? "+" : "") + Integer.toString(mins);
} }
public static String hourAgo(long time, ResourceHelper resourceHelper) { public static String hourAgo(long time, ResourceHelper resourceHelper) {