From e913cfe454826bb64cc3511972c51dcffcc8c849 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 19 Jun 2018 20:41:40 +0200 Subject: [PATCH] prepare oref1 plugin --- .../info/nightscout/androidaps/MainApp.java | 2 + .../androidaps/PreferencesActivity.java | 2 + .../IobCobCalculatorPlugin.java | 8 +- .../IobCobCalculator/IobCobOref1Thread.java | 280 ++++++++++++++++++ .../SensitivityOref1Plugin.java | 173 +++++++++++ app/src/main/res/values/strings.xml | 2 + .../main/res/xml/pref_absorption_oref1.xml | 68 +++++ 7 files changed, 533 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobOref1Thread.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref1/SensitivityOref1Plugin.java create mode 100644 app/src/main/res/xml/pref_absorption_oref1.xml diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 7f4a6e4a9c..e682bb3dce 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -64,6 +64,7 @@ import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; 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.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; @@ -150,6 +151,7 @@ public class MainApp extends Application { pluginsList.add(SensitivityOref0Plugin.getPlugin()); pluginsList.add(SensitivityAAPSPlugin.getPlugin()); pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin()); + pluginsList.add(SensitivityOref1Plugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin()); diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index 014dfcd863..2c10ad88d6 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; 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.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; @@ -152,6 +153,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY); + addPreferencesFromResourceIfEnabled(SensitivityOref1Plugin.getPlugin(), PluginType.SENSITIVITY); if (Config.HWPUMPS) { addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java index 2e8e16a226..ba4b89ebaa 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java @@ -35,6 +35,7 @@ import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; 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.TreatmentsPlugin; import info.nightscout.utils.DateUtil; @@ -68,7 +69,7 @@ public class IobCobCalculatorPlugin extends PluginBase { final Object dataLock = new Object(); boolean stopCalculationTrigger = false; - private IobCobThread thread = null; + private Thread thread = null; public IobCobCalculatorPlugin() { super(new PluginDescription() @@ -541,7 +542,10 @@ public class IobCobCalculatorPlugin extends PluginBase { public void runCalculation(String from, long start, boolean bgDataReload, Event cause) { log.debug("Starting calculation thread: " + from); 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(); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobOref1Thread.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobOref1Thread.java new file mode 100644 index 0000000000..e28d6356e5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobOref1Thread.java @@ -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 bucketed_data = iobCobCalculatorPlugin.getBucketedData(); + LongSparseArray 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 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("")); + } + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref1/SensitivityOref1Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref1/SensitivityOref1Plugin.java new file mode 100644 index 0000000000..3f2eae604d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref1/SensitivityOref1Plugin.java @@ -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 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 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; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cffe9a2421..c9f701c8e8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,6 +39,7 @@ Pump integration for pumps which don\'t have any driver yet (Open Loop) 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. Sensitivity is calculated from 24h data in the past and carbs (if not absorbed) are cut after time specified in preferences. + 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. 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. Receive BG values from the patched Dexcom G5 app. Receive BG values from Glimp. @@ -665,6 +666,7 @@ Which sensitivity algorithm should be used? SENS Sensitivity Oref0 + Sensitivity Oref1 Sensitivity AAPS Absorption settings absorption_maxtime diff --git a/app/src/main/res/xml/pref_absorption_oref1.xml b/app/src/main/res/xml/pref_absorption_oref1.xml new file mode 100644 index 0000000000..d951366d27 --- /dev/null +++ b/app/src/main/res/xml/pref_absorption_oref1.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + +