DynISF: resolve situation where TDD is not available
This commit is contained in:
parent
85f170f17d
commit
0e1caa3c9c
|
@ -7,10 +7,10 @@ import info.nightscout.database.entities.TotalDailyDose
|
|||
|
||||
interface TddCalculator {
|
||||
|
||||
fun calculate(days: Long): LongSparseArray<TotalDailyDose>
|
||||
fun calculateToday(): TotalDailyDose
|
||||
fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose
|
||||
fun calculate(startTime: Long, endTime: Long): TotalDailyDose
|
||||
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose?
|
||||
fun calculate(days: Long, allowMissingDays: Boolean): LongSparseArray<TotalDailyDose>?
|
||||
fun calculateToday(): TotalDailyDose?
|
||||
fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose?
|
||||
fun calculate(startTime: Long, endTime: Long, allowMissingData: Boolean): TotalDailyDose?
|
||||
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>?): TotalDailyDose?
|
||||
fun stats(context: Context): TableLayout
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.ViewGroup
|
|||
import android.widget.TableLayout
|
||||
import android.widget.TableRow
|
||||
import android.widget.TextView
|
||||
import androidx.core.util.size
|
||||
import info.nightscout.database.ValueWrapper
|
||||
import info.nightscout.database.entities.Bolus
|
||||
import info.nightscout.database.entities.TotalDailyDose
|
||||
|
@ -37,7 +38,7 @@ class TddCalculatorImpl @Inject constructor(
|
|||
private val repository: AppRepository
|
||||
) : TddCalculator {
|
||||
|
||||
override fun calculate(days: Long): LongSparseArray<TotalDailyDose> {
|
||||
override fun calculate(days: Long, allowMissingDays: Boolean): LongSparseArray<TotalDailyDose>? {
|
||||
var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
|
||||
val endTime = MidnightTime.calc(dateUtil.now())
|
||||
//val stepSize = T.hours(24).msecs() // this is not true on DST change
|
||||
|
@ -55,8 +56,8 @@ class TddCalculatorImpl @Inject constructor(
|
|||
if (endTime > startTime) {
|
||||
var midnight = startTime
|
||||
while (midnight < endTime) {
|
||||
val tdd = calculate(midnight, midnight + T.hours(24).msecs())
|
||||
result.put(midnight, tdd)
|
||||
val tdd = calculate(midnight, midnight + T.hours(24).msecs(), allowMissingData = false)
|
||||
if (tdd != null) result.put(midnight, tdd)
|
||||
midnight = MidnightTime.calc(midnight + T.hours(27).msecs()) // be sure we find correct midnight
|
||||
}
|
||||
}
|
||||
|
@ -68,25 +69,28 @@ class TddCalculatorImpl @Inject constructor(
|
|||
repository.insertTotalDailyDose(tdd)
|
||||
}
|
||||
}
|
||||
return result
|
||||
if (result.size.toLong() == days || allowMissingDays) return result
|
||||
return null
|
||||
}
|
||||
|
||||
override fun calculateToday(): TotalDailyDose {
|
||||
override fun calculateToday(): TotalDailyDose? {
|
||||
val startTime = MidnightTime.calc(dateUtil.now())
|
||||
val endTime = dateUtil.now()
|
||||
return calculate(startTime, endTime)
|
||||
return calculate(startTime, endTime, allowMissingData = true)
|
||||
}
|
||||
|
||||
override fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose {
|
||||
override fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose? {
|
||||
val startTime = dateUtil.now() + T.hours(hour = startHours).msecs()
|
||||
val endTime = dateUtil.now() + T.hours(hour = endHours).msecs()
|
||||
return calculate(startTime, endTime)
|
||||
return calculate(startTime, endTime, allowMissingData = false)
|
||||
}
|
||||
|
||||
override fun calculate(startTime: Long, endTime: Long): TotalDailyDose {
|
||||
override fun calculate(startTime: Long, endTime: Long, allowMissingData: Boolean): TotalDailyDose? {
|
||||
val isWholeDay = (endTime - startTime) >= T.days(1).msecs()
|
||||
val startTimeAligned = startTime - startTime % (5 * 60 * 1000)
|
||||
val endTimeAligned = endTime - endTime % (5 * 60 * 1000)
|
||||
val tdd = TotalDailyDose(timestamp = startTimeAligned)
|
||||
var tbrFound = false
|
||||
repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet()
|
||||
.filter { it.type != Bolus.Type.PRIMING }
|
||||
.forEach { t ->
|
||||
|
@ -98,8 +102,9 @@ class TddCalculatorImpl @Inject constructor(
|
|||
val calculationStep = T.mins(5).msecs()
|
||||
for (t in startTimeAligned until endTimeAligned step calculationStep) {
|
||||
|
||||
val profile = profileFunction.getProfile(t) ?: continue
|
||||
val profile = profileFunction.getProfile(t) ?: if (allowMissingData) continue else return null
|
||||
val tbr = iobCobCalculator.getBasalData(profile, t)
|
||||
if (tbr.isTempBasalRunning) tbrFound = true
|
||||
val absoluteRate = tbr.tempBasalAbsolute
|
||||
tdd.basalAmount += absoluteRate / 60.0 * 5.0
|
||||
|
||||
|
@ -111,11 +116,13 @@ class TddCalculatorImpl @Inject constructor(
|
|||
}
|
||||
tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount
|
||||
aapsLogger.debug(LTag.CORE, tdd.toString())
|
||||
return tdd
|
||||
if (tdd.bolusAmount > 0 || tdd.basalAmount > 0 || tbrFound) return tdd
|
||||
return null
|
||||
}
|
||||
|
||||
override fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose? {
|
||||
override fun averageTDD(tdds: LongSparseArray<TotalDailyDose>?): TotalDailyDose? {
|
||||
val totalTdd = TotalDailyDose(timestamp = dateUtil.now())
|
||||
tdds ?: return null
|
||||
if (tdds.size() == 0) return null
|
||||
for (i in 0 until tdds.size()) {
|
||||
val tdd = tdds.valueAt(i)
|
||||
|
@ -132,7 +139,7 @@ class TddCalculatorImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun stats(context: Context): TableLayout {
|
||||
val tdds = calculate(7)
|
||||
val tdds = calculate(7, allowMissingDays = true) ?: return TableLayout(context)
|
||||
val averageTdd = averageTDD(tdds)
|
||||
val todayTdd = calculateToday()
|
||||
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -156,6 +163,7 @@ class TddCalculatorImpl @Inject constructor(
|
|||
})
|
||||
layout.addView(averageTdd.toTableRow(context, rh, tdds.size(), includeCarbs = true))
|
||||
}
|
||||
todayTdd?.let {
|
||||
layout.addView(TextView(context).apply {
|
||||
text = rh.gs(info.nightscout.shared.R.string.today)
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
|
@ -165,4 +173,5 @@ class TddCalculatorImpl @Inject constructor(
|
|||
layout.addView(todayTdd.toTableRow(context, rh, dateUtil, includeCarbs = true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,14 +577,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
// for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero
|
||||
// over 60 minutes (data points every 5m)
|
||||
var predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) );
|
||||
//IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
||||
IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + (round(( -iobTick.activity * (1800 / ( TDD * (Math.log((Math.max( IOBpredBGs[IOBpredBGs.length-1],39) / insulinDivisor ) + 1 ) ) ))
|
||||
* 5 ),2)) + predDev;
|
||||
if (!TDD) IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev;
|
||||
else IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + (round(( -iobTick.activity * (1800 / ( TDD * (Math.log((Math.max( IOBpredBGs[IOBpredBGs.length-1],39) / insulinDivisor ) + 1 ) ) )) * 5 ),2)) + predDev;
|
||||
|
||||
// calculate predBGs with long zero temp without deviations
|
||||
//var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
||||
var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + (round(( -iobTick.iobWithZeroTemp.activity * (1800 / ( TDD * (Math.log(( Math.max(ZTpredBGs[ZTpredBGs.length-1],39) /
|
||||
insulinDivisor ) + 1 ) ) )) * 5 ), 2));
|
||||
if (!TDD) var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI;
|
||||
else var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + (round(( -iobTick.iobWithZeroTemp.activity * (1800 / ( TDD * (Math.log(( Math.max(ZTpredBGs[ZTpredBGs.length-1],39) / insulinDivisor ) + 1 ) ) )) * 5 ), 2));
|
||||
// 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)
|
||||
var predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) );
|
||||
|
@ -613,9 +611,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
//console.error(UAMpredBGs.length,slopeFromDeviations, predUCI);
|
||||
UAMduration=round((UAMpredBGs.length+1)*5/60,1);
|
||||
}
|
||||
//UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI;
|
||||
UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + (round(( -iobTick.activity * (1800 / ( TDD
|
||||
* (Math.log(( Math.max(UAMpredBGs[UAMpredBGs.length-1],39) / insulinDivisor ) + 1 ) ) )) * 5 ),2)) + Math.min(0, predDev) + predUCI;
|
||||
if (!TDD) UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI;
|
||||
else UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + (round(( -iobTick.activity * (1800 / ( TDD * (Math.log(( Math.max(UAMpredBGs[UAMpredBGs.length-1],39) / insulinDivisor ) + 1 ) ) )) * 5 ),2)) + Math.min(0, predDev) + predUCI;
|
||||
//console.error(predBGI, predCI, predUCI);
|
||||
// truncate all BG predictions at 4 hours
|
||||
if ( IOBpredBGs.length < 48) { IOBpredBGs.push(IOBpredBG); }
|
||||
|
@ -727,6 +724,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
var fSensBG = Math.min(minPredBG,bg);
|
||||
|
||||
if (TDD) {
|
||||
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))/insulinDivisor)+1)*TDD));
|
||||
//var future_sens_old = ( 277700 / (TDD * ((bg * 0.5) + (eventualBG * 0.5 ))));
|
||||
|
@ -748,6 +746,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
|
||||
}
|
||||
future_sens = round(future_sens,1);
|
||||
} else future_sens = variable_sens
|
||||
|
||||
|
||||
var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs;
|
||||
|
|
|
@ -262,23 +262,11 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||
|
||||
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");
|
||||
|
||||
// console.log("Insulin Peak = " + insulin.peak + "; ");
|
||||
val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(1, allowMissingDays = false))?.totalAmount
|
||||
val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(7, allowMissingDays = false))?.totalAmount
|
||||
val tddLast24H = tddCalculator.calculateDaily(-24, 0)?.totalAmount
|
||||
val tddLast4H = tddCalculator.calculateDaily(-4, 0)?.totalAmount
|
||||
val tddLast8to4H = tddCalculator.calculateDaily(-8, -4)?.totalAmount
|
||||
|
||||
val insulin = activePlugin.activeInsulin
|
||||
val insulinDivisor = when {
|
||||
|
@ -286,25 +274,35 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
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 + "; ");
|
||||
|
||||
var tdd: Double? = null
|
||||
var variableSensitivity: Double
|
||||
if (tddLast24H != null && tddLast4H != null && tddLast8to4H != null) {
|
||||
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 + "; ");
|
||||
|
||||
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");
|
||||
|
||||
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 = 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 + "; ");
|
||||
} else {
|
||||
variableSensitivity = profile.getIsfMgdl()
|
||||
}
|
||||
// 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)
|
||||
tdd?.let { this.profile.put("TDD", tdd) }
|
||||
|
||||
|
||||
if (sp.getBoolean(R.string.key_adjust_sensitivity, false) && tdd7D != null && tdd7D != 0.0)
|
||||
if (sp.getBoolean(R.string.key_adjust_sensitivity, false) && tdd7D != null && tddLast24H != null)
|
||||
autosensData.put("ratio", tddLast24H / tdd7D)
|
||||
else
|
||||
autosensData.put("ratio", 1.0)
|
||||
|
|
|
@ -133,11 +133,10 @@ class StatusLightHandler @Inject constructor(
|
|||
private fun handleUsage(view: TextView?, units: String) {
|
||||
handler.post {
|
||||
val therapyEvent = repository.getLastTherapyRecordUpToNow(TherapyEvent.Type.CANNULA_CHANGE).blockingGet()
|
||||
var usage = 0.0
|
||||
var usage =
|
||||
if (therapyEvent is ValueWrapper.Existing) {
|
||||
val tdd = tddCalculator.calculate(therapyEvent.value.timestamp, dateUtil.now())
|
||||
usage = tdd.totalAmount
|
||||
}
|
||||
tddCalculator.calculate(therapyEvent.value.timestamp, dateUtil.now(), allowMissingData = false)?.totalAmount ?: 0.0
|
||||
} else 0.0
|
||||
runOnUiThread {
|
||||
view?.text = DecimalFormatter.to0Decimal(usage, units)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue