250 lines
9.4 KiB
Java
250 lines
9.4 KiB
Java
package com.eveningoutpost.dexdrip.Models;
|
|
|
|
import android.content.SharedPreferences;
|
|
import android.preference.PreferenceManager;
|
|
import android.util.Log;
|
|
|
|
import com.eveningoutpost.dexdrip.Home;
|
|
import com.eveningoutpost.dexdrip.UtilityModels.Constants;
|
|
import com.eveningoutpost.dexdrip.UtilityModels.Pref;
|
|
import com.eveningoutpost.dexdrip.profileeditor.ProfileEditor;
|
|
import com.eveningoutpost.dexdrip.profileeditor.ProfileItem;
|
|
import com.eveningoutpost.dexdrip.xdrip;
|
|
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Created by jamorham on 04/01/16.
|
|
*/
|
|
|
|
// user profile for insulin related parameters which can be configured and set at times of day
|
|
// currently a placeholder with hardcoded values
|
|
|
|
// TODO Proper support for MG/DL
|
|
|
|
|
|
public class Profile {
|
|
|
|
private final static String TAG = "jamorham pred";
|
|
public static double minimum_shown_iob = 0.005;
|
|
public static double minimum_shown_cob = 0.01;
|
|
public static double minimum_insulin_recommendation = 0.1;
|
|
public static double minimum_carb_recommendation = 1;
|
|
public static double scale_factor = 18;
|
|
private static double the_carb_ratio = 10; // now defunct
|
|
private static double stored_default_sensitivity = 54; // now defunct
|
|
private static double stored_default_absorption_rate = 35;
|
|
private static double stored_default_insulin_action_time = 3.0;
|
|
private static double stored_default_carb_delay_minutes = 15;
|
|
private static boolean preferences_loaded = false;
|
|
private static List<ProfileItem> profileItemList;
|
|
|
|
public static double getSensitivity(double when) {
|
|
final double sensitivity = findItemListElementForTime(when).sensitivity;
|
|
// Log.d(TAG,"sensitivity: "+sensitivity);
|
|
return sensitivity;
|
|
// expressed in native units lowering effect of 1U
|
|
}
|
|
|
|
public static void setSensitivityDefault(double value) {
|
|
// sanity check goes here
|
|
stored_default_sensitivity = value;
|
|
}
|
|
|
|
public static void setInsulinActionTimeDefault(double value) {
|
|
// sanity check goes here
|
|
if (value < 0.1) return;
|
|
if (value > 24) return;
|
|
stored_default_insulin_action_time = value;
|
|
}
|
|
|
|
static double getCarbAbsorptionRate(double when) {
|
|
return stored_default_absorption_rate; // carbs per hour
|
|
}
|
|
|
|
public static void setCarbAbsorptionDefault(double value) {
|
|
// sanity check goes here
|
|
if (value < 0.01) return;
|
|
stored_default_absorption_rate = value;
|
|
}
|
|
|
|
static double insulinActionTime(double when) {
|
|
return stored_default_insulin_action_time;
|
|
}
|
|
|
|
static double carbDelayMinutes(double when) {
|
|
return stored_default_carb_delay_minutes;
|
|
}
|
|
|
|
static double maxLiverImpactRatio(double when) {
|
|
return 0.3; // how much can the liver block carbs going in to blood stream?
|
|
}
|
|
|
|
public static double getCarbRatio(double when) {
|
|
return findItemListElementForTime(when).carb_ratio;
|
|
//return the_carb_ratio; // g per unit
|
|
}
|
|
|
|
|
|
private static void populateProfile() {
|
|
if (profileItemList == null) {
|
|
profileItemList = ProfileEditor.loadData(false);
|
|
Log.d(TAG, "Loaded profile data, blocks: " + profileItemList.size());
|
|
}
|
|
}
|
|
|
|
public static void invalidateProfile() {
|
|
profileItemList = null;
|
|
}
|
|
|
|
private static ProfileItem findItemListElementForTime(double when) {
|
|
populateProfile();
|
|
// TODO does this want/need a hash table lookup cache?
|
|
if (profileItemList.size() == 1)
|
|
profileItemList.get(0); // always will be first/only element.
|
|
// get time of day
|
|
final int min = ProfileItem.timeStampToMin(when);
|
|
// find element
|
|
for (ProfileItem item : profileItemList) {
|
|
if (item.start_min < item.end_min) {
|
|
// regular
|
|
if ((item.start_min <= min) && (item.end_min >= min)) {
|
|
// Log.d(TAG, "Match on item " + item.getTimePeriod() + " " + profileItemList.indexOf(item));
|
|
return item;
|
|
}
|
|
} else {
|
|
// item spans midnight
|
|
if ((min >= item.start_min) || (min <= item.end_min)) {
|
|
// Log.d(TAG, "midnight span Match on item " + item.getTimePeriod() + " " + profileItemList.indexOf(item));
|
|
return item;
|
|
}
|
|
}
|
|
}
|
|
Log.wtf(TAG, "Null return from findItemListElementForTime");
|
|
return null; // should be impossible
|
|
}
|
|
|
|
|
|
static public void setDefaultCarbRatio(Double value) {
|
|
if (value <= 0) {
|
|
Log.e(TAG, "Invalid default carb ratio: " + value);
|
|
return;
|
|
}
|
|
the_carb_ratio = value; // g per unit
|
|
}
|
|
|
|
static double getLiverSensRatio(double when) {
|
|
return 2.0;
|
|
}
|
|
|
|
public static void validateTargetRange() {
|
|
final double default_target_glucose = tolerantParseDouble(Pref.getString("plus_target_range", Double.toString(5.5 / scale_factor)));
|
|
if (default_target_glucose > tolerantParseDouble(Pref.getString("highValue", Double.toString(5.5 / scale_factor)))) {
|
|
Pref.setString("plus_target_range", JoH.qs(default_target_glucose * Constants.MGDL_TO_MMOLL, 1));
|
|
UserError.Log.i(TAG, "Converted initial value of target glucose to mmol");
|
|
}
|
|
}
|
|
|
|
static double getTargetRangeInMmol(double when) {
|
|
// return tolerantParseDouble(Home.getString("plus_target_range",Double.toString(5.5 / scale_factor)));
|
|
return getTargetRangeInUnits(when) / scale_factor;
|
|
}
|
|
|
|
public static double getTargetRangeInUnits(double when) {
|
|
return tolerantParseDouble(Pref.getString("plus_target_range", Double.toString(5.5 / scale_factor)));
|
|
//return getTargetRangeInMmol(when) * scale_factor; // TODO deal with rounding errors here? (3 decimal places?)
|
|
}
|
|
|
|
static double getCarbSensitivity(double when) {
|
|
return getCarbRatio(when) / getSensitivity(when);
|
|
}
|
|
|
|
static double getCarbsToRaiseByMmol(double mmol, double when) {
|
|
|
|
double result = getCarbSensitivity(when) * mmol;
|
|
return result;
|
|
}
|
|
|
|
static double getInsulinToLowerByMmol(double mmol, double when) {
|
|
return mmol / getSensitivity(when);
|
|
}
|
|
|
|
// take an average of carb suggestions when our scope is between two times
|
|
static double getCarbsToRaiseByMmolBetweenTwoTimes(double mmol, double whennow, double whenthen) {
|
|
double result = (getCarbsToRaiseByMmol(mmol, whennow) + getCarbsToRaiseByMmol(mmol, whenthen)) / 2;
|
|
UserError.Log.d(TAG, "GetCarbsToRaiseByMmolBetweenTwoTimes: " + JoH.qs(mmol) + " result: " + JoH.qs(result));
|
|
return result;
|
|
}
|
|
|
|
static double getInsulinToLowerByMmolBetweenTwoTimes(double mmol, double whennow, double whenthen) {
|
|
return (getInsulinToLowerByMmol(mmol, whennow) + getInsulinToLowerByMmol(mmol, whenthen)) / 2;
|
|
}
|
|
|
|
public static double[] evaluateEndGameMmol(double mmol, double endGameTime, double timeNow) {
|
|
double addcarbs = 0;
|
|
double addinsulin = 0;
|
|
final double target_mmol = getTargetRangeInMmol(endGameTime) * scale_factor;
|
|
double diff_mmol = target_mmol - mmol;
|
|
if (diff_mmol > 0) {
|
|
addcarbs = getCarbsToRaiseByMmolBetweenTwoTimes(diff_mmol, timeNow, endGameTime);
|
|
} else if (diff_mmol < 0) {
|
|
addinsulin = getInsulinToLowerByMmolBetweenTwoTimes(diff_mmol * -1, timeNow, endGameTime);
|
|
}
|
|
return new double[]{addcarbs, addinsulin};
|
|
}
|
|
|
|
public static void reloadPreferencesIfNeeded(SharedPreferences prefs) {
|
|
if (!preferences_loaded) reloadPreferences(prefs);
|
|
}
|
|
|
|
public static void reloadPreferences() {
|
|
Log.d(TAG, "Reloaded profile preferences");
|
|
reloadPreferences(PreferenceManager.getDefaultSharedPreferences(xdrip.getAppContext()));
|
|
}
|
|
|
|
public static synchronized void reloadPreferences(SharedPreferences prefs) {
|
|
validateTargetRange();
|
|
try {
|
|
Profile.setSensitivityDefault(tolerantParseDouble(prefs.getString("profile_insulin_sensitivity_default", "0")));
|
|
} catch (Exception e) {
|
|
if (JoH.ratelimit("invalid-insulin-profile", 60)) {
|
|
Home.toaststatic("Invalid insulin sensitivity");
|
|
}
|
|
}
|
|
try {
|
|
Profile.setDefaultCarbRatio(tolerantParseDouble(prefs.getString("profile_carb_ratio_default", "0")));
|
|
} catch (Exception e) {
|
|
if (JoH.ratelimit("invalid-insulin-profile", 60)) {
|
|
Home.toaststatic("Invalid default carb ratio!");
|
|
}
|
|
}
|
|
try {
|
|
Profile.setCarbAbsorptionDefault(tolerantParseDouble(prefs.getString("profile_carb_absorption_default", "0")));
|
|
} catch (Exception e) {
|
|
if (JoH.ratelimit("invalid-insulin-profile", 60)) {
|
|
Home.toaststatic("Invalid carb absorption rate");
|
|
}
|
|
}
|
|
try {
|
|
Profile.setInsulinActionTimeDefault(tolerantParseDouble(prefs.getString("xplus_insulin_dia", "3.0")));
|
|
} catch (Exception e) {
|
|
if (JoH.ratelimit("invalid-insulin-profile", 60)) {
|
|
Home.toaststatic("Invalid insulin action time");
|
|
}
|
|
}
|
|
profileItemList = null;
|
|
populateProfile();
|
|
preferences_loaded = true;
|
|
}
|
|
|
|
private static double tolerantParseDouble(String str) throws NumberFormatException {
|
|
return Double.parseDouble(str.replace(",", "."));
|
|
|
|
}
|
|
|
|
// TODO placeholder
|
|
public static double getBasalRate(final long when) {
|
|
return 0d;
|
|
}
|
|
|
|
} |