prepare oref1 plugin
This commit is contained in:
parent
af8e1fb32f
commit
e913cfe454
|
@ -64,6 +64,7 @@ import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
|
||||||
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
|
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
|
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
|
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
|
||||||
|
import info.nightscout.androidaps.plugins.SensitivityOref1.SensitivityOref1Plugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
|
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
|
||||||
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
||||||
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
|
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
|
||||||
|
@ -150,6 +151,7 @@ public class MainApp extends Application {
|
||||||
pluginsList.add(SensitivityOref0Plugin.getPlugin());
|
pluginsList.add(SensitivityOref0Plugin.getPlugin());
|
||||||
pluginsList.add(SensitivityAAPSPlugin.getPlugin());
|
pluginsList.add(SensitivityAAPSPlugin.getPlugin());
|
||||||
pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin());
|
pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin());
|
||||||
|
pluginsList.add(SensitivityOref1Plugin.getPlugin());
|
||||||
if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin());
|
if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin());
|
||||||
if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
|
if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
|
||||||
if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin());
|
if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin());
|
||||||
|
|
|
@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
|
||||||
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
|
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
|
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
|
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
|
||||||
|
import info.nightscout.androidaps.plugins.SensitivityOref1.SensitivityOref1Plugin;
|
||||||
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
|
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
|
||||||
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
|
||||||
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
|
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
|
||||||
|
@ -152,6 +153,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
||||||
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
|
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
|
||||||
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
|
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
|
||||||
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
|
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
|
||||||
|
addPreferencesFromResourceIfEnabled(SensitivityOref1Plugin.getPlugin(), PluginType.SENSITIVITY);
|
||||||
|
|
||||||
if (Config.HWPUMPS) {
|
if (Config.HWPUMPS) {
|
||||||
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);
|
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);
|
||||||
|
|
|
@ -35,6 +35,7 @@ import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
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.OpenAPSSMB.OpenAPSSMBPlugin;
|
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.SensitivityOref1.SensitivityOref1Plugin;
|
||||||
import info.nightscout.androidaps.plugins.Treatments.Treatment;
|
import info.nightscout.androidaps.plugins.Treatments.Treatment;
|
||||||
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
||||||
import info.nightscout.utils.DateUtil;
|
import info.nightscout.utils.DateUtil;
|
||||||
|
@ -68,7 +69,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
|
||||||
final Object dataLock = new Object();
|
final Object dataLock = new Object();
|
||||||
|
|
||||||
boolean stopCalculationTrigger = false;
|
boolean stopCalculationTrigger = false;
|
||||||
private IobCobThread thread = null;
|
private Thread thread = null;
|
||||||
|
|
||||||
public IobCobCalculatorPlugin() {
|
public IobCobCalculatorPlugin() {
|
||||||
super(new PluginDescription()
|
super(new PluginDescription()
|
||||||
|
@ -541,7 +542,10 @@ public class IobCobCalculatorPlugin extends PluginBase {
|
||||||
public void runCalculation(String from, long start, boolean bgDataReload, Event cause) {
|
public void runCalculation(String from, long start, boolean bgDataReload, Event cause) {
|
||||||
log.debug("Starting calculation thread: " + from);
|
log.debug("Starting calculation thread: " + from);
|
||||||
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
|
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
|
||||||
thread = new IobCobThread(this, from, start, bgDataReload, cause);
|
if (SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
|
||||||
|
thread = new IobCobOref1Thread(this, from, start, bgDataReload, cause);
|
||||||
|
else
|
||||||
|
thread = new IobCobThread(this, from, start, bgDataReload, cause);
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,280 @@
|
||||||
|
package info.nightscout.androidaps.plugins.IobCobCalculator;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.support.v4.util.LongSparseArray;
|
||||||
|
|
||||||
|
import com.crashlytics.android.answers.CustomEvent;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.BuildConfig;
|
||||||
|
import info.nightscout.androidaps.Config;
|
||||||
|
import info.nightscout.androidaps.Constants;
|
||||||
|
import info.nightscout.androidaps.MainApp;
|
||||||
|
import info.nightscout.androidaps.R;
|
||||||
|
import info.nightscout.androidaps.data.IobTotal;
|
||||||
|
import info.nightscout.androidaps.data.Profile;
|
||||||
|
import info.nightscout.androidaps.db.BgReading;
|
||||||
|
import info.nightscout.androidaps.events.Event;
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
|
||||||
|
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
|
||||||
|
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.Treatments.Treatment;
|
||||||
|
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
|
||||||
|
import info.nightscout.utils.DateUtil;
|
||||||
|
import info.nightscout.utils.FabricPrivacy;
|
||||||
|
import info.nightscout.utils.SP;
|
||||||
|
|
||||||
|
import static info.nightscout.utils.DateUtil.now;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mike on 23.01.2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class IobCobOref1Thread extends Thread {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(IobCobOref1Thread.class);
|
||||||
|
private final Event cause;
|
||||||
|
|
||||||
|
private IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||||
|
private boolean bgDataReload;
|
||||||
|
private String from;
|
||||||
|
private long start;
|
||||||
|
|
||||||
|
private PowerManager.WakeLock mWakeLock;
|
||||||
|
|
||||||
|
public IobCobOref1Thread(IobCobCalculatorPlugin plugin, String from, long start, boolean bgDataReload, Event cause) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.iobCobCalculatorPlugin = plugin;
|
||||||
|
this.bgDataReload = bgDataReload;
|
||||||
|
this.from = from;
|
||||||
|
this.cause = cause;
|
||||||
|
this.start = start;
|
||||||
|
|
||||||
|
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
|
||||||
|
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void run() {
|
||||||
|
mWakeLock.acquire();
|
||||||
|
try {
|
||||||
|
if (MainApp.getConfigBuilder() == null) {
|
||||||
|
log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
|
||||||
|
return; // app still initializing
|
||||||
|
}
|
||||||
|
if (!MainApp.getConfigBuilder().isProfileValid("IobCobThread")) {
|
||||||
|
log.debug("Aborting calculation thread (No profile): " + from);
|
||||||
|
return; // app still initializing
|
||||||
|
}
|
||||||
|
//log.debug("Locking calculateSensitivityData");
|
||||||
|
|
||||||
|
long oldestTimeWithData = iobCobCalculatorPlugin.oldestDataAvailable();
|
||||||
|
|
||||||
|
synchronized (iobCobCalculatorPlugin.dataLock) {
|
||||||
|
if (bgDataReload) {
|
||||||
|
iobCobCalculatorPlugin.loadBgData(start);
|
||||||
|
iobCobCalculatorPlugin.createBucketedData();
|
||||||
|
}
|
||||||
|
List<BgReading> bucketed_data = iobCobCalculatorPlugin.getBucketedData();
|
||||||
|
LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
|
||||||
|
|
||||||
|
if (bucketed_data == null || bucketed_data.size() < 3) {
|
||||||
|
log.debug("Aborting calculation thread (No bucketed data available): " + from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
|
||||||
|
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--) {
|
||||||
|
String progress = i + (MainApp.isDev() ? " (" + from + ")" : "");
|
||||||
|
MainApp.bus().post(new EventIobCalculationProgress(progress));
|
||||||
|
|
||||||
|
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||||
|
iobCobCalculatorPlugin.stopCalculationTrigger = false;
|
||||||
|
log.debug("Aborting calculation thread (trigger): " + from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check if data already exists
|
||||||
|
long bgTime = bucketed_data.get(i).date;
|
||||||
|
bgTime = IobCobCalculatorPlugin.roundUpTime(bgTime);
|
||||||
|
if (bgTime > IobCobCalculatorPlugin.roundUpTime(now()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AutosensData existing;
|
||||||
|
if ((existing = autosensDataTable.get(bgTime)) != null) {
|
||||||
|
previous = existing;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime);
|
||||||
|
if (profile == null) {
|
||||||
|
log.debug("Aborting calculation thread (no profile): " + from);
|
||||||
|
return; // profile not set yet
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
|
||||||
|
|
||||||
|
double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
|
||||||
|
|
||||||
|
AutosensData autosensData = new AutosensData();
|
||||||
|
autosensData.time = bgTime;
|
||||||
|
if (previous != null)
|
||||||
|
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
|
||||||
|
else
|
||||||
|
autosensData.activeCarbsList = new ArrayList<>();
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
delta = (bg - bucketed_data.get(i + 1).value);
|
||||||
|
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
|
||||||
|
|
||||||
|
IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile);
|
||||||
|
|
||||||
|
double bgi = -iob.activity * sens * 5;
|
||||||
|
double deviation = delta - bgi;
|
||||||
|
double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
|
||||||
|
|
||||||
|
double slopeFromMaxDeviation = 0;
|
||||||
|
double slopeFromMinDeviation = 999;
|
||||||
|
double maxDeviation = 0;
|
||||||
|
double minDeviation = 999;
|
||||||
|
|
||||||
|
// https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
|
||||||
|
if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
|
||||||
|
long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
|
||||||
|
AutosensData hourAgoData = IobCobCalculatorPlugin.getPlugin().getAutosensData(hourago);
|
||||||
|
if (hourAgoData != null) {
|
||||||
|
int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString());
|
||||||
|
int past = 1;
|
||||||
|
try {
|
||||||
|
for (; past < 12; past++) {
|
||||||
|
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
|
||||||
|
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
|
||||||
|
if (ad.avgDeviation > maxDeviation) {
|
||||||
|
slopeFromMaxDeviation = Math.min(0, deviationSlope);
|
||||||
|
maxDeviation = ad.avgDeviation;
|
||||||
|
}
|
||||||
|
if (ad.avgDeviation < minDeviation) {
|
||||||
|
slopeFromMinDeviation = Math.max(0, deviationSlope);
|
||||||
|
minDeviation = ad.avgDeviation;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (Config.logAutosensData)
|
||||||
|
// log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unhandled exception", e);
|
||||||
|
FabricPrivacy.logException(e);
|
||||||
|
FabricPrivacy.getInstance().logCustom(new CustomEvent("CatchedError")
|
||||||
|
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
|
||||||
|
.putCustomAttribute("version", BuildConfig.VERSION)
|
||||||
|
.putCustomAttribute("autosensDataTable", iobCobCalculatorPlugin.getAutosensDataTable().toString())
|
||||||
|
.putCustomAttribute("for_data", ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString())
|
||||||
|
.putCustomAttribute("past", past)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Treatment> recentTreatments = TreatmentsPlugin.getPlugin().getTreatments5MinBackFromHistory(bgTime);
|
||||||
|
for (int ir = 0; ir < recentTreatments.size(); ir++) {
|
||||||
|
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
|
||||||
|
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if we are absorbing carbs
|
||||||
|
if (previous != null && previous.cob > 0) {
|
||||||
|
// calculate sum of min carb impact from all active treatments
|
||||||
|
double totalMinCarbsImpact = 0d;
|
||||||
|
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
|
||||||
|
//when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
|
||||||
|
for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
|
||||||
|
AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
|
||||||
|
totalMinCarbsImpact += c.min5minCarbImpact;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Oref sensitivity
|
||||||
|
totalMinCarbsImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out how many carbs that represents
|
||||||
|
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
|
||||||
|
double ci = Math.max(deviation, totalMinCarbsImpact);
|
||||||
|
if (ci != deviation)
|
||||||
|
autosensData.failoverToMinAbsorbtionRate = true;
|
||||||
|
autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
|
||||||
|
// and add that to the running total carbsAbsorbed
|
||||||
|
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
|
||||||
|
autosensData.substractAbosorbedCarbs();
|
||||||
|
autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
|
||||||
|
}
|
||||||
|
autosensData.removeOldCarbs(bgTime);
|
||||||
|
autosensData.cob += autosensData.carbsFromBolus;
|
||||||
|
autosensData.deviation = deviation;
|
||||||
|
autosensData.bgi = bgi;
|
||||||
|
autosensData.delta = delta;
|
||||||
|
autosensData.avgDelta = avgDelta;
|
||||||
|
autosensData.avgDeviation = avgDeviation;
|
||||||
|
autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
|
||||||
|
autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
|
||||||
|
|
||||||
|
|
||||||
|
// calculate autosens only without COB
|
||||||
|
if (autosensData.cob <= 0) {
|
||||||
|
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
|
||||||
|
autosensData.pastSensitivity += "=";
|
||||||
|
autosensData.nonEqualDeviation = true;
|
||||||
|
} else if (deviation > 0) {
|
||||||
|
autosensData.pastSensitivity += "+";
|
||||||
|
autosensData.nonEqualDeviation = true;
|
||||||
|
} else {
|
||||||
|
autosensData.pastSensitivity += "-";
|
||||||
|
autosensData.nonEqualDeviation = true;
|
||||||
|
}
|
||||||
|
autosensData.nonCarbsDeviation = 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);
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime));
|
||||||
|
autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio;
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug(autosensData.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainApp.bus().post(new EventAutosensCalculationFinished(cause));
|
||||||
|
log.debug("Finishing calculation thread: " + from);
|
||||||
|
} finally {
|
||||||
|
mWakeLock.release();
|
||||||
|
MainApp.bus().post(new EventIobCalculationProgress(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
package info.nightscout.androidaps.plugins.SensitivityOref1;
|
||||||
|
|
||||||
|
import android.support.v4.util.LongSparseArray;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.Config;
|
||||||
|
import info.nightscout.androidaps.MainApp;
|
||||||
|
import info.nightscout.androidaps.R;
|
||||||
|
import info.nightscout.androidaps.data.Profile;
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
|
import info.nightscout.androidaps.interfaces.SensitivityInterface;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
|
||||||
|
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
|
||||||
|
import info.nightscout.utils.Round;
|
||||||
|
import info.nightscout.utils.SP;
|
||||||
|
import info.nightscout.utils.SafeParse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mike on 19.06.2018.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SensitivityOref1Plugin extends PluginBase implements SensitivityInterface {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
|
||||||
|
|
||||||
|
static SensitivityOref1Plugin plugin = null;
|
||||||
|
|
||||||
|
public static SensitivityOref1Plugin getPlugin() {
|
||||||
|
if (plugin == null)
|
||||||
|
plugin = new SensitivityOref1Plugin();
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SensitivityOref1Plugin() {
|
||||||
|
super(new PluginDescription()
|
||||||
|
.mainType(PluginType.SENSITIVITY)
|
||||||
|
.pluginName(R.string.sensitivityoref1)
|
||||||
|
.shortName(R.string.sensitivity_shortname)
|
||||||
|
.preferencesId(R.xml.pref_absorption_oref1)
|
||||||
|
.description(R.string.description_sensitivity_oref1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AutosensResult detectSensitivity(long fromTime, long toTime) {
|
||||||
|
LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
|
||||||
|
|
||||||
|
String age = SP.getString(R.string.key_age, "");
|
||||||
|
int defaultHours = 24;
|
||||||
|
if (age.equals(MainApp.gs(R.string.key_adult))) defaultHours = 24;
|
||||||
|
if (age.equals(MainApp.gs(R.string.key_teenage))) defaultHours = 24;
|
||||||
|
if (age.equals(MainApp.gs(R.string.key_child))) defaultHours = 24;
|
||||||
|
int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours);
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
Profile profile = MainApp.getConfigBuilder().getProfile();
|
||||||
|
|
||||||
|
if (profile == null) {
|
||||||
|
log.debug("No profile");
|
||||||
|
return new AutosensResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autosensDataTable == null || autosensDataTable.size() < 4) {
|
||||||
|
log.debug("No autosens data available");
|
||||||
|
return new AutosensResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutosensData current = IobCobCalculatorPlugin.getPlugin().getAutosensData(toTime); // this is running inside lock already
|
||||||
|
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.time > toTime) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
|
||||||
|
deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d);
|
||||||
|
if (deviationsArray.size() > hoursForDetection * 60 / 5)
|
||||||
|
deviationsArray.remove(0);
|
||||||
|
|
||||||
|
pastSensitivity += autosensData.pastSensitivity;
|
||||||
|
int secondsFromMidnight = Profile.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);
|
||||||
|
|
||||||
|
double sens = profile.getIsf();
|
||||||
|
|
||||||
|
double ratio = 1;
|
||||||
|
String ratioLimit = "";
|
||||||
|
String sensResult = "";
|
||||||
|
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug("Records: " + index + " " + pastSensitivity);
|
||||||
|
|
||||||
|
Arrays.sort(deviations);
|
||||||
|
|
||||||
|
for (double i = 0.9; i > 0.1; i = i - 0.02) {
|
||||||
|
if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.02)) >= 0 && IobCobCalculatorPlugin.percentile(deviations, i) < 0) {
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50);
|
||||||
|
double pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.45);
|
||||||
|
|
||||||
|
double basalOff = 0;
|
||||||
|
|
||||||
|
if (pSensitive < 0) { // sensitive
|
||||||
|
basalOff = pSensitive * (60 / 5) / Profile.toMgdl(sens, profile.getUnits());
|
||||||
|
sensResult = "Excess insulin sensitivity detected";
|
||||||
|
} else if (pResistant > 0) { // resistant
|
||||||
|
basalOff = pResistant * (60 / 5) / Profile.toMgdl(sens, profile.getUnits());
|
||||||
|
sensResult = "Excess insulin resistance detected";
|
||||||
|
} else {
|
||||||
|
sensResult = "Sensitivity normal";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug(sensResult);
|
||||||
|
|
||||||
|
ratio = 1 + (basalOff / profile.getMaxDailyBasal());
|
||||||
|
|
||||||
|
double rawRatio = ratio;
|
||||||
|
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_min, "0.7")));
|
||||||
|
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
|
||||||
|
|
||||||
|
if (ratio != rawRatio) {
|
||||||
|
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
|
||||||
|
log.debug(ratioLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.logAutosensData)
|
||||||
|
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " ratio: " + ratio + " mealCOB: " + current.cob);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@
|
||||||
<string name="description_pump_virtual">Pump integration for pumps which don\'t have any driver yet (Open Loop)</string>
|
<string name="description_pump_virtual">Pump integration for pumps which don\'t have any driver yet (Open Loop)</string>
|
||||||
<string name="description_sensitivity_aaps">Sensitivity is calculated the same way like Oref0, but you can specify timeframe to the past. Minimal carb absorption is calculated from max carb absorption time from preferences.</string>
|
<string name="description_sensitivity_aaps">Sensitivity is calculated the same way like Oref0, but you can specify timeframe to the past. Minimal carb absorption is calculated from max carb absorption time from preferences.</string>
|
||||||
<string name="description_sensitivity_oref0">Sensitivity is calculated from 24h data in the past and carbs (if not absorbed) are cut after time specified in preferences.</string>
|
<string name="description_sensitivity_oref0">Sensitivity is calculated from 24h data in the past and carbs (if not absorbed) are cut after time specified in preferences.</string>
|
||||||
|
<string name="description_sensitivity_oref1">Sensitivity is calculated from 24h data in the past and carbs (if not absorbed) are cut after time specified in preferences. Plugin also calculates UAM.</string>
|
||||||
<string name="description_sensitivity_weighted_average">Sensitivity is calculated as a weighted average from deviations. Newer deviations have higher weight. Minimal carb absorption is calculated from max carb absorption time from preferences. This algorithm is the fastest in following sensitivity changes.</string>
|
<string name="description_sensitivity_weighted_average">Sensitivity is calculated as a weighted average from deviations. Newer deviations have higher weight. Minimal carb absorption is calculated from max carb absorption time from preferences. This algorithm is the fastest in following sensitivity changes.</string>
|
||||||
<string name="description_source_dexcom_g5">Receive BG values from the patched Dexcom G5 app.</string>
|
<string name="description_source_dexcom_g5">Receive BG values from the patched Dexcom G5 app.</string>
|
||||||
<string name="description_source_glimp">Receive BG values from Glimp.</string>
|
<string name="description_source_glimp">Receive BG values from Glimp.</string>
|
||||||
|
@ -665,6 +666,7 @@
|
||||||
<string name="configbuilder_sensitivity_description">Which sensitivity algorithm should be used?</string>
|
<string name="configbuilder_sensitivity_description">Which sensitivity algorithm should be used?</string>
|
||||||
<string name="sensitivity_shortname">SENS</string>
|
<string name="sensitivity_shortname">SENS</string>
|
||||||
<string name="sensitivityoref0">Sensitivity Oref0</string>
|
<string name="sensitivityoref0">Sensitivity Oref0</string>
|
||||||
|
<string name="sensitivityoref1">Sensitivity Oref1</string>
|
||||||
<string name="sensitivityaaps">Sensitivity AAPS</string>
|
<string name="sensitivityaaps">Sensitivity AAPS</string>
|
||||||
<string name="absorptionsettings_title">Absorption settings</string>
|
<string name="absorptionsettings_title">Absorption settings</string>
|
||||||
<string name="key_absorption_maxtime" translatable="false">absorption_maxtime</string>
|
<string name="key_absorption_maxtime" translatable="false">absorption_maxtime</string>
|
||||||
|
|
68
app/src/main/res/xml/pref_absorption_oref1.xml
Normal file
68
app/src/main/res/xml/pref_absorption_oref1.xml
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:validate="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="absorption"
|
||||||
|
android:title="@string/absorptionsettings_title">
|
||||||
|
|
||||||
|
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="8.0"
|
||||||
|
android:dialogMessage="@string/openapsama_min_5m_carbimpact_summary"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:key="@string/key_openapsama_min_5m_carbimpact"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/openapsama_min_5m_carbimpact"
|
||||||
|
validate:floatmaxNumber="12.0"
|
||||||
|
validate:floatminNumber="0.1"
|
||||||
|
validate:testType="floatNumericRange" />
|
||||||
|
|
||||||
|
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="6"
|
||||||
|
android:dialogMessage="@string/absorption_cutoff_summary"
|
||||||
|
android:digits="0123456789.,"
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="@string/key_absorption_cutoff"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:title="@string/absorption_cutoff_title"
|
||||||
|
validate:maxNumber="10"
|
||||||
|
validate:minNumber="4"
|
||||||
|
validate:testType="numericRange" />
|
||||||
|
|
||||||
|
<PreferenceScreen android:title="@string/advancedsettings_title">
|
||||||
|
|
||||||
|
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="1.2"
|
||||||
|
android:dialogMessage="@string/openapsama_autosens_max_summary"
|
||||||
|
android:digits="0123456789.,"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:key="@string/key_openapsama_autosens_max"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/openapsama_autosens_max"
|
||||||
|
validate:floatmaxNumber="3"
|
||||||
|
validate:floatminNumber="0.5"
|
||||||
|
validate:testType="floatNumericRange" />
|
||||||
|
|
||||||
|
<com.andreabaccega.widget.ValidatingEditTextPreference
|
||||||
|
android:defaultValue="0.7"
|
||||||
|
android:dialogMessage="@string/openapsama_autosens_min_summary"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:key="@string/key_openapsama_autosens_min"
|
||||||
|
android:maxLines="20"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/openapsama_autosens_min"
|
||||||
|
validate:floatmaxNumber="1.0"
|
||||||
|
validate:floatminNumber="0.1"
|
||||||
|
validate:testType="floatNumericRange" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
Loading…
Reference in a new issue