Merge pull request #1992 from nightscout/dynisf

DynISF: move calc to kotlin, cleanup
This commit is contained in:
Milos Kozak 2022-08-06 13:09:41 +02:00 committed by GitHub
commit 5de6f0df11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 178 additions and 264 deletions

View file

@ -203,16 +203,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
// 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default)
}
var profile_sens = round(profile.sens,1)
var sens = profile.sens;
var now = new Date().getHours();
if (now < 1){
now = 1;}
else {
console.error("Time now is "+now+"; ");
}
//*********************************************************************************
//** Start of Dynamic ISF code for predictions **
//*********************************************************************************
@ -221,96 +211,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
console.error( " Dynamic ISF version Beta 1.6.5 ");
console.error("---------------------------------------------------------");
if (meal_data.TDDAIMI7){
var tdd7 = meal_data.TDDAIMI7;
}
else{
var tdd7 = ((basal * 12)*100)/21;
}
console.error("7-day average TDD is: " +tdd7+ "; ");
if (meal_data.TDDLast24){
var tdd_24 = meal_data.TDDLast24;
}
else {
var tdd_24 = (( basal * 24 ) * 2.8);
}
if (meal_data.TDDPUMP){
var tdd_pump = ( (meal_data.TDDPUMP / now ) * 24);
}
else {
var tdd_pump = (( basal * 24 ) * 2.8);
}
console.log("Rolling TDD for last 24 hours is: "+tdd_24+"; ");
/*var tdd_pump_now = meal_data.TDDPUMP;
var tdd_pump = ( tdd_pump_now / (now / 24));*/
//var TDD = (tdd7 * 0.4) + (tdd_pump * 0.6);
var tdd1 = meal_data.TDDAIMI1;
var tdd_4 = meal_data.TDDLast4;
var tdd8to4 = meal_data.TDD4to8;
var tdd_last8_wt = ( ( ( 1.4 * tdd_4) + ( 0.6 * tdd8to4) ) * 3 );
console.error("Rolling 8 hours weight average: "+tdd_last8_wt+"; ");
console.error("1-day average TDD is: "+tdd1+"; ");
console.error("7-day average TDD is: " +tdd7+ "; ");
//TDD = ( tdd_last8_wt * 0.6) + ( tdd7 * 0.4 );
var TDD = ( tdd_last8_wt * 0.33 ) + ( tdd7 * 0.34 ) + (tdd1 * 0.33);
console.log("TDD = " +TDD+ " using average of 7-day, 1-day and weighted 8hr average");
//var ins_val = 75;
var insulin = profile.insulinType;
console.log("Insulin Peak = "+profile.insulinPeak+"; ");
//console.log("Initial insulin value for ISF: "+ins_val+"; ");
//console.log("Current value for insulin: "+insulin+"; ");
var ins_val;
if (profile.insulinPeak > 65) { // lyumjev peak: 45
ins_val = 55;
} else if (profile.insulinPeak > 50 ){ // ultra rapid peak: 55
ins_val = 65;
} else {
ins_val = 75; // rapid peak: 75
}
console.log("For "+profile.insulinType+" (insulin peak: "+profile.insulinPeak+") divisor is: "+ins_val+"; ");
console.log("Insulin value for ISF based on profile: "+ins_val+"; ");
var dynISFadjust = profile.DynISFAdjust;
dynISFadjust = ( dynISFadjust / 100 );
TDD = ( dynISFadjust * TDD );
var variable_sens = 1800 / ( TDD * (Math.log(( bg / ins_val ) + 1 ) ) );
variable_sens = round(variable_sens,1);
if (dynISFadjust > 1 ) {
console.log("TDD adjustment factor is: " +dynISFadjust+"; ");
console.log("TDD adjusted to "+TDD+" using adjustment factor of "+dynISFadjust+"; ");
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
}
else if (dynISFadjust < 1 ){
console.log("TDD adjustment factor is: " +dynISFadjust+"; ");
console.log("TDD adjusted to "+TDD+" using adjustment factor of "+dynISFadjust+"; ");
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
} else {
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
}
sens = variable_sens;
var variable_sens = profile.variable_sens;
var TDD = profile.TDD;
var insulinDivisor = profile.insulinDivisor;
//*********************************************************************************
//** End of Dynamic ISF code for predictions **
//*********************************************************************************
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget
|| profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
// w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
// e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
//sensitivityRatio = 2/(2+(target_bg-normalTarget)/40);
@ -320,47 +231,29 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
sensitivityRatio = round(sensitivityRatio,2);
console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
sens = sens / sensitivityRatio ;
sens = round(sens, 1);
console.log("ISF from "+variable_sens+" to "+sens+ "due to temp target; ");
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
sensitivityRatio = autosens_data.ratio;
console.log("Autosens ratio: "+sensitivityRatio+"; ");
}
else {
sensitivityRatio = ( meal_data.TDD24 / tdd7 );
}
if (sensitivityRatio > 1) {
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
sensitivityRatio = round(sensitivityRatio,2);
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
}
else if( sensitivityRatio < 1) {
sensitivityRatio = Math.max(sensitivityRatio, profile.autosens_min);
sensitivityRatio = round(sensitivityRatio,2);
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
}
else {
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
}
if (sensitivityRatio && profile.openapsama_useautosens === true) {
if (sensitivityRatio) {
basal = profile.current_basal * sensitivityRatio;
basal = round_basal(basal, profile);
if (basal !== profile_current_basal) {
console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
} else {
console.log("Autosens disabled. Basal unchanged: "+basal+"; ");
console.log("Basal unchanged: "+basal+"; ");
}
}
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
if (profile.temptargetSet) {
//console.log("Temp Target set, not adjusting with autosens; ");
} else {
if ( profile.sensitivity_raises_target && sensitivityRatio < 1 && profile.openapsama_useautosens === true || profile.resistance_lowers_target && sensitivityRatio > 1 && profile.openapsama_useautosens === true) {
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
if ( profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1 ) {
// with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range
min_bg = round((min_bg - 60) / sensitivityRatio) + 60;
max_bg = round((max_bg - 60) / sensitivityRatio) + 60;
var new_target_bg = round((target_bg - 60) / sensitivityRatio) + 60;
min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
// don't allow target_bg below 80
new_target_bg = Math.max(80, new_target_bg);
if (target_bg === new_target_bg) {
@ -372,7 +265,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
}
}
if (typeof iob_data === 'undefined' ) {
rT.error ='Error: iob_data undefined. ';
return rT;
@ -401,8 +293,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
console.error("; CR:",profile.carb_ratio);
var sens = variable_sens
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
var lastTempAge;
@ -413,7 +304,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
}
//console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m");
var tempModulus = (lastTempAge + currenttemp.duration) % 30;
console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
console.error("currenttemp:",round(currenttemp.rate,2),"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
rT.temp = 'absolute';
rT.deliverAt = deliverAt;
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate !== iob_data.lastTemp.rate && lastTempAge > 10 && currenttemp.duration ) {
@ -832,21 +723,21 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
var fSensBG = Math.min(minPredBG,bg);
if (bg > target_bg && glucose_status.delta < 3 && glucose_status.delta > -3 && glucose_status.short_avgdelta > -3 && glucose_status.short_avgdelta < 3 && eventualBG > target_bg && eventualBG < bg ) {
var future_sens = ( 1800 / (Math.log((((fSensBG * 0.5) + (bg * 0.5))/ins_val)+1)*TDD));
var future_sens = ( 1800 / (Math.log((((fSensBG * 0.5) + (bg * 0.5))/insulinDivisor)+1)*TDD));
//var future_sens_old = ( 277700 / (TDD * ((bg * 0.5) + (eventualBG * 0.5 ))));
console.log("Future state sensitivity is " +future_sens+" based on eventual and current bg due to flat glucose level above target");
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
}
else if( glucose_status.delta > 0 && eventualBG > target_bg || eventualBG > bg ) {
var future_sens = ( 1800 / (Math.log((bg/ins_val)+1)*TDD));
else if( glucose_status.delta > 0 && eventualBG > target_bg || eventualBG > bg) {
var future_sens = ( 1800 / (Math.log((bg/insulinDivisor)+1)*TDD));
//var future_sens_old = ( 277700 / (TDD * bg));
console.log("Future state sensitivity is " +future_sens+" using current bg due to small delta or variation");
rT.reason += "Dosing sensitivity: " +future_sens+" using current BG;";
}
else {
var future_sens = ( 1800 / (Math.log((fSensBG/ins_val)+1)*TDD));
var future_sens = ( 1800 / (Math.log((fSensBG/insulinDivisor)+1)*TDD));
//var future_sens_old = ( 277700 / (TDD * eventualBG));
console.log("Future state sensitivity is " +future_sens+" based on eventual bg due to -ve delta");
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
@ -854,9 +745,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
future_sens = round(future_sens,1);
var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs;
// if we have COB and UAM is enabled, average both
if ( minUAMPredBG < 999 && minCOBPredBG < 999 ) {
@ -1079,11 +967,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
}
}
// calculate 30m low-temp required to get projected BG up to target
// multiply by 2 to low-temp faster for increased hypo safety
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / future_sens);
insulinReq = round( insulinReq , 2);
// calculate naiveInsulinReq based on naive_eventualBG

View file

@ -22,6 +22,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.stats.TddCalculator
import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.AAPSLogger
@ -36,6 +37,7 @@ import java.io.IOException
import java.lang.reflect.InvocationTargetException
import java.nio.charset.StandardCharsets
import javax.inject.Inject
import kotlin.math.ln
class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
@ -194,10 +196,6 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
this.profile.put("lgsThreshold", Profile.toMgdl(sp.getDouble(R.string.key_lgs_threshold, 65.0)))
val insulin = activePlugin.activeInsulin
val insulinType = insulin.friendlyName
val insulinPeak = insulin.peak
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
this.profile.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));
@ -227,9 +225,6 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
this.profile.put("DynISFAdjust", SafeParse.stringToDouble(sp.getString(R.string.key_DynISFAdjust, "100")))
this.profile.put("insulinType", insulinType)
this.profile.put("insulinPeak", insulinPeak)
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
//set the min SMB amount to be the amount set by the pump.
this.profile.put("bolus_increment", pumpBolusStep)
@ -237,8 +232,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
this.profile.put("current_basal", basalRate)
this.profile.put("temptargetSet", tempTargetSet)
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
this.profile.put("autosens_min", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_min, "0.8")))
this.profile.put("openapsama_useautosens", sp.getBoolean(R.string.key_openapsama_useautosens, false))
this.profile.put("autosens_min", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_min, "0.7")))
//set the min SMB amount to be the amount set by the pump.
if (profileFunction.getUnits() == GlucoseUnit.MMOL) {
this.profile.put("out_units", "mmol/L")
@ -270,19 +264,53 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
this.mealData.put("TDDAIMI1", tddCalculator.averageTDD(tddCalculator.calculate(1))?.totalAmount)
this.mealData.put("TDDAIMI7", tddCalculator.averageTDD(tddCalculator.calculate(7))?.totalAmount)
this.mealData.put("TDDLast4", tddCalculator.calculateDaily(-4, 0).totalAmount)
this.mealData.put("TDD4to8", tddCalculator.calculateDaily(-8, -4).totalAmount)
this.mealData.put("TDD24", tddCalculator.calculateDaily(-24, 0).totalAmount)
val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(1))?.totalAmount
val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(7))?.totalAmount
val tddLast24H = tddCalculator.calculateDaily(-24, 0).totalAmount
val tddLast4H = tddCalculator.calculateDaily(-4, 0).totalAmount
val tddLast8to4H = tddCalculator.calculateDaily(-8, -4).totalAmount
val tddWeightedFromLast8H = ((1.4 * tddLast4H) + (0.6 * tddLast8to4H)) * 3
// console.error("Rolling 8 hours weight average: " + tdd_last8_wt + "; ");
// console.error("1-day average TDD is: " + tdd1 + "; ");
// console.error("7-day average TDD is: " + tdd7 + "; ");
var tdd =
if (tdd1D != null && tdd7D != null) (tddWeightedFromLast8H * 0.33) + (tdd7D * 0.34) + (tdd1D * 0.33)
else tddWeightedFromLast8H
// console.log("TDD = " + TDD + " using average of 7-day, 1-day and weighted 8hr average");
if (constraintChecker.isAutosensModeEnabled().value()) {
autosensData.put("ratio", autosensDataRatio)
} else {
autosensData.put("ratio", 1.0)
// console.log("Insulin Peak = " + insulin.peak + "; ");
val insulin = activePlugin.activeInsulin
val insulinDivisor = when {
insulin.peak > 65 -> 55 // lyumjev peak: 45
insulin.peak > 50 -> 65 // ultra rapid peak: 55
else -> 75 // rapid peak: 75
}
// console.log("For " + insulin.friendlyName + " (insulin peak: " + insulin.peak + ") insulin divisor is: " + ins_val + "; ");
val dynISFadjust = SafeParse.stringToDouble(sp.getString(R.string.key_DynISFAdjust, "100")) / 100.0
tdd *= dynISFadjust
var variableSensitivity = 1800 / (tdd * (ln((glucoseStatus.glucose / insulinDivisor) + 1)))
variableSensitivity = Round.roundTo(variableSensitivity, 0.1)
if (dynISFadjust != 1.0) {
// console.log("TDD adjusted to " + TDD + " using adjustment factor of " + dynISFadjust + "; ");
}
// console.log("Current sensitivity for predictions is " + variable_sens + " based on current bg");
this.profile.put("variable_sens", variableSensitivity)
this.profile.put("insulinDivisor", insulinDivisor)
this.profile.put("TDD", tdd)
if (sp.getBoolean(R.string.key_adjust_sensitivity, false) && tdd7D != null)
autosensData.put("ratio", tddLast24H / tdd7D)
else
autosensData.put("ratio", 1.0)
this.microBolusAllowed = microBolusAllowed
smbAlwaysAllowed = advancedFiltering
currentTime = now

View file

@ -1084,7 +1084,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private fun updateSensitivity() {
_binding ?: return
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) {
if (constraintChecker.isAutosensModeEnabled().value()) {
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
} else {
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_x_swap_vert)

View file

@ -204,7 +204,7 @@ class Widget : AppWidgetProvider() {
}
}
fun updateProfile(views: RemoteViews) {
private fun updateProfile(views: RemoteViews) {
val profileTextColor =
profileFunction.getProfile()?.let {
if (it is ProfileSealed.EPS) {
@ -226,7 +226,7 @@ class Widget : AppWidgetProvider() {
}
private fun updateSensitivity(views: RemoteViews) {
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value())
if (constraintChecker.isAutosensModeEnabled().value())
views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_swap_vert_black_48dp_green)
else
views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_x_swap_vert)

View file

@ -1251,6 +1251,7 @@
<string name="blocked_by_connectivity">Blocked by connectivity options</string>
<string name="no_watch_connected">(No Watch Connected)</string>
<string name="error_asking_for_permissions">Error asking for permissions</string>
<string name="key_adjust_sensitivity" translatable="false">dynisf_adjust_sensitivity</string>
<string name="dynisf_adjust_sensitivity">Adjust sensitivity and BG</string>
</resources>

View file

@ -30,7 +30,7 @@
<SwitchPreference
android:defaultValue="false"
android:key="openapsama_useautosens"
android:key="@string/key_openapsama_useautosens"
android:title="@string/openapsama_useautosens" />
<SwitchPreference

View file

@ -51,8 +51,8 @@
<SwitchPreference
android:defaultValue="false"
android:key="openapsama_useautosens"
android:title="@string/openapsama_useautosens" />
android:key="@string/key_adjust_sensitivity"
android:title="@string/dynisf_adjust_sensitivity" />
<SwitchPreference
android:defaultValue="false"