This commit is contained in:
Milos Kozak 2018-06-22 22:52:23 +02:00
commit 4efb115209
18 changed files with 762 additions and 28 deletions

View file

@ -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());

View file

@ -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);

View file

@ -29,6 +29,7 @@ import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
import info.nightscout.utils.Translator;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_CAREPORTALEVENTS)
@ -127,6 +128,19 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return result;
}
public static boolean isEvent5minBack(List<CareportalEvent> list, long time) {
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
//log.debug("Found event for time: " + DateUtil.dateAndTimeString(time) + " " + event.toString());
return true;
}
}
//log.debug("WWWWWW No found event for time: " + DateUtil.dateAndTimeString(time));
return false;
}
// -------- DataPointWithLabelInterface -------
@Override

View file

@ -1249,7 +1249,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEventsFromTime(boolean ascending) {
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().eq("eventType", type);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();

View file

@ -56,11 +56,11 @@ public class AutosensData implements DataPointWithLabelInterface {
}
public long time = 0L;
long chartTime;
public double bg = 0; // mgdl
private long chartTime;
public String pastSensitivity = "";
public double deviation = 0d;
boolean nonCarbsDeviation = false;
public boolean nonEqualDeviation = false;
public boolean validDeviation = false;
List<CarbsInPast> activeCarbsList = new ArrayList<>();
double absorbed = 0d;
public double carbsFromBolus = 0d;
@ -76,6 +76,14 @@ public class AutosensData implements DataPointWithLabelInterface {
public double usedMinCarbsImpact = 0d;
public boolean failoverToMinAbsorbtionRate = false;
// Oref1
public boolean absorbing = false;
public double mealCarbs = 0;
public int mealStartCounter = 999;
public String type = "";
public boolean uam = false;
public List<Double> extraDeviation = new ArrayList<>();
@Override
public String toString() {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation =" + slopeFromMinDeviation;

View file

@ -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,6 +542,9 @@ 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) {
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();
}

View file

@ -0,0 +1,351 @@
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.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
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.db.TempTarget;
import info.nightscout.androidaps.events.Event;
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.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;
import static java.util.Calendar.MINUTE;
/**
* 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;
}
autosensData.bg = bg;
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.mealCarbs = previous.mealCarbs;
autosensData.substractAbosorbedCarbs();
autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
autosensData.absorbing = previous.absorbing;
autosensData.mealStartCounter = previous.mealStartCounter;
autosensData.type = previous.type;
autosensData.uam = previous.uam;
}
autosensData.removeOldCarbs(bgTime);
autosensData.cob += autosensData.carbsFromBolus;
autosensData.mealCarbs += autosensData.carbsFromBolus;
autosensData.deviation = deviation;
autosensData.bgi = bgi;
autosensData.delta = delta;
autosensData.avgDelta = avgDelta;
autosensData.avgDeviation = avgDeviation;
autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
// If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens
if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) {
if (deviation > 0)
autosensData.absorbing = true;
else
autosensData.absorbing = false;
// stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h
if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) {
autosensData.absorbing = false;
}
if (!autosensData.absorbing && autosensData.cob < 0.5) {
autosensData.mealCarbs = 0;
}
// check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag
if (!autosensData.type.equals("csf")) {
// process.stderr.write("(");
autosensData.mealStartCounter = 0;
}
autosensData.mealStartCounter++;
autosensData.type = "csf";
} else {
// check previous "type" value, and if it was csf, set a mealAbsorption end flag
if (autosensData.type.equals("csf")) {
// process.stderr.write(")");
}
double currentBasal = profile.getBasal(bgTime);
// always exclude the first 45m after each carb entry
//if (iob.iob > currentBasal || uam ) {
if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) {
autosensData.mealStartCounter++;
if (deviation > 0)
autosensData.uam = true;
else
autosensData.uam = false;
if (!autosensData.type.equals("uam")) {
// process.stderr.write("u(");
}
autosensData.type = "uam";
} else {
if (autosensData.type.equals("uam")) {
// process.stderr.write(")");
}
autosensData.type = "non-meal";
}
}
// Exclude meal-related deviations (carb absorption) from autosens
if (autosensData.type.equals("non-meal")) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity = "=";
autosensData.validDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity = "+";
autosensData.validDeviation = true;
} else {
autosensData.pastSensitivity = "-";
autosensData.validDeviation = true;
}
} else {
autosensData.pastSensitivity = "x";
}
//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);
// add an extra negative deviation if a high temptarget is running and exercise mode is set
if (SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory(bgTime);
if (tempTarget != null && tempTarget.target() > 100) {
autosensData.extraDeviation.add(-(tempTarget.target() - 100) / 20);
}
}
// add one neutral deviation every 2 hours to help decay over long exclusion periods
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(bgTime);
int min = calendar.get(MINUTE);
int hours = calendar.get(Calendar.HOUR_OF_DAY);
if (min >= 0 && min < 5 && hours % 2 == 0)
autosensData.extraDeviation.add(0d);
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(""));
}
}
}

View file

@ -145,6 +145,7 @@ public class IobCobThread extends Thread {
log.error("! value < 39");
continue;
}
autosensData.bg = bg;
delta = (bg - bucketed_data.get(i + 1).value);
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
@ -245,18 +246,17 @@ public class IobCobThread extends Thread {
// calculate autosens only without COB
if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "=";
autosensData.nonEqualDeviation = true;
autosensData.pastSensitivity = "=";
autosensData.validDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity += "+";
autosensData.nonEqualDeviation = true;
autosensData.pastSensitivity = "+";
autosensData.validDeviation = true;
} else {
autosensData.pastSensitivity += "-";
autosensData.nonEqualDeviation = true;
autosensData.pastSensitivity = "-";
autosensData.validDeviation = true;
}
autosensData.nonCarbsDeviation = true;
} else {
autosensData.pastSensitivity += "C";
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);

View file

@ -234,8 +234,8 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("high_temptarget_raises_sensitivity", SMBDefaults.high_temptarget_raises_sensitivity);
mProfile.put("low_temptarget_lowers_sensitivity", SMBDefaults.low_temptarget_lowers_sensitivity);
mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
mProfile.put("sensitivity_raises_target", SMBDefaults.sensitivity_raises_target);
mProfile.put("resistance_lowers_target", SMBDefaults.resistance_lowers_target);
mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);

View file

@ -438,9 +438,18 @@ public class GraphData {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) {
int color = MainApp.gc(R.color.deviationblack); // "="
if (autosensData.pastSensitivity.equals("C")) color = MainApp.gc(R.color.deviationgrey);
if (autosensData.pastSensitivity.equals("+")) color = MainApp.gc(R.color.deviationgreen);
if (autosensData.pastSensitivity.equals("-")) color = MainApp.gc(R.color.deviationred);
if (autosensData.type.equals("") || autosensData.type.equals("non-meal")) {
if (autosensData.pastSensitivity.equals("C"))
color = MainApp.gc(R.color.deviationgrey);
if (autosensData.pastSensitivity.equals("+"))
color = MainApp.gc(R.color.deviationgreen);
if (autosensData.pastSensitivity.equals("-"))
color = MainApp.gc(R.color.deviationred);
} else if (autosensData.type.equals("uam")) {
color = MainApp.gc(R.color.uam);
} else if (autosensData.type.equals("csf")) {
color = MainApp.gc(R.color.deviationgrey);
}
devArray.add(new DeviationDataPoint(time, autosensData.deviation, color, devScale));
maxDevValueFound = Math.max(maxDevValueFound, Math.abs(autosensData.deviation));
}

View file

@ -5,7 +5,6 @@ import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@ -15,6 +14,7 @@ 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.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -81,6 +81,8 @@ public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInte
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = "";
int index = 0;
@ -97,8 +99,20 @@ public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInte
continue;
}
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.validDeviation ? autosensData.deviation : 0d;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d);
deviationsArray.add(deviation);
if (deviationsArray.size() > hoursForDetection * 60 / 5)
deviationsArray.remove(0);

View file

@ -14,6 +14,7 @@ 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.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -81,6 +82,8 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = "";
int index = 0;
@ -97,8 +100,20 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
continue;
}
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.validDeviation ? autosensData.deviation : 0d;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d);
deviationsArray.add(deviation);
if (deviationsArray.size() > hoursForDetection * 60 / 5)
deviationsArray.remove(0);

View file

@ -0,0 +1,197 @@
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.db.CareportalEvent;
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();
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<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
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;
}
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.validDeviation ? autosensData.deviation : 0d;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
deviationsArray.add(deviation);
for (int i = 0; i < autosensData.extraDeviation.size(); i++)
deviationsArray.add(autosensData.extraDeviation.get(i));
if (deviationsArray.size() > 96)
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++;
}
// when we have less than 8h worth of deviation data, add up to 90m of zero deviations
// this dampens any large sensitivity changes detected based on too little data, without ignoring them completely
log.debug("Using most recent " + deviationsArray.size() + " deviations");
if (deviationsArray.size() < 96) {
int pad = Math.round((1 - deviationsArray.size() / 96) * 18);
log.debug("Adding " + pad + " more zero deviations");
for (int d = 0; d < pad; d++) {
//process.stderr.write(".");
deviationsArray.add(0d);
}
}
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.01) {
if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.01)) >= 0 && IobCobCalculatorPlugin.percentile(deviations, i) < 0) {
if (Config.logAutosensData)
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (>50% = sensitivity)");
}
if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.01)) > 0 && IobCobCalculatorPlugin.percentile(deviations, i) <= 0) {
if (Config.logAutosensData)
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (>50% = resistance)");
}
}
double pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50);
double pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.50);
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;
}
}

View file

@ -6,11 +6,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -79,6 +81,8 @@ public class SensitivityWeightedAveragePlugin extends PluginBase implements Sens
return new AutosensResult();
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
String pastSensitivity = "";
int index = 0;
LongSparseArray<Double> data = new LongSparseArray<>();
@ -101,11 +105,23 @@ public class SensitivityWeightedAveragePlugin extends PluginBase implements Sens
continue;
}
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
data.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.validDeviation ? autosensData.deviation : 0d;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
//data.append(autosensData.time);
long reverseWeight = (toTime - autosensData.time) / (5 * 60 * 1000L);
data.append(reverseWeight, autosensData.nonEqualDeviation ? autosensData.deviation : 0d);
data.append(reverseWeight, deviation);
//weights += reverseWeight;
//weightedsum += reverseWeight * (autosensData.nonEqualDeviation ? autosensData.deviation : 0d);
//weightedsum += reverseWeight * (autosensData.validDeviation ? autosensData.deviation : 0d);
pastSensitivity += autosensData.pastSensitivity;

View file

@ -136,7 +136,7 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
llm = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(llm);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false));
RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEvents(false));
recyclerView.setAdapter(adapter);
refreshFromNS = (Button) view.findViewById(R.id.careportal_refreshfromnightscout);
@ -185,7 +185,7 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false)), false);
recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEvents(false)), false);
}
});
}

View file

@ -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_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_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_source_dexcom_g5">Receive BG values from the patched Dexcom G5 app.</string>
<string name="description_source_glimp">Receive BG values from Glimp.</string>
@ -666,6 +667,7 @@
<string name="configbuilder_sensitivity_description">Which sensitivity algorithm should be used?</string>
<string name="sensitivity_shortname">SENS</string>
<string name="sensitivityoref0">Sensitivity Oref0</string>
<string name="sensitivityoref1">Sensitivity Oref1</string>
<string name="sensitivityaaps">Sensitivity AAPS</string>
<string name="absorptionsettings_title">Absorption settings</string>
<string name="key_absorption_maxtime" translatable="false">absorption_maxtime</string>
@ -1115,7 +1117,7 @@
<string name="readstatus">Read status</string>
<string name="adjustprofileinns">Changes must be done in NS</string>
<string name="exitwizard">Skip setup wizard</string>
<string name="setupwizard_bgsource_description">Where should blood glucose(BG) data be comming from ?\n</string>
<string name="setupwizard_bgsource_description">Where should blood glucose(BG) data be coming from ?\n</string>
<string name="setupwizard_loop_description">Press the button below to enable AndroidAPS to suggest/make basal changes</string>
<string name="setupwizard_objectives_description">Press the button below to enable Objectives. Look in the Objectives tab, after you finish this wizard, to make AndroidAPS completely functional.\n</string>
<string name="enableobjectives">Enable Objectives</string>
@ -1129,7 +1131,7 @@
<string name="diawarning">Please remember: new insulin profiles require DIA at least 5h. DIA 5-6h on new profile is equal to DIA 3h on old insulin profiles.</string>
<string name="bgsourcesetup">Configure BG source</string>
<string name="setupwizard_profile_description">Please select source of profile. If patient is a child you should use NS profile. If there is nobody following you on Nightscout you will probably prefer Local profile. Please remember that you are only selecting the profile source. To use it you must activate it by executing \"Profile switch\"</string>
<string name="setupwizard_aps_description">Select one from availables algorithms. They are sorted from oldest to newest. Newer algorithm is usualy more powerfull and more aggresive. Thus if you are new looper you may probably start with AMA and not with latest one. Do not forget to read the OpenAPS documentation and configure it before use.</string>
<string name="setupwizard_aps_description">Select one from availables algorithms. They are sorted from oldest to newest. Newer algorithm is usually more powerful and more aggresive. Thus if you are new looper you may probably start with AMA and not with latest one. Do not forget to read the OpenAPS documentation and configure it before use.</string>
<string name="startobjective">Start your first objective</string>
<string name="permission">Permission</string>
<string name="askforpermission">Ask for permission</string>
@ -1163,6 +1165,10 @@
<string name="nth_objective">%1$d. Objective</string>
<string name="poctech">Poctech</string>
<string name="description_source_poctech">Receive BG values from Poctech app</string>
<string translatable="false" name="key_high_temptarget_raises_sensitivity">high_temptarget_raises_sensitivity</string>
<string translatable="false" name="key_low_temptarget_lowers_sensitivity">low_temptarget_lowers_sensitivity</string>
<string name="high_temptarget_raises_sensitivity_summary"><![CDATA[Raise sensitivity for temptargets >= 100]]></string>
<string name="low_temptarget_lowers_sensitivity_summary"><![CDATA[Lower sensitivity for temptargets < 100]]></string>
<string name="combo_invalid_setup">Invalid pump setup, check the docs and verify that the Quick Info menu is named "QUICK INFO" using the 360 configuration software.</string>
<string name="custom">Custom</string>

View 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>

View file

@ -85,6 +85,18 @@
android:summary="@string/enableuam_summary"
android:title="@string/enableuam" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_high_temptarget_raises_sensitivity"
android:summary="@string/high_temptarget_raises_sensitivity_summary"
android:title="@string/key_high_temptarget_raises_sensitivity" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_low_temptarget_lowers_sensitivity"
android:summary="@string/low_temptarget_lowers_sensitivity_summary"
android:title="@string/key_low_temptarget_lowers_sensitivity" />
<PreferenceScreen android:title="@string/advancedsettings_title">
<Preference android:summary="@string/openapsama_link_to_preferncejson_doc_txt">