more work on autosens
This commit is contained in:
parent
5fe3c50171
commit
3add216584
|
@ -1,17 +1,5 @@
|
||||||
package info.nightscout.androidaps.data;
|
package info.nightscout.androidaps.data;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.db.BgReading;
|
|
||||||
import info.nightscout.androidaps.db.Treatment;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.Autosens;
|
|
||||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.AutosensResult;
|
|
||||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 04.01.2017.
|
* Created by mike on 04.01.2017.
|
||||||
*/
|
*/
|
||||||
|
@ -19,28 +7,4 @@ public class MealData {
|
||||||
public double boluses = 0d;
|
public double boluses = 0d;
|
||||||
public double carbs = 0d;
|
public double carbs = 0d;
|
||||||
public double mealCOB = 0.0d;
|
public double mealCOB = 0.0d;
|
||||||
|
|
||||||
|
|
||||||
public void addTreatment(Treatment treatment) {
|
|
||||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
|
||||||
if (profile == null) return;
|
|
||||||
|
|
||||||
long now = new Date().getTime();
|
|
||||||
long dia_ago = now - (new Double(1.5d * profile.getDia() * 60 * 60 * 1000l)).longValue();
|
|
||||||
long t = treatment.created_at.getTime();
|
|
||||||
if (t > dia_ago && t <= now) {
|
|
||||||
if (treatment.carbs >= 1) {
|
|
||||||
carbs += treatment.carbs;
|
|
||||||
if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS)) {
|
|
||||||
AutosensResult result = Autosens.detectSensitivityandCarbAbsorption((long) (new Date().getTime() - 60 * 60 * 1000L * profile.getDia() * 2), t);
|
|
||||||
double myCarbsAbsorbed = result.carbsAbsorbed;
|
|
||||||
double myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
|
|
||||||
mealCOB = Math.max(mealCOB, myMealCOB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (treatment.insulin > 0 && treatment.mealBolus) {
|
|
||||||
boluses += treatment.insulin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ import java.util.Date;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AutosensData {
|
public class AutosensData {
|
||||||
|
long time = 0L;
|
||||||
String pastSensitivity = "";
|
String pastSensitivity = "";
|
||||||
double deviation = 0d;
|
double deviation = 0d;
|
||||||
|
boolean calculateWithDeviation = false;
|
||||||
double absorbed = 0d;
|
double absorbed = 0d;
|
||||||
double carbsFromBolus = 0d;
|
double carbsFromBolus = 0d;
|
||||||
public double cob = 0;
|
public double cob = 0;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
package info.nightscout.androidaps.plugins.IobCobCalculator;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
|
@ -12,15 +12,14 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import info.nightscout.androidaps.Config;
|
import info.nightscout.androidaps.Config;
|
||||||
import info.nightscout.androidaps.Constants;
|
import info.nightscout.androidaps.Constants;
|
||||||
import info.nightscout.androidaps.MainApp;
|
import info.nightscout.androidaps.MainApp;
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
import info.nightscout.androidaps.data.IobTotal;
|
||||||
import info.nightscout.androidaps.data.MealData;
|
|
||||||
import info.nightscout.androidaps.db.BgReading;
|
import info.nightscout.androidaps.db.BgReading;
|
||||||
import info.nightscout.androidaps.db.Treatment;
|
import info.nightscout.androidaps.db.Treatment;
|
||||||
import info.nightscout.androidaps.events.EventNewBG;
|
import info.nightscout.androidaps.events.EventNewBG;
|
||||||
|
@ -30,9 +29,9 @@ import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||||
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
|
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
|
||||||
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
||||||
import info.nightscout.androidaps.plugins.OpenAPSAMA.Autosens;
|
import info.nightscout.utils.Round;
|
||||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.utils.SP;
|
import info.nightscout.utils.SP;
|
||||||
|
import info.nightscout.utils.SafeParse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 24.04.2017.
|
* Created by mike on 24.04.2017.
|
||||||
|
@ -41,17 +40,19 @@ import info.nightscout.utils.SP;
|
||||||
public class IobCobCalculatorPlugin implements PluginBase {
|
public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
|
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
|
||||||
|
|
||||||
private static LongSparseArray<IobTotal> iobTable = new LongSparseArray<>();
|
private static LongSparseArray<IobTotal> iobTable = new LongSparseArray<>(); // oldest at index 0
|
||||||
private static LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>();
|
private static LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
|
||||||
|
|
||||||
private static List<BgReading> bgReadings = null; // newest at index 0
|
private static volatile List<BgReading> bgReadings = null; // newest at index 0
|
||||||
private static List<BgReading> bucketed_data = null;
|
private static volatile List<BgReading> bucketed_data = null;
|
||||||
|
|
||||||
private static double dia = Constants.defaultDIA;
|
private static double dia = Constants.defaultDIA;
|
||||||
|
|
||||||
private static Handler sHandler = null;
|
private static Handler sHandler = null;
|
||||||
private static HandlerThread sHandlerThread = null;
|
private static HandlerThread sHandlerThread = null;
|
||||||
|
|
||||||
|
private static Object dataLock = new Object();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return GENERAL;
|
return GENERAL;
|
||||||
|
@ -109,15 +110,20 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static List<BgReading> getBucketedData(long fromTime) {
|
public static List<BgReading> getBucketedData(long fromTime) {
|
||||||
if (bucketed_data == null) {
|
//log.debug("Locking getBucketedData");
|
||||||
log.debug("No bucketed data available");
|
synchronized (dataLock) {
|
||||||
return null;
|
if (bucketed_data == null) {
|
||||||
}
|
log.debug("No bucketed data available");
|
||||||
int index = indexNewerThan(fromTime);
|
return null;
|
||||||
if (index > -1) {
|
}
|
||||||
log.debug("Bucketed data striped off: " + index + "/" + bucketed_data.size());
|
int index = indexNewerThan(fromTime);
|
||||||
return bucketed_data.subList(0, index);
|
if (index > -1) {
|
||||||
|
List<BgReading> part = bucketed_data.subList(0, index);
|
||||||
|
log.debug("Bucketed data striped off: " + part.size() + "/" + bucketed_data.size());
|
||||||
|
return part;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//log.debug("Releasing getBucketedData");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,168 +143,178 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadBgData() {
|
private void loadBgData() {
|
||||||
onNewProfile(new EventNewBasalProfile(null));
|
//log.debug("Locking loadBgData");
|
||||||
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia)), false);
|
synchronized (dataLock) {
|
||||||
log.debug("BG data loaded. Size: " + bgReadings.size());
|
onNewProfile(new EventNewBasalProfile(null));
|
||||||
|
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (new Date().getTime() - 60 * 60 * 1000L * (24 + dia)), false);
|
||||||
|
log.debug("BG data loaded. Size: " + bgReadings.size());
|
||||||
|
}
|
||||||
|
//log.debug("Releasing loadBgData");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createBucketedData() {
|
public void createBucketedData() {
|
||||||
if (bgReadings == null || bgReadings.size() < 3) {
|
//log.debug("Locking createBucketedData");
|
||||||
bucketed_data = null;
|
synchronized (dataLock) {
|
||||||
return;
|
if (bgReadings == null || bgReadings.size() < 3) {
|
||||||
}
|
bucketed_data = null;
|
||||||
|
return;
|
||||||
bucketed_data = new ArrayList<>();
|
|
||||||
bucketed_data.add(bgReadings.get(0));
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 1; i < bgReadings.size(); ++i) {
|
|
||||||
long bgTime = bgReadings.get(i).getTimeIndex();
|
|
||||||
long lastbgTime = bgReadings.get(i - 1).getTimeIndex();
|
|
||||||
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
|
|
||||||
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
|
bucketed_data = new ArrayList<>();
|
||||||
if (Math.abs(elapsed_minutes) > 8) {
|
bucketed_data.add(bgReadings.get(0));
|
||||||
// interpolate missing data points
|
int j = 0;
|
||||||
double lastbg = bgReadings.get(i - 1).value;
|
for (int i = 1; i < bgReadings.size(); ++i) {
|
||||||
elapsed_minutes = Math.abs(elapsed_minutes);
|
long bgTime = bgReadings.get(i).getTimeIndex();
|
||||||
//console.error(elapsed_minutes);
|
long lastbgTime = bgReadings.get(i - 1).getTimeIndex();
|
||||||
long nextbgTime;
|
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
|
||||||
while (elapsed_minutes > 5) {
|
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
|
||||||
nextbgTime = lastbgTime - 5 * 60 * 1000;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
|
||||||
|
if (Math.abs(elapsed_minutes) > 8) {
|
||||||
|
// interpolate missing data points
|
||||||
|
double lastbg = bgReadings.get(i - 1).value;
|
||||||
|
elapsed_minutes = Math.abs(elapsed_minutes);
|
||||||
|
//console.error(elapsed_minutes);
|
||||||
|
long nextbgTime;
|
||||||
|
while (elapsed_minutes > 5) {
|
||||||
|
nextbgTime = lastbgTime - 5 * 60 * 1000;
|
||||||
|
j++;
|
||||||
|
BgReading newBgreading = new BgReading();
|
||||||
|
newBgreading.timeIndex = nextbgTime;
|
||||||
|
double gapDelta = bgReadings.get(i).value - lastbg;
|
||||||
|
//console.error(gapDelta, lastbg, elapsed_minutes);
|
||||||
|
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
|
||||||
|
newBgreading.value = Math.round(nextbg);
|
||||||
|
//console.error("Interpolated", bucketed_data[j]);
|
||||||
|
bucketed_data.add(newBgreading);
|
||||||
|
//log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
||||||
|
|
||||||
|
elapsed_minutes = elapsed_minutes - 5;
|
||||||
|
lastbg = nextbg;
|
||||||
|
lastbgTime = nextbgTime;
|
||||||
|
}
|
||||||
j++;
|
j++;
|
||||||
BgReading newBgreading = new BgReading();
|
BgReading newBgreading = new BgReading();
|
||||||
newBgreading.timeIndex = nextbgTime;
|
newBgreading.value = bgReadings.get(i).value;
|
||||||
double gapDelta = bgReadings.get(i).value - lastbg;
|
newBgreading.timeIndex = bgTime;
|
||||||
//console.error(gapDelta, lastbg, elapsed_minutes);
|
|
||||||
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
|
|
||||||
newBgreading.value = Math.round(nextbg);
|
|
||||||
//console.error("Interpolated", bucketed_data[j]);
|
|
||||||
bucketed_data.add(newBgreading);
|
bucketed_data.add(newBgreading);
|
||||||
//log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
||||||
|
} else if (Math.abs(elapsed_minutes) > 2) {
|
||||||
elapsed_minutes = elapsed_minutes - 5;
|
j++;
|
||||||
lastbg = nextbg;
|
BgReading newBgreading = new BgReading();
|
||||||
lastbgTime = nextbgTime;
|
newBgreading.value = bgReadings.get(i).value;
|
||||||
|
newBgreading.timeIndex = bgTime;
|
||||||
|
bucketed_data.add(newBgreading);
|
||||||
|
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
||||||
|
} else {
|
||||||
|
bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
|
||||||
|
//log.error("***** Average");
|
||||||
}
|
}
|
||||||
j++;
|
|
||||||
BgReading newBgreading = new BgReading();
|
|
||||||
newBgreading.value = bgReadings.get(i).value;
|
|
||||||
newBgreading.timeIndex = bgTime;
|
|
||||||
bucketed_data.add(newBgreading);
|
|
||||||
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
|
||||||
} else if (Math.abs(elapsed_minutes) > 2) {
|
|
||||||
j++;
|
|
||||||
BgReading newBgreading = new BgReading();
|
|
||||||
newBgreading.value = bgReadings.get(i).value;
|
|
||||||
newBgreading.timeIndex = bgTime;
|
|
||||||
bucketed_data.add(newBgreading);
|
|
||||||
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value);
|
|
||||||
} else {
|
|
||||||
bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
|
|
||||||
//log.error("***** Average");
|
|
||||||
}
|
}
|
||||||
|
log.debug("Bucketed data created. Size: " + bucketed_data.size());
|
||||||
}
|
}
|
||||||
log.debug("Bucketed data created. Size: " + bucketed_data.size());
|
//log.debug("Releasing createBucketedData");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculateSensitivityData() {
|
public void calculateSensitivityData() {
|
||||||
NSProfile profile = ConfigBuilderPlugin.getActiveProfile() != null ? ConfigBuilderPlugin.getActiveProfile().getProfile() : null;
|
//log.debug("Locking calculateSensitivityData");
|
||||||
|
synchronized (dataLock) {
|
||||||
|
NSProfile profile = ConfigBuilderPlugin.getActiveProfile() != null ? ConfigBuilderPlugin.getActiveProfile().getProfile() : null;
|
||||||
|
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
log.debug("calculateSensitivityData: No profile available");
|
log.debug("calculateSensitivityData: No profile available");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigBuilderPlugin.getActiveTreatments() == null) {
|
|
||||||
log.debug("calculateSensitivityData: No treatments plugin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TreatmentsInterface treatmentsInterface = ConfigBuilderPlugin.getActiveTreatments();
|
|
||||||
if (bucketed_data == null || bucketed_data.size() < 3) {
|
|
||||||
log.debug("calculateSensitivityData: No bucketed data available");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).timeIndex);
|
|
||||||
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
|
|
||||||
AutosensData previous = autosensDataTable.get(prevDataTime);
|
|
||||||
// start from oldest to be able sub cob
|
|
||||||
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
|
|
||||||
// check if data already exists
|
|
||||||
long bgTime = bucketed_data.get(i).timeIndex;
|
|
||||||
bgTime = roundUpTime(bgTime);
|
|
||||||
|
|
||||||
AutosensData existing;
|
|
||||||
if ((existing = autosensDataTable.get(bgTime)) != null) {
|
|
||||||
previous = existing;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int secondsFromMidnight = NSProfile.secondsFromMidnight(bgTime);
|
if (ConfigBuilderPlugin.getActiveTreatments() == null) {
|
||||||
double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits());
|
log.debug("calculateSensitivityData: No treatments plugin");
|
||||||
|
return;
|
||||||
AutosensData autosensData = new AutosensData();
|
|
||||||
|
|
||||||
//console.error(bgTime , bucketed_data[i].glucose);
|
|
||||||
double bg;
|
|
||||||
double avgDelta;
|
|
||||||
double delta;
|
|
||||||
bg = bucketed_data.get(i).value;
|
|
||||||
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
|
|
||||||
log.error("! value < 39");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
|
||||||
delta = (bg - bucketed_data.get(i + 1).value);
|
|
||||||
|
|
||||||
IobTotal iob = calulateFromTreatmentsAndTemps(bgTime);
|
|
||||||
|
|
||||||
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100d;
|
|
||||||
double deviation = delta - bgi;
|
|
||||||
|
|
||||||
List<Treatment> recentTreatments = treatmentsInterface.getTreatments5MinBack(bgTime);
|
|
||||||
for (int ir = 0; ir < recentTreatments.size(); ir++) {
|
|
||||||
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we absorbing carbs
|
TreatmentsInterface treatmentsInterface = ConfigBuilderPlugin.getActiveTreatments();
|
||||||
if (previous != null && previous.cob > 0) {
|
if (bucketed_data == null || bucketed_data.size() < 3) {
|
||||||
// figure out how many carbs that represents
|
log.debug("calculateSensitivityData: No bucketed data available");
|
||||||
// but always assume at least 3mg/dL/5m (default) absorption
|
return;
|
||||||
double ci = Math.max(deviation, SP.getDouble("openapsama_min_5m_carbimpact", 3.0));
|
|
||||||
autosensData.absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
|
|
||||||
// and add that to the running total carbsAbsorbed
|
|
||||||
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
|
|
||||||
}
|
}
|
||||||
autosensData.cob += autosensData.carbsFromBolus;
|
|
||||||
|
|
||||||
// calculate autosens only without COB
|
long prevDataTime = roundUpTime(bucketed_data.get(bucketed_data.size() - 3).timeIndex);
|
||||||
if (autosensData.cob <= 0) {
|
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
|
||||||
if (deviation > 0) {
|
AutosensData previous = autosensDataTable.get(prevDataTime);
|
||||||
autosensData.pastSensitivity += "+";
|
// start from oldest to be able sub cob
|
||||||
} else if (deviation == 0) {
|
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
|
||||||
autosensData.pastSensitivity += "=";
|
// check if data already exists
|
||||||
} else {
|
long bgTime = bucketed_data.get(i).timeIndex;
|
||||||
autosensData.pastSensitivity += "-";
|
bgTime = roundUpTime(bgTime);
|
||||||
|
|
||||||
|
AutosensData existing;
|
||||||
|
if ((existing = autosensDataTable.get(bgTime)) != null) {
|
||||||
|
previous = existing;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
//avgDeltas[i] = avgDelta;
|
|
||||||
//bgis[i] = bgi;
|
int secondsFromMidnight = NSProfile.secondsFromMidnight(bgTime);
|
||||||
|
double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits());
|
||||||
|
|
||||||
|
AutosensData autosensData = new AutosensData();
|
||||||
|
autosensData.time = bgTime;
|
||||||
|
|
||||||
|
//console.error(bgTime , bucketed_data[i].glucose);
|
||||||
|
double bg;
|
||||||
|
double avgDelta;
|
||||||
|
double delta;
|
||||||
|
bg = bucketed_data.get(i).value;
|
||||||
|
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
|
||||||
|
log.error("! value < 39");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
||||||
|
delta = (bg - bucketed_data.get(i + 1).value);
|
||||||
|
|
||||||
|
IobTotal iob = calulateFromTreatmentsAndTemps(bgTime);
|
||||||
|
|
||||||
|
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100d;
|
||||||
|
double deviation = delta - bgi;
|
||||||
|
|
||||||
|
List<Treatment> recentTreatments = treatmentsInterface.getTreatments5MinBack(bgTime);
|
||||||
|
for (int ir = 0; ir < recentTreatments.size(); ir++) {
|
||||||
|
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are absorbing carbs
|
||||||
|
if (previous != null && previous.cob > 0) {
|
||||||
|
// figure out how many carbs that represents
|
||||||
|
// but always assume at least 3mg/dL/5m (default) absorption
|
||||||
|
double ci = Math.max(deviation, SP.getDouble("openapsama_min_5m_carbimpact", 3.0));
|
||||||
|
autosensData.absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
|
||||||
|
// and add that to the running total carbsAbsorbed
|
||||||
|
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
|
||||||
|
}
|
||||||
|
autosensData.cob += autosensData.carbsFromBolus;
|
||||||
autosensData.deviation = deviation;
|
autosensData.deviation = deviation;
|
||||||
} else {
|
|
||||||
autosensData.pastSensitivity += "C";
|
// calculate autosens only without COB
|
||||||
//console.error(bgTime);
|
if (autosensData.cob <= 0) {
|
||||||
|
if (deviation > 0) {
|
||||||
|
autosensData.pastSensitivity += "+";
|
||||||
|
} else if (deviation == 0) {
|
||||||
|
autosensData.pastSensitivity += "=";
|
||||||
|
} else {
|
||||||
|
autosensData.pastSensitivity += "-";
|
||||||
|
}
|
||||||
|
autosensData.calculateWithDeviation = true;
|
||||||
|
} else {
|
||||||
|
autosensData.pastSensitivity += "C";
|
||||||
|
}
|
||||||
|
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
|
||||||
|
|
||||||
|
previous = autosensData;
|
||||||
|
autosensDataTable.put(bgTime, autosensData);
|
||||||
|
log.debug(autosensData.log(bgTime));
|
||||||
}
|
}
|
||||||
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
|
|
||||||
|
|
||||||
previous = autosensData;
|
|
||||||
autosensDataTable.put(bgTime, autosensData);
|
|
||||||
log.debug(autosensData.log(bgTime));
|
|
||||||
}
|
}
|
||||||
|
//log.debug("Releasing calculateSensitivityData");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IobTotal calulateFromTreatmentsAndTemps(long time) {
|
public static IobTotal calulateFromTreatmentsAndTemps(long time) {
|
||||||
|
@ -326,7 +342,7 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
|
|
||||||
public static AutosensData getAutosensData(long time) {
|
public static AutosensData getAutosensData(long time) {
|
||||||
long now = new Date().getTime();
|
long now = new Date().getTime();
|
||||||
if (time > now )
|
if (time > now)
|
||||||
return null;
|
return null;
|
||||||
time = roundUpTime(time);
|
time = roundUpTime(time);
|
||||||
AutosensData data = autosensDataTable.get(time);
|
AutosensData data = autosensDataTable.get(time);
|
||||||
|
@ -339,6 +355,15 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AutosensData getLastAutosensData() {
|
||||||
|
AutosensData data = autosensDataTable.valueAt(autosensDataTable.size() - 1);
|
||||||
|
if (data.time < new Date().getTime() - 5 * 60 * 1000) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static IobTotal[] calculateIobArrayInDia() {
|
public static IobTotal[] calculateIobArrayInDia() {
|
||||||
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
||||||
// predict IOB out to DIA plus 30m
|
// predict IOB out to DIA plus 30m
|
||||||
|
@ -355,6 +380,103 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AutosensResult detectSensitivity(long fromTime) {
|
||||||
|
//log.debug("Locking detectSensitivity");
|
||||||
|
synchronized (dataLock) {
|
||||||
|
if (autosensDataTable == null || autosensDataTable.size() < 4) {
|
||||||
|
log.debug("No bucketed data available");
|
||||||
|
return new AutosensResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutosensData current = getLastAutosensData();
|
||||||
|
if (current == null) {
|
||||||
|
log.debug("No current autosens data available");
|
||||||
|
return new AutosensResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<Double> deviationsArray = new ArrayList<>();
|
||||||
|
String pastSensitivity = "";
|
||||||
|
int index = 0;
|
||||||
|
while (index < autosensDataTable.size()) {
|
||||||
|
AutosensData autosensData = autosensDataTable.valueAt(index);
|
||||||
|
|
||||||
|
if (autosensData.time < fromTime) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autosensData.calculateWithDeviation)
|
||||||
|
deviationsArray.add(autosensData.deviation);
|
||||||
|
|
||||||
|
pastSensitivity += autosensData.pastSensitivity;
|
||||||
|
int secondsFromMidnight = NSProfile.secondsFromMidnight(autosensData.time);
|
||||||
|
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
|
||||||
|
pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double[] deviations = new Double[deviationsArray.size()];
|
||||||
|
deviations = deviationsArray.toArray(deviations);
|
||||||
|
|
||||||
|
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
|
||||||
|
|
||||||
|
double ratio = 1;
|
||||||
|
String ratioLimit = "";
|
||||||
|
String sensResult = "";
|
||||||
|
|
||||||
|
log.debug("Records: " + index + " " + pastSensitivity);
|
||||||
|
Arrays.sort(deviations);
|
||||||
|
|
||||||
|
for (double i = 0.9; i > 0.1; i = i - 0.02) {
|
||||||
|
if (percentile(deviations, (i + 0.02)) >= 0 && percentile(deviations, i) < 0) {
|
||||||
|
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double pSensitive = percentile(deviations, 0.50);
|
||||||
|
double pResistant = percentile(deviations, 0.45);
|
||||||
|
|
||||||
|
double basalOff = 0;
|
||||||
|
|
||||||
|
if (pSensitive < 0) { // sensitive
|
||||||
|
basalOff = pSensitive * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
||||||
|
sensResult = "Excess insulin sensitivity detected";
|
||||||
|
} else if (pResistant > 0) { // resistant
|
||||||
|
basalOff = pResistant * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
||||||
|
sensResult = "Excess insulin resistance detected";
|
||||||
|
} else {
|
||||||
|
sensResult = "Sensitivity normal";
|
||||||
|
}
|
||||||
|
log.debug(sensResult);
|
||||||
|
ratio = 1 + (basalOff / profile.getMaxDailyBasal());
|
||||||
|
|
||||||
|
double rawRatio = ratio;
|
||||||
|
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_min", "0.7")));
|
||||||
|
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2")));
|
||||||
|
|
||||||
|
if (ratio != rawRatio) {
|
||||||
|
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
|
||||||
|
log.debug(ratioLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
double newisf = Math.round(NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) / ratio);
|
||||||
|
if (ratio != 1) {
|
||||||
|
log.debug("ISF adjusted from " + NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) + " to " + newisf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutosensResult output = new AutosensResult();
|
||||||
|
output.ratio = Round.roundTo(ratio, 0.01);
|
||||||
|
output.carbsAbsorbed = Round.roundTo(current.cob, 0.01);
|
||||||
|
output.pastSensitivity = pastSensitivity;
|
||||||
|
output.ratioLimit = ratioLimit;
|
||||||
|
output.sensResult = sensResult;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
//log.debug("Releasing detectSensitivity");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
|
public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
|
||||||
JSONArray array = new JSONArray();
|
JSONArray array = new JSONArray();
|
||||||
for (int i = 0; i < iobArray.length; i++) {
|
for (int i = 0; i < iobArray.length; i++) {
|
||||||
|
@ -388,24 +510,44 @@ public class IobCobCalculatorPlugin implements PluginBase {
|
||||||
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
|
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onNewHistoryData(EventNewHistoryData ev) {
|
public void onNewHistoryData(EventNewHistoryData ev) {
|
||||||
long time = ev.time;
|
//log.debug("Locking onNewHistoryData");
|
||||||
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString());
|
synchronized (dataLock) {
|
||||||
for (int index = iobTable.size() - 1; index >= 0; index--) {
|
long time = ev.time;
|
||||||
if (iobTable.keyAt(index) > time) {
|
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString());
|
||||||
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
|
for (int index = iobTable.size() - 1; index >= 0; index--) {
|
||||||
iobTable.removeAt(index);
|
if (iobTable.keyAt(index) > time) {
|
||||||
} else {
|
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString());
|
||||||
break;
|
iobTable.removeAt(index);
|
||||||
}
|
} else {
|
||||||
}
|
break;
|
||||||
for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
|
}
|
||||||
if (autosensDataTable.keyAt(index) > time) {
|
}
|
||||||
log.debug("Removing from autosensDataTable: " + new Date(autosensDataTable.keyAt(index)).toLocaleString());
|
for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
|
||||||
autosensDataTable.removeAt(index);
|
if (autosensDataTable.keyAt(index) > time) {
|
||||||
} else {
|
log.debug("Removing from autosensDataTable: " + new Date(autosensDataTable.keyAt(index)).toLocaleString());
|
||||||
break;
|
autosensDataTable.removeAt(index);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//log.debug("Releasing onNewHistoryData");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
|
||||||
|
// Returns the value at a given percentile in a sorted numeric array.
|
||||||
|
// "Linear interpolation between closest ranks" method
|
||||||
|
public static double percentile(Double[] arr, double p) {
|
||||||
|
if (arr.length == 0) return 0;
|
||||||
|
if (p <= 0) return arr[0];
|
||||||
|
if (p >= 1) return arr[arr.length - 1];
|
||||||
|
|
||||||
|
double index = arr.length * p,
|
||||||
|
lower = Math.floor(index),
|
||||||
|
upper = lower + 1,
|
||||||
|
weight = index % 1;
|
||||||
|
|
||||||
|
if (upper >= arr.length) return arr[(int) lower];
|
||||||
|
return arr[(int) lower] * (1 - weight) + arr[(int) upper] * weight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,204 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.OpenAPSAMA;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.db.BgReading;
|
|
||||||
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
|
||||||
import info.nightscout.utils.Round;
|
|
||||||
import info.nightscout.utils.SP;
|
|
||||||
import info.nightscout.utils.SafeParse;
|
|
||||||
|
|
||||||
|
|
||||||
public class Autosens {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(Autosens.class);
|
|
||||||
|
|
||||||
public static AutosensResult detectSensitivityandCarbAbsorption(long dataFromTime, Long mealTime) {
|
|
||||||
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
|
||||||
|
|
||||||
//console.error(mealTime);
|
|
||||||
|
|
||||||
double carbsAbsorbed = 0;
|
|
||||||
|
|
||||||
List<BgReading> bucketed_data = IobCobCalculatorPlugin.getBucketedData(dataFromTime);
|
|
||||||
if (bucketed_data == null)
|
|
||||||
return new AutosensResult();
|
|
||||||
|
|
||||||
//console.error(bucketed_data);
|
|
||||||
//double[] avgDeltas = new double[bucketed_data.size() - 2];
|
|
||||||
//double[] bgis = new double[bucketed_data.size() - 2];
|
|
||||||
double[] deviations = new double[bucketed_data.size() - 2];
|
|
||||||
|
|
||||||
String pastSensitivity = "";
|
|
||||||
for (int i = 0; i < bucketed_data.size() - 3; ++i) {
|
|
||||||
long bgTime = bucketed_data.get(i).timeIndex;
|
|
||||||
int secondsFromMidnight = NSProfile.secondsFromMidnight(new Date(bgTime));
|
|
||||||
|
|
||||||
String hour = "";
|
|
||||||
//log.debug(new Date(bgTime).toString());
|
|
||||||
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
|
|
||||||
hour += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits());
|
|
||||||
|
|
||||||
//console.error(bgTime , bucketed_data[i].glucose);
|
|
||||||
double bg;
|
|
||||||
double avgDelta;
|
|
||||||
double delta;
|
|
||||||
bg = bucketed_data.get(i).value;
|
|
||||||
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
|
|
||||||
log.error("! value < 39");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
|
||||||
delta = (bg - bucketed_data.get(i + 1).value);
|
|
||||||
|
|
||||||
// avgDelta = avgDelta.toFixed(2);
|
|
||||||
IobTotal iob = IobCobCalculatorPlugin.calulateFromTreatmentsAndTemps(bgTime);
|
|
||||||
|
|
||||||
double bgi = Math.round((-iob.activity * sens * 5) * 100) / 100d;
|
|
||||||
// bgi = bgi.toFixed(2);
|
|
||||||
//console.error(delta);
|
|
||||||
double deviation = delta - bgi;
|
|
||||||
// deviation = deviation.toFixed(2);
|
|
||||||
//if (deviation < 0 && deviation > -2) { console.error("BG: "+bg+", avgDelta: "+avgDelta+", BGI: "+bgi+", deviation: "+deviation); }
|
|
||||||
|
|
||||||
// Exclude large positive deviations (carb absorption) from autosens
|
|
||||||
if (avgDelta - bgi < 6) {
|
|
||||||
if (deviation > 0) {
|
|
||||||
pastSensitivity += "+";
|
|
||||||
} else if (deviation == 0) {
|
|
||||||
pastSensitivity += "=";
|
|
||||||
} else {
|
|
||||||
pastSensitivity += "-";
|
|
||||||
}
|
|
||||||
//avgDeltas[i] = avgDelta;
|
|
||||||
//bgis[i] = bgi;
|
|
||||||
deviations[i] = deviation;
|
|
||||||
} else {
|
|
||||||
pastSensitivity += ">";
|
|
||||||
//console.error(bgTime);
|
|
||||||
}
|
|
||||||
pastSensitivity += hour;
|
|
||||||
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
|
|
||||||
|
|
||||||
// if bgTime is more recent than mealTime
|
|
||||||
if (mealTime != null && bgTime > mealTime) {
|
|
||||||
// figure out how many carbs that represents
|
|
||||||
// but always assume at least 3mg/dL/5m (default) absorption
|
|
||||||
double ci = Math.max(deviation, SP.getDouble("openapsama_min_5m_carbimpact", 3.0));
|
|
||||||
double absorbed = ci * profile.getIc(secondsFromMidnight) / sens;
|
|
||||||
// and add that to the running total carbsAbsorbed
|
|
||||||
carbsAbsorbed += absorbed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double ratio = 1;
|
|
||||||
String ratioLimit = "";
|
|
||||||
String sensResult = "";
|
|
||||||
|
|
||||||
if (mealTime == null) {
|
|
||||||
//console.error("");
|
|
||||||
log.debug(pastSensitivity);
|
|
||||||
//console.log(JSON.stringify(avgDeltas));
|
|
||||||
//console.log(JSON.stringify(bgis));
|
|
||||||
//Arrays.sort(avgDeltas);
|
|
||||||
//Arrays.sort(bgis);
|
|
||||||
Arrays.sort(deviations);
|
|
||||||
|
|
||||||
for (double i = 0.9; i > 0.1; i = i - 0.02) {
|
|
||||||
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
|
|
||||||
if (percentile(deviations, (i + 0.02)) >= 0 && percentile(deviations, i) < 0) {
|
|
||||||
//console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2));
|
|
||||||
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
double pSensitive = percentile(deviations, 0.50);
|
|
||||||
double pResistant = percentile(deviations, 0.45);
|
|
||||||
//p30 = percentile(deviations, 0.3);
|
|
||||||
|
|
||||||
// average = deviationSum / deviations.length;
|
|
||||||
|
|
||||||
//console.error("Mean deviation: "+average.toFixed(2));
|
|
||||||
double basalOff = 0;
|
|
||||||
|
|
||||||
if (pSensitive < 0) { // sensitive
|
|
||||||
basalOff = pSensitive * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
|
||||||
sensResult = "Excess insulin sensitivity detected";
|
|
||||||
} else if (pResistant > 0) { // resistant
|
|
||||||
basalOff = pResistant * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits());
|
|
||||||
sensResult = "Excess insulin resistance detected";
|
|
||||||
} else {
|
|
||||||
sensResult = "Sensitivity normal";
|
|
||||||
}
|
|
||||||
log.debug(sensResult);
|
|
||||||
ratio = 1 + (basalOff / profile.getMaxDailyBasal());
|
|
||||||
|
|
||||||
// don't adjust more than 1.5x
|
|
||||||
double rawRatio = ratio;
|
|
||||||
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_min", "0.7")));
|
|
||||||
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2")));
|
|
||||||
|
|
||||||
if (ratio != rawRatio) {
|
|
||||||
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
|
|
||||||
log.debug(ratioLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
double newisf = Math.round(NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) / ratio);
|
|
||||||
if (ratio != 1) {
|
|
||||||
log.debug("ISF adjusted from " + NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) + " to " + newisf);
|
|
||||||
}
|
|
||||||
//console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr");
|
|
||||||
//console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U");
|
|
||||||
}
|
|
||||||
|
|
||||||
AutosensResult output = new AutosensResult();
|
|
||||||
output.ratio = Round.roundTo(ratio, 0.01);
|
|
||||||
output.carbsAbsorbed = Round.roundTo(carbsAbsorbed, 0.01);
|
|
||||||
output.pastSensitivity = pastSensitivity;
|
|
||||||
output.ratioLimit = ratioLimit;
|
|
||||||
output.sensResult = sensResult;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
|
|
||||||
// Returns the value at a given percentile in a sorted numeric array.
|
|
||||||
// "Linear interpolation between closest ranks" method
|
|
||||||
public static double percentile(double[] arr, double p) {
|
|
||||||
if (arr.length == 0) return 0;
|
|
||||||
if (p <= 0) return arr[0];
|
|
||||||
if (p >= 1) return arr[arr.length - 1];
|
|
||||||
|
|
||||||
double index = arr.length * p,
|
|
||||||
lower = Math.floor(index),
|
|
||||||
upper = lower + 1,
|
|
||||||
weight = index % 1;
|
|
||||||
|
|
||||||
if (upper >= arr.length) return arr[(int) lower];
|
|
||||||
return arr[(int) lower] * (1 - weight) + arr[(int) upper] * weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the percentile of the given value in a sorted numeric array.
|
|
||||||
public static double percentRank(double[] arr, double v) {
|
|
||||||
for (int i = 0, l = arr.length; i < l; i++) {
|
|
||||||
if (v <= arr[i]) {
|
|
||||||
while (i < l && v == arr[i]) i++;
|
|
||||||
if (i == 0) return 0;
|
|
||||||
if (v != arr[i - 1]) {
|
|
||||||
i += (v - arr[i - 1]) / (arr[i] - arr[i - 1]);
|
|
||||||
}
|
|
||||||
return i / l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -17,6 +17,7 @@ import info.nightscout.androidaps.db.TempTarget;
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
|
||||||
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
||||||
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
import info.nightscout.androidaps.plugins.Loop.APSResult;
|
||||||
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
import info.nightscout.androidaps.plugins.Loop.ScriptReader;
|
||||||
|
@ -217,7 +218,8 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
|
||||||
|
|
||||||
startPart = new Date();
|
startPart = new Date();
|
||||||
if(MainApp.getConfigBuilder().isAMAModeEnabled()){
|
if(MainApp.getConfigBuilder().isAMAModeEnabled()){
|
||||||
lastAutosensResult = Autosens.detectSensitivityandCarbAbsorption(getBGDataFrom, null);
|
//lastAutosensResult = Autosens.detectSensitivityandCarbAbsorption(getBGDataFrom, null);
|
||||||
|
lastAutosensResult = IobCobCalculatorPlugin.detectSensitivity(getBGDataFrom);
|
||||||
} else {
|
} else {
|
||||||
lastAutosensResult = new AutosensResult();
|
lastAutosensResult = new AutosensResult();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1084,7 +1084,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
|
||||||
Double maxCobValueFound = 0d;
|
Double maxCobValueFound = 0d;
|
||||||
|
|
||||||
if (showIobView.isChecked() || showCobView.isChecked()) {
|
if (showIobView.isChecked() || showCobView.isChecked()) {
|
||||||
Date start = new Date();
|
//Date start = new Date();
|
||||||
List<DataPoint> iobArray = new ArrayList<>();
|
List<DataPoint> iobArray = new ArrayList<>();
|
||||||
List<DataPoint> cobArray = new ArrayList<>();
|
List<DataPoint> cobArray = new ArrayList<>();
|
||||||
for (long time = fromTime; time <= now; time += 5 * 60 * 1000L) {
|
for (long time = fromTime; time <= now; time += 5 * 60 * 1000L) {
|
||||||
|
@ -1101,7 +1101,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Profiler.log(log, "IOB processed", start);
|
//Profiler.log(log, "IOB processed", start);
|
||||||
DataPoint[] iobData = new DataPoint[iobArray.size()];
|
DataPoint[] iobData = new DataPoint[iobArray.size()];
|
||||||
iobData = iobArray.toArray(iobData);
|
iobData = iobArray.toArray(iobData);
|
||||||
iobSeries = new FixedLineGraphSeries<>(iobData);
|
iobSeries = new FixedLineGraphSeries<>(iobData);
|
||||||
|
|
|
@ -21,6 +21,8 @@ import info.nightscout.androidaps.interfaces.InsulinInterface;
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
||||||
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
|
||||||
import info.nightscout.utils.SP;
|
import info.nightscout.utils.SP;
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
||||||
@Override
|
@Override
|
||||||
public String getNameShort() {
|
public String getNameShort() {
|
||||||
String name = MainApp.sResources.getString(R.string.treatments_shortname);
|
String name = MainApp.sResources.getString(R.string.treatments_shortname);
|
||||||
if (!name.trim().isEmpty()){
|
if (!name.trim().isEmpty()) {
|
||||||
//only if translation exists
|
//only if translation exists
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -153,8 +155,27 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
|
||||||
public MealData getMealData() {
|
public MealData getMealData() {
|
||||||
MealData result = new MealData();
|
MealData result = new MealData();
|
||||||
|
|
||||||
|
NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
|
||||||
|
if (profile == null) return result;
|
||||||
|
|
||||||
|
long now = new Date().getTime();
|
||||||
|
long dia_ago = now - (new Double(1.5d * profile.getDia() * 60 * 60 * 1000l)).longValue();
|
||||||
|
|
||||||
for (Treatment treatment : treatments) {
|
for (Treatment treatment : treatments) {
|
||||||
result.addTreatment(treatment);
|
long t = treatment.created_at.getTime();
|
||||||
|
if (t > dia_ago && t <= now) {
|
||||||
|
if (treatment.carbs >= 1) {
|
||||||
|
result.carbs += treatment.carbs;
|
||||||
|
}
|
||||||
|
if (treatment.insulin > 0 && treatment.mealBolus) {
|
||||||
|
result.boluses += treatment.insulin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData();
|
||||||
|
if (autosensData != null) {
|
||||||
|
result.mealCOB = autosensData.cob;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue