Skip to content

Commit

Permalink
Glucose Meter: Groundwork for opportunistic calibration improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
jamorham committed Feb 9, 2017
1 parent 1e93a35 commit da73c89
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 6 deletions.
19 changes: 14 additions & 5 deletions app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ public static BgReading create(double raw_data, double filtered_data, Context co
// used when we are not fast inserting data
if (!quick) {
bgReading.perform_calculations();

if (JoH.ratelimit("opportunistic-calibration", 60)) {
BloodTest.opportunisticCalibration();
}

context.startService(new Intent(context, Notifications.class));
}
BgSendQueue.handleNewBgReading(bgReading, "create", context, Home.get_follower(), quick);
Expand Down Expand Up @@ -872,8 +877,12 @@ private static void FixCalibration(BgReading bgr) {
bgr.calibration = calibration;
}
}

public static void bgReadingInsertFromJson(String json, boolean do_notification) {
if ((json == null) || (json.length() == 0)) {
Log.e(TAG, "bgreadinginsertfromjson passed a null or zero length json");
return;
}
BgReading bgr = fromJSON(json);
if (bgr != null) {
try {
Expand Down Expand Up @@ -1166,8 +1175,8 @@ public void calculateAgeAdjustedRawValue(){
}
}

public void find_new_raw_curve() {
List<BgReading> last_3 = BgReading.latest(3);
void find_new_raw_curve() {
final List<BgReading> last_3 = BgReading.latest(3);
if ((last_3 != null) && (last_3.size() == 3)) {

final BgReading latest = last_3.get(0);
Expand Down Expand Up @@ -1222,8 +1231,8 @@ public void find_new_raw_curve() {
}
}
public static double weightedAverageRaw(double timeA, double timeB, double calibrationTime, double rawA, double rawB) {
double relativeSlope = (rawB - rawA)/(timeB - timeA);
double relativeIntercept = rawA - (relativeSlope * timeA);
final double relativeSlope = (rawB - rawA)/(timeB - timeA);
final double relativeIntercept = rawA - (relativeSlope * timeA);
return ((relativeSlope * calibrationTime) + relativeIntercept);
}

Expand Down
113 changes: 112 additions & 1 deletion app/src/main/java/com/eveningoutpost/dexdrip/Models/BloodTest.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package com.eveningoutpost.dexdrip.Models;

import android.provider.BaseColumns;
import android.util.Log;

import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Delete;
import com.activeandroid.query.Select;
import com.activeandroid.util.SQLiteUtils;
import com.eveningoutpost.dexdrip.AddCalibration;
import com.eveningoutpost.dexdrip.GlucoseMeter.GlucoseReadingRx;
import com.eveningoutpost.dexdrip.Home;
import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;
import com.eveningoutpost.dexdrip.UtilityModels.Constants;
import com.eveningoutpost.dexdrip.calibrations.CalibrationAbstract;
import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration;
import com.eveningoutpost.dexdrip.messages.BloodTestMessage;
import com.eveningoutpost.dexdrip.messages.BloodTestMultiMessage;
import com.eveningoutpost.dexdrip.xdrip;
import com.google.common.math.DoubleMath;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
Expand Down Expand Up @@ -277,11 +285,114 @@ public static List<BloodTest> latestForGraph(int number, long startTime, long en
}
}

synchronized static void opportunisticCalibration() {
if (Home.getPreferencesBooleanDefaultFalse("bluetooth_meter_for_calibrations_auto")) {
final BloodTest bt = last();
if (bt == null) {
Log.d(TAG, "opportunistic: No blood tests");
return;
}
if (JoH.msSince(bt.timestamp) > Constants.DAY_IN_MS) {
Log.d(TAG, "opportunistic: Blood test older than 1 days ago");
return;
}

final Calibration calibration = Calibration.lastValid();
if (calibration == null) {
Log.d(TAG, "opportunistic: No calibrations");
return;
}

if (JoH.msSince(calibration.timestamp) < Constants.HOUR_IN_MS) {
Log.d(TAG, "opportunistic: Last calibration less than 1 hour ago");
return;
}

if (bt.timestamp <= calibration.timestamp) {
Log.d(TAG, "opportunistic: Blood test isn't more recent than last calibration");
return;
}

// get closest bgreading - must be within dexcom period and locked to sensor
final BgReading bgReading = BgReading.getForPreciseTimestamp(bt.timestamp + (AddCalibration.estimatedInterstitialLagSeconds * 1000), BgGraphBuilder.DEXCOM_PERIOD);
if (bgReading == null) {
Log.d(TAG, "opportunistic: No matching bg reading");
return;
}

if (!CalibrationRequest.isSlopeFlatEnough(bgReading)) {
Log.d(TAG, "opportunistic: Slope is not flat enough at: " + JoH.dateTimeText(bgReading.timestamp));
return;
}

// TODO store evaluation failure for this record in cache for future optimization

// TODO Check we have prior reading as well perhaps

UserError.Log.ueh(TAG, "Opportunistic calibration for Blood Test at " + JoH.dateTimeText(bt.timestamp) + " of " + BgGraphBuilder.unitized_string_with_units_static(bt.mgdl) + " matching sensor slope at: " + JoH.dateTimeText(bgReading.timestamp));
final long time_since = JoH.msSince(bt.timestamp);


Log.d(TAG, "opportunistic: attempting auto calibration");
Home.startHomeWithExtra(xdrip.getAppContext(),
Home.BLUETOOTH_METER_CALIBRATION,
BgGraphBuilder.unitized_string_static(bt.mgdl),
Long.toString(time_since),
"auto");
}
}

public static String evaluateAccuracy(long period) {

// CACHE??
// TODO Plugins by time

final List<BloodTest> bloodTests = latestForGraph(1000, JoH.tsl() - period, JoH.tsl() - AddCalibration.estimatedInterstitialLagSeconds);
final List<Double> difference = new ArrayList<>();
final List<Double> plugin_difference = new ArrayList<>();
if ((bloodTests == null) || (bloodTests.size() == 0)) return null;

final boolean show_plugin = true;
final CalibrationAbstract plugin = (show_plugin) ? PluggableCalibration.getCalibrationPluginFromPreferences() : null;
final CalibrationAbstract.CalibrationData cd = (plugin != null) ? plugin.getCalibrationData() : null;

for (BloodTest bt : bloodTests) {
final BgReading bgReading = BgReading.getForPreciseTimestamp(bt.timestamp + (AddCalibration.estimatedInterstitialLagSeconds * 1000), BgGraphBuilder.DEXCOM_PERIOD);

if (bgReading != null) {
final double diff = Math.abs(bgReading.calculated_value - bt.mgdl);
difference.add(diff);
if (d) Log.d(TAG, "Evaluate Accuracy: difference: " + JoH.qs(diff));

if ((plugin != null) && (cd != null)) {
final double plugin_diff = Math.abs(bt.mgdl - plugin.getGlucoseFromBgReading(bgReading, cd));
plugin_difference.add(plugin_diff);
if (d)
Log.d(TAG, "Evaluate Plugin Accuracy: difference: " + JoH.qs(plugin_diff));
}
}
}
double avg = DoubleMath.mean(difference);
Log.d(TAG, "Average accuracy: " + accuracyAsString(avg) + " (" + JoH.qs(avg, 5) + ")");

if (plugin_difference.size() > 0) {
double plugin_avg = DoubleMath.mean(plugin_difference);
Log.d(TAG, "Plugin Average accuracy: " + accuracyAsString(plugin_avg) + " (" + JoH.qs(plugin_avg, 5) + ")");
return accuracyAsString(plugin_avg) + " / " + accuracyAsString(avg);
}
return accuracyAsString(avg);
}

public static String accuracyAsString(double avg) {
final boolean domgdl = Home.getPreferencesStringWithDefault("units", "mgdl").equals("mgdl");
// +- symbol
return "\u00B1" + (!domgdl ? JoH.qs(avg * Constants.MGDL_TO_MMOLL, 2) + " mmol" : JoH.qs(avg, 1) + " mgdl");
}

public static List<BloodTest> cleanup(int retention_days) {
return new Delete()
.from(BloodTest.class)
.where("timestamp < ?", JoH.tsl() - (retention_days * 86400000L))
.where("timestamp < ?", JoH.tsl() - (retention_days * Constants.DAY_IN_MS))
.execute();
}

Expand Down

0 comments on commit da73c89

Please sign in to comment.