prelim commit
This commit is contained in:
parent
585f4e2bc2
commit
354071348c
2 changed files with 178 additions and 170 deletions
|
@ -31,14 +31,13 @@ function calculate_expected_delta(target_bg, eventual_bg, bgi) {
|
|||
// (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24
|
||||
var five_min_blocks = (2 * 60) / 5;
|
||||
var target_delta = target_bg - eventual_bg;
|
||||
var expectedDelta = round(bgi + (target_delta / five_min_blocks), 1);
|
||||
return expectedDelta;
|
||||
return /* expectedDelta */ round(bgi + (target_delta / five_min_blocks), 1);
|
||||
}
|
||||
|
||||
|
||||
function convert_bg(value, profile)
|
||||
{
|
||||
if (profile.out_units == "mmol/L")
|
||||
if (profile.out_units === "mmol/L")
|
||||
{
|
||||
return round(value / 18, 1).toFixed(1);
|
||||
}
|
||||
|
@ -48,10 +47,13 @@ function convert_bg(value, profile)
|
|||
}
|
||||
}
|
||||
|
||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data) {
|
||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime) {
|
||||
var rT = {}; //short for requestedTemp
|
||||
|
||||
var deliverAt = new Date();
|
||||
if (currentTime) {
|
||||
deliverAt = currentTime;
|
||||
}
|
||||
|
||||
if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
|
||||
rT.error ='Error: could not get current basal rate';
|
||||
|
@ -61,26 +63,39 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var basal = profile_current_basal;
|
||||
|
||||
var systemTime = new Date();
|
||||
if (currentTime) {
|
||||
systemTime = currentTime;
|
||||
}
|
||||
var bgTime = new Date(glucose_status.date);
|
||||
var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1);
|
||||
|
||||
var bg = glucose_status.glucose;
|
||||
if (bg < 39) { //Dexcom is in ??? mode or calibrating
|
||||
rT.reason = "CGM is calibrating or in ??? state";
|
||||
var noise = glucose_status.noise;
|
||||
// 38 is an xDrip error state that usually indicates sensor failure
|
||||
// all other BG values between 11 and 37 mg/dL reflect non-error-code BG values, so we should zero temp for those
|
||||
if (bg <= 10 || bg === 38 || noise >= 3) { //Dexcom is in ??? mode or calibrating, or xDrip reports high noise
|
||||
rT.reason = "CGM is calibrating, in ??? state, or noise is high";
|
||||
}
|
||||
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
||||
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
|
||||
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
||||
} else if ( bg > 60 && glucose_status == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) {
|
||||
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||
rT.reason = "CGM was just calibrated";
|
||||
} else {
|
||||
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
||||
}
|
||||
}
|
||||
if (bg < 39 || minAgo > 12 || minAgo < -5) {
|
||||
if (currenttemp.rate >= basal) { // high temp is running
|
||||
rT.reason += ". Canceling high temp basal of "+currenttemp.rate;
|
||||
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && glucose_status == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) ) {
|
||||
if (currenttemp.rate > basal) { // high temp is running
|
||||
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||
rT.deliverAt = deliverAt;
|
||||
rT.temp = 'absolute';
|
||||
rT.duration = 0;
|
||||
rT.rate = 0;
|
||||
rT.duration = 30;
|
||||
rT.rate = basal;
|
||||
return rT;
|
||||
//return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
} else if ( currenttemp.rate == 0 && currenttemp.duration > 30 ) { //shorten long zero temps to 30m
|
||||
} else if ( currenttemp.rate === 0 && currenttemp.duration > 30 ) { //shorten long zero temps to 30m
|
||||
rT.reason += ". Shortening " + currenttemp.duration + "m long zero temp to 30m. ";
|
||||
rT.deliverAt = deliverAt;
|
||||
rT.temp = 'absolute';
|
||||
|
@ -119,10 +134,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
if ( profile.half_basal_exercise_target ) {
|
||||
var halfBasalTarget = profile.half_basal_exercise_target;
|
||||
} else {
|
||||
var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
||||
halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
||||
// 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default)
|
||||
}
|
||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + 10
|
||||
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
|
||||
|
@ -132,36 +147,36 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// limit sensitivityRatio to profile.autosens_max (1.2x by default)
|
||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.error("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
} else if (typeof autosens_data !== 'undefined' ) {
|
||||
process.stderr.write("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
sensitivityRatio = autosens_data.ratio;
|
||||
console.error("Autosens ratio: "+sensitivityRatio+"; ");
|
||||
process.stderr.write("Autosens ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
if (sensitivityRatio) {
|
||||
basal = profile.current_basal * sensitivityRatio;
|
||||
basal = round_basal(basal, profile);
|
||||
if (basal != profile_current_basal) {
|
||||
console.error("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
if (basal !== profile_current_basal) {
|
||||
process.stderr.write("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
} else {
|
||||
console.error("Basal unchanged: "+basal+"; ");
|
||||
process.stderr.write("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.error("Temp Target set, not adjusting with autosens; ");
|
||||
} else if (typeof autosens_data !== 'undefined' ) {
|
||||
//process.stderr.write("Temp Target set, not adjusting with autosens; ");
|
||||
} 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) / autosens_data.ratio) + 60;
|
||||
max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
|
||||
new_target_bg = round((target_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) {
|
||||
console.error("target_bg unchanged: "+new_target_bg+"; ");
|
||||
if (target_bg === new_target_bg) {
|
||||
process.stderr.write("target_bg unchanged: "+new_target_bg+"; ");
|
||||
} else {
|
||||
console.error("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
||||
process.stderr.write("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
||||
}
|
||||
target_bg = new_target_bg;
|
||||
}
|
||||
|
@ -197,34 +212,33 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
var profile_sens = round(profile.sens,1)
|
||||
var sens = profile.sens;
|
||||
if (typeof autosens_data !== 'undefined' ) {
|
||||
if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
sens = profile.sens / sensitivityRatio;
|
||||
sens = round(sens, 1);
|
||||
if (sens != profile_sens) {
|
||||
console.error("ISF from "+profile_sens+" to "+sens);
|
||||
if (sens !== profile_sens) {
|
||||
process.stderr.write("ISF from "+profile_sens+" to "+sens);
|
||||
} else {
|
||||
console.error("ISF unchanged: "+sens);
|
||||
process.stderr.write("ISF unchanged: "+sens);
|
||||
}
|
||||
//console.error(" (autosens ratio "+sensitivityRatio+")");
|
||||
//process.stderr.write(" (autosens ratio "+sensitivityRatio+")");
|
||||
}
|
||||
console.error("; CR:",profile.carb_ratio);
|
||||
|
||||
// compare currenttemp to iob_data.lastTemp and cancel temp if they don't match
|
||||
var lastTempAge;
|
||||
if (typeof iob_data.lastTemp !== 'undefined' ) {
|
||||
lastTempAge = round(( new Date().getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
||||
// } ---- added to not produce errors
|
||||
lastTempAge = round(( new Date(systemTime).getTime() - iob_data.lastTemp.date ) / 60000); // in minutes
|
||||
} else {
|
||||
lastTempAge = 0;
|
||||
}
|
||||
//console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m");
|
||||
tempModulus = (lastTempAge + currenttemp.duration) % 30;
|
||||
var tempModulus = (lastTempAge + currenttemp.duration) % 30;
|
||||
console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m");
|
||||
rT.temp = 'absolute';
|
||||
rT.deliverAt = deliverAt;
|
||||
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate != iob_data.lastTemp.rate ) {
|
||||
rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; setting neutral temp of "+basal+".";
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate !== iob_data.lastTemp.rate && lastTempAge > 10 && currenttemp.duration ) {
|
||||
rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; canceling temp";
|
||||
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||
}
|
||||
if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) {
|
||||
// TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left
|
||||
|
@ -234,10 +248,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
//}
|
||||
//console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1));
|
||||
var lastTempEnded = lastTempAge - iob_data.lastTemp.duration
|
||||
if ( lastTempEnded > 5 ) {
|
||||
rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; setting neutral temp of "+basal+".";
|
||||
if ( lastTempEnded > 5 && lastTempAge > 10 ) {
|
||||
rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; canceling temp";
|
||||
//console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1));
|
||||
return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||
}
|
||||
// TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries
|
||||
//if ( tempModulus < 25 && tempModulus > 5 ) {
|
||||
|
@ -264,37 +278,44 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
if (iob_data.iob > 0) {
|
||||
var naive_eventualBG = round( bg - (iob_data.iob * sens) );
|
||||
} else { // if IOB is negative, be more conservative and use the lower of sens, profile.sens
|
||||
var naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
|
||||
naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) );
|
||||
}
|
||||
// and adjust it for the deviation above
|
||||
var eventualBG = naive_eventualBG + deviation;
|
||||
// calculate what portion of that is due to bolussnooze
|
||||
//var bolusContrib = iob_data.bolussnooze * sens;
|
||||
// and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime
|
||||
//var naive_snoozeBG = round( naive_eventualBG + 1.5 * bolusContrib );
|
||||
// adjust that for deviation like we did eventualBG
|
||||
//var snoozeBG = naive_snoozeBG + deviation;
|
||||
|
||||
// adjust target BG range if needed to safely bring down high BG faster without causing lows
|
||||
if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) {
|
||||
// raise target for noisy / raw CGM data
|
||||
if (glucose_status.noise >= 2) {
|
||||
// increase target at least 10% (default 30%) for raw / noisy data
|
||||
var noisyCGMTargetMultiplier = Math.max( 1.1, profile.noisyCGMTargetMultiplier );
|
||||
// don't allow maxRaw above 250
|
||||
var maxRaw = Math.min( 250, profile.maxRaw );
|
||||
var adjustedMinBG = round(Math.min(200, min_bg * noisyCGMTargetMultiplier ));
|
||||
var adjustedTargetBG = round(Math.min(200, target_bg * noisyCGMTargetMultiplier ));
|
||||
var adjustedMaxBG = round(Math.min(200, max_bg * noisyCGMTargetMultiplier ));
|
||||
process.stderr.write("Raising target_bg for noisy / raw CGM data, from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||
min_bg = adjustedMinBG;
|
||||
target_bg = adjustedTargetBG;
|
||||
max_bg = adjustedMaxBG;
|
||||
// adjust target BG range if configured to bring down high BG faster
|
||||
} else if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) {
|
||||
// with target=100, as BG rises from 100 to 160, adjustedTarget drops from 100 to 80
|
||||
var adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0);
|
||||
var adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0);
|
||||
var adjustedMaxBG = round(Math.max(80, max_bg - (bg - max_bg)/3 ),0);
|
||||
adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0);
|
||||
adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0);
|
||||
adjustedMaxBG = round(Math.max(80, max_bg - (bg - max_bg)/3 ),0);
|
||||
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it
|
||||
//console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG);
|
||||
if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) {
|
||||
console.error("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
process.stderr.write("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; ");
|
||||
min_bg = adjustedMinBG;
|
||||
} else {
|
||||
console.error("min_bg unchanged: "+min_bg+"; ");
|
||||
process.stderr.write("min_bg unchanged: "+min_bg+"; ");
|
||||
}
|
||||
// if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it
|
||||
if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) {
|
||||
console.error("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||
process.stderr.write("target_bg from "+target_bg+" to "+adjustedTargetBG+"; ");
|
||||
target_bg = adjustedTargetBG;
|
||||
} else {
|
||||
console.error("target_bg unchanged: "+target_bg+"; ");
|
||||
process.stderr.write("target_bg unchanged: "+target_bg+"; ");
|
||||
}
|
||||
// if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it
|
||||
if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) {
|
||||
|
@ -321,7 +342,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
, 'bg': bg
|
||||
, 'tick': tick
|
||||
, 'eventualBG': eventualBG
|
||||
//, 'snoozeBG': snoozeBG
|
||||
, 'insulinReq': 0
|
||||
, 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run)
|
||||
, 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
|
||||
|
@ -353,7 +373,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// enable SMB/UAM (if enabled in preferences) while we have COB
|
||||
} else if (profile.enableSMB_with_COB === true && meal_data.mealCOB) {
|
||||
if (meal_data.bwCarbs) {
|
||||
if (profile.A52_risk_enable) {
|
||||
if (profile.A52_risk_enable === true) {
|
||||
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
|
@ -365,9 +385,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
// enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry
|
||||
// (6 hours is defined in carbWindow in lib/meal/total.js)
|
||||
} else if (profile.enableSMB_after_carbs === true && meal_data.carbs ) {
|
||||
} else if ((profile.enableSMB_after_carbs === true || profile.enableSMB_with_carbs === true) && meal_data.carbs ) {
|
||||
if (meal_data.bwCarbs) {
|
||||
if (profile.A52_risk_enable) {
|
||||
if (profile.A52_risk_enable === true) {
|
||||
console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
|
@ -380,7 +400,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// enable SMB/UAM (if enabled in preferences) if a low temptarget is set
|
||||
} else if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) {
|
||||
if (meal_data.bwFound) {
|
||||
if (profile.A52_risk_enable) {
|
||||
if (profile.A52_risk_enable === true) {
|
||||
console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard")
|
||||
enableSMB=true;
|
||||
} else {
|
||||
|
@ -404,7 +424,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
enableSMB=true;
|
||||
}
|
||||
} else {
|
||||
console.error("SMB disabled (no enableSMB preferences active)");
|
||||
console.error("SMB disabled for this run (no selected enableSMB criteria met)");
|
||||
}
|
||||
// enable UAM (if enabled in preferences)
|
||||
var enableUAM=(profile.enableUAM);
|
||||
|
@ -417,43 +437,48 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// calculate current carb absorption rate, and how long to absorb all carbs
|
||||
// CI = current carb impact on BG in mg/dL/5m
|
||||
ci = round((minDelta - bgi),1);
|
||||
uci = round((minDelta - bgi),1);
|
||||
var uci = round((minDelta - bgi),1);
|
||||
// ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g)
|
||||
if (profile.temptargetSet) {
|
||||
|
||||
// TODO: remove commented-out code for old behavior
|
||||
//if (profile.temptargetSet) {
|
||||
// if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR
|
||||
var csf = profile.sens / profile.carb_ratio;
|
||||
} else {
|
||||
//var csf = profile.sens / profile.carb_ratio;
|
||||
//} else {
|
||||
// otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments
|
||||
// so that autotuned CR is still in effect even when basals and ISF are being adjusted by autosens
|
||||
var csf = sens / profile.carb_ratio;
|
||||
}
|
||||
//var csf = sens / profile.carb_ratio;
|
||||
//}
|
||||
// use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments so that
|
||||
// autotuned CR is still in effect even when basals and ISF are being adjusted by TT or autosens
|
||||
// this avoids overdosing insulin for large meals when low temp targets are active
|
||||
csf = sens / profile.carb_ratio;
|
||||
console.error("profile.sens:",profile.sens,"sens:",sens,"CSF:",csf);
|
||||
|
||||
var maxCarbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed
|
||||
// limit Carb Impact to maxCarbAbsorptionRate * csf in mg/dL per 5m
|
||||
maxCI = round(maxCarbAbsorptionRate*csf*5/60,1)
|
||||
var maxCI = round(maxCarbAbsorptionRate*csf*5/60,1)
|
||||
if (ci > maxCI) {
|
||||
console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )");
|
||||
ci = maxCI;
|
||||
}
|
||||
// set meal_carbimpact high enough to absorb all meal carbs over 6 hours
|
||||
// total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g)
|
||||
//console.error(csf * meal_data.carbs);
|
||||
// meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay)
|
||||
//var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1)
|
||||
var remainingCATimeMin = 3; // h; before carb absorption starts
|
||||
// adjust remainingCATime (instead of CR) for autosens
|
||||
remainingCATimeMin = remainingCATimeMin / sensitivityRatio;
|
||||
var remainingCATimeMin = 3; // h; duration of expected not-yet-observed carb absorption
|
||||
// adjust remainingCATime (instead of CR) for autosens if sensitivityRatio defined
|
||||
if (sensitivityRatio){
|
||||
remainingCATimeMin = remainingCATimeMin / sensitivityRatio;
|
||||
}
|
||||
// 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h
|
||||
// when actual absorption ramps up it will take over from remainingCATime
|
||||
var assumedCarbAbsorptionRate = 20; // g/h; maximum rate to assume carbs will absorb if no CI observed
|
||||
var remainingCATime = remainingCATimeMin; // added by mike https://github.com/openaps/oref0/issues/884
|
||||
var remainingCATime = remainingCATimeMin;
|
||||
if (meal_data.carbs) {
|
||||
// if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it
|
||||
// so <= 90g is assumed to take 3h, and 120g=4h
|
||||
remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate);
|
||||
var lastCarbAge = round(( new Date().getTime() - meal_data.lastCarbTime ) / 60000);
|
||||
var lastCarbAge = round(( new Date(systemTime).getTime() - meal_data.lastCarbTime ) / 60000);
|
||||
//console.error(meal_data.lastCarbTime, lastCarbAge);
|
||||
|
||||
fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs;
|
||||
var fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs;
|
||||
remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60;
|
||||
remainingCATime = round(remainingCATime,1);
|
||||
//console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime)
|
||||
|
@ -478,7 +503,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h)
|
||||
var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2);
|
||||
//console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime);
|
||||
//if (meal_data.mealCOB * 3 > meal_data.carbs) { }
|
||||
|
||||
// calculate peak deviation in last hour, and slope from that to current deviation
|
||||
var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2);
|
||||
|
@ -488,17 +512,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3);
|
||||
//console.error(slopeFromMaxDeviation);
|
||||
|
||||
aci = 10;
|
||||
var aci = 10;
|
||||
//5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m)
|
||||
// duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m)
|
||||
// limit cid to remainingCATime hours: the reset goes to remainingCI
|
||||
if (ci == 0) {
|
||||
if (ci === 0) {
|
||||
// avoid divide by zero
|
||||
cid = 0;
|
||||
} else {
|
||||
cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci ));
|
||||
}
|
||||
acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
||||
var acid = Math.max(0, meal_data.mealCOB * csf / aci );
|
||||
// duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay)
|
||||
console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m");
|
||||
//console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours");
|
||||
|
@ -529,18 +553,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
try {
|
||||
iobArray.forEach(function(iobTick) {
|
||||
//console.error(iobTick);
|
||||
predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
||||
predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
|
||||
var predBGI = round(( -iobTick.activity * sens * 5 ), 2);
|
||||
var predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2);
|
||||
// for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero
|
||||
// over 60 minutes (data points every 5m)
|
||||
predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
||||
var predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
||||
IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
||||
// calculate predBGs with long zero temp without deviations
|
||||
ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
||||
var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
||||
// for COBpredBGs, predicted carb impact drops linearly from current carb impact down to zero
|
||||
// eventually accounting for all carbs (if they can be absorbed over DIA)
|
||||
predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
|
||||
predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) );
|
||||
var predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
|
||||
var predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) );
|
||||
// if any carbs aren't absorbed after remainingCATime hours, assume they'll absorb in a /\ shaped
|
||||
// bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m)
|
||||
// and ending at remainingCATime h (remainingCATime*12 * 5m intervals)
|
||||
|
@ -549,18 +573,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
remainingCItotal += predCI+remainingCI;
|
||||
remainingCIs.push(round(remainingCI,0));
|
||||
predCIs.push(round(predCI,0));
|
||||
//console.error(round(predCI,1)+"+"+round(remainingCI,1)+" ");
|
||||
//process.stderr.write(round(predCI,1)+"+"+round(remainingCI,1)+" ");
|
||||
COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI;
|
||||
aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
|
||||
var aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI;
|
||||
// for UAMpredBGs, predicted carb impact drops at slopeFromDeviations
|
||||
// calculate predicted CI from UAM based on slopeFromDeviations
|
||||
predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) );
|
||||
var predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) );
|
||||
// if slopeFromDeviations is too flat, predicted deviation impact drops linearly from
|
||||
// current deviation down to zero over 3h (data points every 5m)
|
||||
predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) );
|
||||
var predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) );
|
||||
//console.error(predUCIslope, predUCImax);
|
||||
// predicted CI from UAM is the lesser of CI based on deviationSlope or DIA
|
||||
predUCI = Math.min(predUCIslope, predUCImax);
|
||||
var predUCI = Math.min(predUCIslope, predUCImax);
|
||||
if(predUCI>0) {
|
||||
//console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
|
||||
UAMduration=round((UAMpredBGs.length+1)*5/60,1);
|
||||
|
@ -599,19 +623,18 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// set eventualBG to include effect of carbs
|
||||
//console.error("PredBGs:",JSON.stringify(predBGs));
|
||||
} catch (e) {
|
||||
console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled:",e);
|
||||
console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled");
|
||||
}
|
||||
if (meal_data.mealCOB) {
|
||||
console.error("predCIs (mg/dL/5m):",predCIs.join(" "));
|
||||
console.error("remainingCIs: ",remainingCIs.join(" "));
|
||||
}
|
||||
//,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2));
|
||||
rT.predBGs = {};
|
||||
IOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=IOBpredBGs.length-1; i > 12; i--) {
|
||||
if (IOBpredBGs[i-1] != IOBpredBGs[i]) { break; }
|
||||
if (IOBpredBGs[i-1] !== IOBpredBGs[i]) { break; }
|
||||
else { IOBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.IOB = IOBpredBGs;
|
||||
|
@ -619,10 +642,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
ZTpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=ZTpredBGs.length-1; i > 6; i--) {
|
||||
//if (ZTpredBGs[i-1] != ZTpredBGs[i]) { break; }
|
||||
for (i=ZTpredBGs.length-1; i > 6; i--) {
|
||||
// stop displaying ZTpredBGs once they're rising and above target
|
||||
if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] < target_bg) { break; }
|
||||
if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] <= target_bg) { break; }
|
||||
else { ZTpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.ZT = ZTpredBGs;
|
||||
|
@ -631,19 +653,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
aCOBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||
if (aCOBpredBGs[i-1] != aCOBpredBGs[i]) { break; }
|
||||
for (i=aCOBpredBGs.length-1; i > 12; i--) {
|
||||
if (aCOBpredBGs[i-1] !== aCOBpredBGs[i]) { break; }
|
||||
else { aCOBpredBGs.pop(); }
|
||||
}
|
||||
// disable for now. may want to add a preference to re-enable
|
||||
//rT.predBGs.aCOB = aCOBpredBGs;
|
||||
}
|
||||
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
||||
COBpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=COBpredBGs.length-1; i > 12; i--) {
|
||||
if (COBpredBGs[i-1] != COBpredBGs[i]) { break; }
|
||||
for (i=COBpredBGs.length-1; i > 12; i--) {
|
||||
if (COBpredBGs[i-1] !== COBpredBGs[i]) { break; }
|
||||
else { COBpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.COB = COBpredBGs;
|
||||
|
@ -655,8 +675,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
UAMpredBGs.forEach(function(p, i, theArray) {
|
||||
theArray[i] = round(Math.min(401,Math.max(39,p)));
|
||||
});
|
||||
for (var i=UAMpredBGs.length-1; i > 12; i--) {
|
||||
if (UAMpredBGs[i-1] != UAMpredBGs[i]) { break; }
|
||||
for (i=UAMpredBGs.length-1; i > 12; i--) {
|
||||
if (UAMpredBGs[i-1] !== UAMpredBGs[i]) { break; }
|
||||
else { UAMpredBGs.pop(); }
|
||||
}
|
||||
rT.predBGs.UAM = UAMpredBGs;
|
||||
|
@ -666,7 +686,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
}
|
||||
|
||||
// set eventualBG and snoozeBG based on COB or UAM predBGs
|
||||
// set eventualBG based on COB or UAM predBGs
|
||||
rT.eventualBG = eventualBG;
|
||||
}
|
||||
|
||||
|
@ -733,14 +753,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
//console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG);
|
||||
// if any carbs have been entered recently
|
||||
if (meal_data.carbs) {
|
||||
// average the minIOBPredBG and minUAMPredBG if available
|
||||
/*
|
||||
if ( minUAMPredBG < 999 ) {
|
||||
avgMinPredBG = round( (minIOBPredBG+minUAMPredBG)/2 );
|
||||
} else {
|
||||
avgMinPredBG = minIOBPredBG;
|
||||
}
|
||||
*/
|
||||
|
||||
// if UAM is disabled, use max of minIOBPredBG, minCOBPredBG
|
||||
if ( ! enableUAM && minCOBPredBG < 999 ) {
|
||||
|
@ -748,30 +760,27 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher
|
||||
} else if ( minCOBPredBG < 999 ) {
|
||||
// calculate blendedMinPredBG based on how many carbs remain as COB
|
||||
//blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minUAMPredBG;
|
||||
blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
||||
var blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG;
|
||||
// if blendedMinPredBG > minCOBPredBG, use that instead
|
||||
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
|
||||
// if carbs have been entered, but have expired, use minUAMPredBG
|
||||
} else {
|
||||
//minPredBG = minUAMPredBG;
|
||||
minPredBG = minZTUAMPredBG;
|
||||
}
|
||||
// in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG
|
||||
} else if ( enableUAM ) {
|
||||
//minPredBG = round(Math.max(minIOBPredBG,minUAMPredBG));
|
||||
minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG));
|
||||
}
|
||||
|
||||
// make sure minPredBG isn't higher than avgPredBG
|
||||
minPredBG = Math.min( minPredBG, avgPredBG );
|
||||
|
||||
console.error("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
||||
process.stderr.write("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG);
|
||||
if (minCOBPredBG < 999) {
|
||||
console.error(" minCOBPredBG: "+minCOBPredBG);
|
||||
process.stderr.write(" minCOBPredBG: "+minCOBPredBG);
|
||||
}
|
||||
if (minUAMPredBG < 999) {
|
||||
console.error(" minUAMPredBG: "+minUAMPredBG);
|
||||
process.stderr.write(" minUAMPredBG: "+minUAMPredBG);
|
||||
}
|
||||
console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs);
|
||||
// But if the COB line falls off a cliff, don't trust UAM too much:
|
||||
|
@ -790,9 +799,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile)
|
||||
}
|
||||
rT.reason += "; ";
|
||||
//var bgUndershoot = threshold - Math.min(minGuardBG, Math.max( naive_eventualBG, eventualBG ));
|
||||
// use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39
|
||||
//var carbsReqBG = Math.max( naive_eventualBG, eventualBG );
|
||||
var carbsReqBG = naive_eventualBG;
|
||||
if ( carbsReqBG < 40 ) {
|
||||
carbsReqBG = Math.min( minGuardBG, carbsReqBG );
|
||||
|
@ -802,14 +809,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var minutesAboveMinBG = 240;
|
||||
var minutesAboveThreshold = 240;
|
||||
if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) {
|
||||
for (var i=0; i<COBpredBGs.length; i++) {
|
||||
for (i=0; i<COBpredBGs.length; i++) {
|
||||
//console.error(COBpredBGs[i], min_bg);
|
||||
if ( COBpredBGs[i] < min_bg ) {
|
||||
minutesAboveMinBG = 5*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i=0; i<COBpredBGs.length; i++) {
|
||||
for (i=0; i<COBpredBGs.length; i++) {
|
||||
//console.error(COBpredBGs[i], threshold);
|
||||
if ( COBpredBGs[i] < threshold ) {
|
||||
minutesAboveThreshold = 5*i;
|
||||
|
@ -817,14 +824,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
||||
for (i=0; i<IOBpredBGs.length; i++) {
|
||||
//console.error(IOBpredBGs[i], min_bg);
|
||||
if ( IOBpredBGs[i] < min_bg ) {
|
||||
minutesAboveMinBG = 5*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i=0; i<IOBpredBGs.length; i++) {
|
||||
for (i=0; i<IOBpredBGs.length; i++) {
|
||||
//console.error(IOBpredBGs[i], threshold);
|
||||
if ( IOBpredBGs[i] < threshold ) {
|
||||
minutesAboveThreshold = 5*i;
|
||||
|
@ -848,9 +855,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) {
|
||||
console.error("BG projected to remain above",convert_bg(threshold,profile),"for",minutesAboveThreshold,"minutes");
|
||||
}
|
||||
// include at least minutesAboveMinBG worth of zero temps in calculating carbsReq
|
||||
// include at least minutesAboveThreshold worth of zero temps in calculating carbsReq
|
||||
// always include at least 30m worth of zero temp (carbs to 80, low temp up to target)
|
||||
//var zeroTempDuration = Math.max(30,minutesAboveMinBG);
|
||||
var zeroTempDuration = minutesAboveThreshold;
|
||||
// BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB
|
||||
var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60;
|
||||
|
@ -871,7 +877,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// predictive low glucose suspend mode: BG is / is projected to be < threshold
|
||||
} else if ( bg < threshold || minGuardBG < threshold ) {
|
||||
rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile);
|
||||
var bgUndershoot = target_bg - minGuardBG;
|
||||
bgUndershoot = target_bg - minGuardBG;
|
||||
var worstCaseInsulinReq = bgUndershoot / sens;
|
||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
durationReq = round(durationReq/30)*30;
|
||||
|
@ -880,6 +886,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
return tempBasalFunctions.setTempBasal(0, durationReq, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
// if not in LGS mode, cancel temps before the top of the hour to reduce beeping/vibration
|
||||
// console.error(profile.skip_neutral_temps, rT.deliverAt.getMinutes());
|
||||
if ( profile.skip_neutral_temps && rT.deliverAt.getMinutes() >= 55 ) {
|
||||
rT.reason += "; Canceling temp at " + rT.deliverAt.getMinutes() + "m past the hour. ";
|
||||
return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
if (eventualBG < min_bg) { // if eventual BG is below target:
|
||||
rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile);
|
||||
// if 5m or 30m avg BG is rising faster than expected delta
|
||||
|
@ -904,9 +917,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
|
||||
// calculate 30m low-temp required to get projected BG up to target
|
||||
// use snoozeBG to more gradually ramp in any counteraction of the user's boluses
|
||||
// multiply by 2 to low-temp faster for increased hypo safety
|
||||
//var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / sens);
|
||||
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens);
|
||||
insulinReq = round( insulinReq , 2);
|
||||
// calculate naiveInsulinReq based on naive_eventualBG
|
||||
|
@ -914,7 +925,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
naiveInsulinReq = round( naiveInsulinReq , 2);
|
||||
if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
// if we're barely falling, newinsulinReq should be barely negative
|
||||
//rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile);
|
||||
var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2);
|
||||
//console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq);
|
||||
insulinReq = newinsulinReq;
|
||||
|
@ -922,6 +932,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// rate required to deliver insulinReq less insulin over 30m:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
|
||||
// if required temp < existing temp basal
|
||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
// if current temp would deliver a lot (30% of basal) less than the required insulin,
|
||||
|
@ -937,18 +948,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
} else {
|
||||
// calculate a long enough zero temp to eventually correct back up to target
|
||||
if ( rate <=0 ) {
|
||||
var bgUndershoot = target_bg - naive_eventualBG;
|
||||
var worstCaseInsulinReq = bgUndershoot / sens;
|
||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
bgUndershoot = target_bg - naive_eventualBG;
|
||||
worstCaseInsulinReq = bgUndershoot / sens;
|
||||
durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
if (durationReq < 0) {
|
||||
durationReq = 0;
|
||||
// don't set an SMB zero temp longer than 60 minutess
|
||||
// don't set a temp longer than 120 minutes
|
||||
} else {
|
||||
durationReq = round(durationReq/30)*30;
|
||||
durationReq = Math.min(60,Math.max(0,durationReq));
|
||||
durationReq = Math.min(120,Math.max(0,durationReq));
|
||||
}
|
||||
//console.error(durationReq);
|
||||
//rT.reason += "insulinReq " + insulinReq + "; "
|
||||
if (durationReq > 0) {
|
||||
rT.reason += ", setting " + durationReq + "m zero temp. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp);
|
||||
|
@ -1011,15 +1021,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
// insulinReq is the additional insulin required to get minPredBG down to target_bg
|
||||
//console.error(minPredBG,eventualBG);
|
||||
//var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
var insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
// when dropping, but not as fast as expected, reduce insulinReq proportionally
|
||||
// to the what fraction of expectedDelta we're dropping at
|
||||
//if (minDelta < 0 && minDelta > expectedDelta) {
|
||||
//var newinsulinReq = round(( insulinReq * (1 - (minDelta / expectedDelta)) ), 2);
|
||||
//console.error("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq + " for minDelta " + minDelta + " vs. expectedDelta " + expectedDelta);
|
||||
//insulinReq = newinsulinReq;
|
||||
//}
|
||||
insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2);
|
||||
// if that would put us over max_iob, then reduce accordingly
|
||||
if (insulinReq > max_iob-iob_data.iob) {
|
||||
rT.reason += "max_iob " + max_iob + ", ";
|
||||
|
@ -1027,21 +1029,21 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
|
||||
// rate required to deliver insulinReq more insulin over 30m:
|
||||
var rate = basal + (2 * insulinReq);
|
||||
rate = basal + (2 * insulinReq);
|
||||
rate = round_basal(rate, profile);
|
||||
insulinReq = round(insulinReq,3);
|
||||
rT.insulinReq = insulinReq;
|
||||
//console.error(iob_data.lastBolusTime);
|
||||
// minutes since last bolus
|
||||
var lastBolusAge = round(( new Date().getTime() - iob_data.lastBolusTime ) / 60000,1);
|
||||
var lastBolusAge = round(( new Date(systemTime).getTime() - iob_data.lastBolusTime ) / 60000,1);
|
||||
//console.error(lastBolusAge);
|
||||
//console.error(profile.temptargetSet, target_bg, rT.COB);
|
||||
// only allow microboluses with COB or low temp targets, or within DIA hours of a bolus
|
||||
if (microBolusAllowed && enableSMB && bg > threshold) {
|
||||
// never bolus more than maxSMBBasalMinutes worth of basal
|
||||
mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
||||
if (typeof profile.maxSMBBasalMinutes == 'undefined' ) {
|
||||
maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||
var mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3);
|
||||
if (typeof profile.maxSMBBasalMinutes === 'undefined' ) {
|
||||
var maxBolus = round( profile.current_basal * 30 / 60 ,1);
|
||||
console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m");
|
||||
// if IOB covers more than COB, limit maxBolus to 30m of basal
|
||||
} else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) {
|
||||
|
@ -1059,11 +1061,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
}
|
||||
// bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment
|
||||
var roundSMBTo = 1 / profile.bolus_increment;
|
||||
microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*roundSMBTo)/roundSMBTo;
|
||||
var microBolus = Math.floor(Math.min(insulinReq/2,maxBolus)*roundSMBTo)/roundSMBTo;
|
||||
// calculate a long enough zero temp to eventually correct back up to target
|
||||
var smbTarget = target_bg;
|
||||
var worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
||||
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens;
|
||||
durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
|
||||
|
||||
// if insulinReq > 0 but not enough for a microBolus, don't set an SMB zero temp
|
||||
if (insulinReq > 0 && microBolus < profile.bolus_increment) {
|
||||
|
@ -1073,10 +1075,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
var smbLowTempReq = 0;
|
||||
if (durationReq <= 0) {
|
||||
durationReq = 0;
|
||||
// don't set a temp longer than 120 minutes
|
||||
// don't set an SMB zero temp longer than 60 minutes
|
||||
} else if (durationReq >= 30) {
|
||||
durationReq = round(durationReq/30)*30;
|
||||
durationReq = Math.min(120,Math.max(0,durationReq));
|
||||
durationReq = Math.min(60,Math.max(0,durationReq));
|
||||
} else {
|
||||
// if SMB durationReq is less than 30m, set a nonzero low temp
|
||||
smbLowTempReq = round( basal * durationReq/30 ,2);
|
||||
|
@ -1118,11 +1120,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
return rT;
|
||||
}
|
||||
|
||||
// if insulinReq is negative, snoozeBG > target_bg, and lastCOBpredBG > target_bg, set a neutral temp
|
||||
//if (insulinReq < 0 && snoozeBG > target_bg && lastCOBpredBG > target_bg) {
|
||||
//rT.reason += "; SMB bolus snooze: setting current basal of " + basal + " as temp. ";
|
||||
//return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp);
|
||||
//}
|
||||
}
|
||||
|
||||
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
|
||||
|
@ -1132,13 +1129,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
rate = round_basal(maxSafeBasal, profile);
|
||||
}
|
||||
|
||||
var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60;
|
||||
if (insulinScheduled >= insulinReq * 2) { // if current temp would deliver >2x more than the required insulin, lower the rate
|
||||
rT.reason += currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " > 2 * insulinReq. Setting temp basal of " + rate + "U/hr. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
||||
if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set
|
||||
if (typeof currenttemp.duration === 'undefined' || currenttemp.duration === 0) { // no temp is set
|
||||
rT.reason += "no temp, setting " + rate + "U/hr. ";
|
||||
return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
private JSONObject mAutosensData = null;
|
||||
private boolean mMicrobolusAllowed;
|
||||
private boolean mSMBAlwaysAllowed;
|
||||
private long mCurrentTime;
|
||||
|
||||
private String storedCurrentTemp = null;
|
||||
private String storedIobData = null;
|
||||
|
@ -58,6 +59,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
private String storedAutosens_data = null;
|
||||
private String storedMicroBolusAllowed = null;
|
||||
private String storedSMBAlwaysAllowed = null;
|
||||
private String storedCurrentTime = null;
|
||||
|
||||
private String scriptDebug = "";
|
||||
|
||||
|
@ -87,6 +89,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
log.debug("Reservoir data: " + "undefined");
|
||||
log.debug("MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
|
||||
log.debug("SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed));
|
||||
// log.debug("Current Time: " + (storedCurrentTime = "" + mCurrentTime));
|
||||
}
|
||||
|
||||
DetermineBasalResultSMB determineBasalResultSMB = null;
|
||||
|
@ -129,7 +132,8 @@ public class DetermineBasalAdapterSMBJS {
|
|||
makeParam(mMealData, rhino, scope),
|
||||
setTempBasalFunctionsObj,
|
||||
new Boolean(mMicrobolusAllowed),
|
||||
makeParam(null, rhino, scope) // reservoir data as undefined
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
mCurrentTime
|
||||
};
|
||||
|
||||
|
||||
|
@ -163,6 +167,7 @@ public class DetermineBasalAdapterSMBJS {
|
|||
storedCurrentTemp = mCurrentTemp.toString();
|
||||
storedProfile = mProfile.toString();
|
||||
storedMeal_data = mMealData.toString();
|
||||
//storedCurrentTime = "" + mCurrentTime;
|
||||
|
||||
return determineBasalResultSMB;
|
||||
|
||||
|
@ -172,6 +177,10 @@ public class DetermineBasalAdapterSMBJS {
|
|||
return storedGlucoseStatus;
|
||||
}
|
||||
|
||||
// String getCurrentTimeParam() {
|
||||
// return storedCurrentTime;
|
||||
// }
|
||||
|
||||
String getCurrentTempParam() {
|
||||
return storedCurrentTemp;
|
||||
}
|
||||
|
@ -332,6 +341,8 @@ public class DetermineBasalAdapterSMBJS {
|
|||
mMicrobolusAllowed = microBolusAllowed;
|
||||
mSMBAlwaysAllowed = advancedFiltering;
|
||||
|
||||
mCurrentTime = System.currentTimeMillis();
|
||||
|
||||
}
|
||||
|
||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
||||
|
|
Loading…
Reference in a new issue