Add Tune insulin Curve option
This commit is contained in:
parent
bf46d8a605
commit
e7da675e1e
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.autotune
|
||||
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.LocalInsulin
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
|
@ -28,16 +29,14 @@ class AutotuneCore @Inject constructor(
|
|||
var carbRatio = previousAutotune.ic
|
||||
//console.error(carbRatio);
|
||||
var csf = isf / carbRatio
|
||||
//val dia = previousAutotune.dia
|
||||
//val insulinInterface = activePlugin.activeInsulin
|
||||
//var peak = 75
|
||||
//if (insulinInterface.id == InsulinInterface.InsulinType.OREF_ULTRA_RAPID_ACTING) peak = 55 else if (insulinInterface.id == InsulinInterface.InsulinType.OREF_FREE_PEAK) peak = sp.getInt(R.string.key_insulin_oref_peak, 75)
|
||||
var dia = previousAutotune.dia
|
||||
var peak = previousAutotune.peak
|
||||
val csfGlucose = preppedGlucose.csfGlucoseData
|
||||
val isfGlucose = preppedGlucose.isfGlucoseData
|
||||
val basalGlucose = preppedGlucose.basalGlucoseData
|
||||
val crData = preppedGlucose.crData
|
||||
//List<DiaDatum> diaDeviations = preppedGlucose.diaDeviations;
|
||||
//List<PeakDatum> peakDeviations = preppedGlucose.peakDeviations;
|
||||
val diaDeviations = preppedGlucose.diaDeviations
|
||||
val peakDeviations = preppedGlucose.peakDeviations
|
||||
val pumpISF = pumpProfile.isf
|
||||
val pumpCarbRatio = pumpProfile.ic
|
||||
val pumpCSF = pumpISF / pumpCarbRatio
|
||||
|
@ -46,92 +45,98 @@ class AutotuneCore @Inject constructor(
|
|||
val autotuneMin = sp.getDouble(R.string.key_openapsama_autosens_min, 0.7)
|
||||
val min5minCarbImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, 3.0)
|
||||
|
||||
/*******Tune DIA (#57-#99) and Peak (#101-#139) disabled for the first version code below in js********************************************************************************************************
|
||||
* // tune DIA
|
||||
* var newDIA = DIA;
|
||||
* if (diaDeviations) {
|
||||
* var currentDIAMeanDev = diaDeviations[2].meanDeviation;
|
||||
* var currentDIARMSDev = diaDeviations[2].RMSDeviation;
|
||||
* //console.error(DIA,currentDIAMeanDev,currentDIARMSDev);
|
||||
* var minMeanDeviations = 1000000;
|
||||
* var minRMSDeviations = 1000000;
|
||||
* var meanBest = 2;
|
||||
* var RMSBest = 2;
|
||||
* for (var i=0; i < diaDeviations.length; i++) {
|
||||
* var meanDeviations = diaDeviations[i].meanDeviation;
|
||||
* var RMSDeviations = diaDeviations[i].RMSDeviation;
|
||||
* if (meanDeviations < minMeanDeviations) {
|
||||
* minMeanDeviations = Math.round(meanDeviations*1000)/1000;
|
||||
* meanBest = i;
|
||||
* }
|
||||
* if (RMSDeviations < minRMSDeviations) {
|
||||
* minRMSDeviations = Math.round(RMSDeviations*1000)/1000;
|
||||
* RMSBest = i;
|
||||
* }
|
||||
* }
|
||||
* console.error("Best insulinEndTime for meanDeviations:",diaDeviations[meanBest].dia,"hours");
|
||||
* console.error("Best insulinEndTime for RMSDeviations:",diaDeviations[RMSBest].dia,"hours");
|
||||
* if ( meanBest < 2 && RMSBest < 2 ) {
|
||||
* if ( diaDeviations[1].meanDeviation < currentDIAMeanDev * 0.99 && diaDeviations[1].RMSDeviation < currentDIARMSDev * 0.99 ) {
|
||||
* newDIA = diaDeviations[1].dia;
|
||||
* }
|
||||
* } else if ( meanBest > 2 && RMSBest > 2 ) {
|
||||
* if ( diaDeviations[3].meanDeviation < currentDIAMeanDev * 0.99 && diaDeviations[3].RMSDeviation < currentDIARMSDev * 0.99 ) {
|
||||
* newDIA = diaDeviations[3].dia;
|
||||
* }
|
||||
* }
|
||||
* if ( newDIA > 12 ) {
|
||||
* console.error("insulinEndTime maximum is 12h: not raising further");
|
||||
* newDIA=12;
|
||||
* }
|
||||
* if ( newDIA !== DIA ) {
|
||||
* console.error("Adjusting insulinEndTime from",DIA,"to",newDIA,"hours");
|
||||
* } else {
|
||||
* console.error("Leaving insulinEndTime unchanged at",DIA,"hours");
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // tune insulinPeakTime
|
||||
* var newPeak = peak;
|
||||
* if (peakDeviations && peakDeviations[2]) {
|
||||
* var currentPeakMeanDev = peakDeviations[2].meanDeviation;
|
||||
* var currentPeakRMSDev = peakDeviations[2].RMSDeviation;
|
||||
* //console.error(currentPeakMeanDev);
|
||||
* minMeanDeviations = 1000000;
|
||||
* minRMSDeviations = 1000000;
|
||||
* meanBest = 2;
|
||||
* RMSBest = 2;
|
||||
* for (i=0; i < peakDeviations.length; i++) {
|
||||
* meanDeviations = peakDeviations[i].meanDeviation;
|
||||
* RMSDeviations = peakDeviations[i].RMSDeviation;
|
||||
* if (meanDeviations < minMeanDeviations) {
|
||||
* minMeanDeviations = Math.round(meanDeviations*1000)/1000;
|
||||
* meanBest = i;
|
||||
* }
|
||||
* if (RMSDeviations < minRMSDeviations) {
|
||||
* minRMSDeviations = Math.round(RMSDeviations*1000)/1000;
|
||||
* RMSBest = i;
|
||||
* }
|
||||
* }
|
||||
* console.error("Best insulinPeakTime for meanDeviations:",peakDeviations[meanBest].peak,"minutes");
|
||||
* console.error("Best insulinPeakTime for RMSDeviations:",peakDeviations[RMSBest].peak,"minutes");
|
||||
* if ( meanBest < 2 && RMSBest < 2 ) {
|
||||
* if ( peakDeviations[1].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[1].RMSDeviation < currentPeakRMSDev * 0.99 ) {
|
||||
* newPeak = peakDeviations[1].peak;
|
||||
* }
|
||||
* } else if ( meanBest > 2 && RMSBest > 2 ) {
|
||||
* if ( peakDeviations[3].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[3].RMSDeviation < currentPeakRMSDev * 0.99 ) {
|
||||
* newPeak = peakDeviations[3].peak;
|
||||
* }
|
||||
* }
|
||||
* if ( newPeak !== peak ) {
|
||||
* console.error("Adjusting insulinPeakTime from",peak,"to",newPeak,"minutes");
|
||||
* } else {
|
||||
* console.error("Leaving insulinPeakTime unchanged at",peak);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
// tune DIA
|
||||
var newDia = dia
|
||||
if (diaDeviations.size > 0)
|
||||
{
|
||||
val currentDiaMeanDev = diaDeviations[2].meanDeviation
|
||||
val currentDiaRMSDev = diaDeviations[2].rmsDeviation
|
||||
//Console.WriteLine(DIA,currentDIAMeanDev,currentDIARMSDev);
|
||||
var minMeanDeviations = 1000000.0
|
||||
var minRmsDeviations = 1000000.0
|
||||
var meanBest = 2
|
||||
var rmsBest = 2
|
||||
for (i in 0..diaDeviations.size-1)
|
||||
{
|
||||
val meanDeviations = diaDeviations[i].meanDeviation
|
||||
val rmsDeviations = diaDeviations[i].rmsDeviation
|
||||
if (meanDeviations < minMeanDeviations)
|
||||
{
|
||||
minMeanDeviations = Round.roundTo(meanDeviations, 0.001)
|
||||
meanBest = i
|
||||
}
|
||||
if (rmsDeviations < minRmsDeviations)
|
||||
{
|
||||
minRmsDeviations = Round.roundTo(rmsDeviations, 0.001)
|
||||
rmsBest = i
|
||||
}
|
||||
}
|
||||
log("Best insulinEndTime for meanDeviations: ${diaDeviations[meanBest].dia} hours")
|
||||
log("Best insulinEndTime for RMSDeviations: ${diaDeviations[rmsBest].dia} hours")
|
||||
if (meanBest < 2 && rmsBest < 2)
|
||||
{
|
||||
if (diaDeviations[1].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[1].rmsDeviation < currentDiaRMSDev * 0.99)
|
||||
newDia = diaDeviations[1].dia
|
||||
}
|
||||
else if (meanBest > 2 && rmsBest > 2)
|
||||
{
|
||||
if (diaDeviations[3].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[3].rmsDeviation < currentDiaRMSDev * 0.99)
|
||||
newDia = diaDeviations[3].dia
|
||||
}
|
||||
if (newDia > 12.0)
|
||||
{
|
||||
log("insulinEndTime maximum is 12h: not raising further")
|
||||
newDia = 12.0
|
||||
}
|
||||
if (newDia != dia)
|
||||
log("Adjusting insulinEndTime from $dia to $newDia hours")
|
||||
else
|
||||
log("Leaving insulinEndTime unchanged at $dia hours")
|
||||
}
|
||||
|
||||
// tune insulinPeakTime
|
||||
var newPeak = peak
|
||||
if (peakDeviations.size > 2)
|
||||
{
|
||||
val currentPeakMeanDev = peakDeviations[2].meanDeviation
|
||||
val currentPeakRMSDev = peakDeviations[2].rmsDeviation
|
||||
//Console.WriteLine(currentPeakMeanDev);
|
||||
var minMeanDeviations = 1000000.0
|
||||
var minRmsDeviations = 1000000.0
|
||||
var meanBest = 2
|
||||
var rmsBest = 2
|
||||
for (i in 0..peakDeviations.size-1)
|
||||
{
|
||||
val meanDeviations = peakDeviations[i].meanDeviation;
|
||||
val rmsDeviations = peakDeviations[i].rmsDeviation;
|
||||
if (meanDeviations < minMeanDeviations)
|
||||
{
|
||||
minMeanDeviations = Round.roundTo(meanDeviations, 0.001)
|
||||
meanBest = i
|
||||
}
|
||||
if (rmsDeviations < minRmsDeviations)
|
||||
{
|
||||
minRmsDeviations = Round.roundTo(rmsDeviations, 0.001)
|
||||
rmsBest = i
|
||||
}
|
||||
}
|
||||
log("Best insulinPeakTime for meanDeviations: ${peakDeviations[meanBest].peak} minutes")
|
||||
log("Best insulinPeakTime for RMSDeviations: ${peakDeviations[rmsBest].peak} minutes")
|
||||
if (meanBest < 2 && rmsBest < 2)
|
||||
{
|
||||
if (peakDeviations[1].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[1].rmsDeviation < currentPeakRMSDev * 0.99)
|
||||
newPeak = peakDeviations[1].peak
|
||||
}
|
||||
else if (meanBest > 2 && rmsBest > 2)
|
||||
{
|
||||
if (peakDeviations[3].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[3].rmsDeviation < currentPeakRMSDev * 0.99)
|
||||
newPeak = peakDeviations[3].peak
|
||||
}
|
||||
if (newPeak != peak)
|
||||
log("Adjusting insulinPeakTime from " + peak + " to " + newPeak + " minutes")
|
||||
else
|
||||
log("Leaving insulinPeakTime unchanged at " + peak)
|
||||
}
|
||||
|
||||
// Calculate carb ratio (CR) independently of csf and isf
|
||||
// Use the time period from meal bolus/carbs until COB is zero and IOB is < currentBasal/2
|
||||
|
@ -142,7 +147,7 @@ class AutotuneCore @Inject constructor(
|
|||
//autotune-core (lib/autotune/index.js) #149-#165
|
||||
var crTotalCarbs = 0.0
|
||||
var crTotalInsulin = 0.0
|
||||
for (i in crData!!.indices) {
|
||||
for (i in crData.indices) {
|
||||
val crDatum = crData[i]
|
||||
val crBGChange = crDatum.crEndBG - crDatum.crInitialBG
|
||||
val crInsulinReq = crBGChange / isf
|
||||
|
@ -181,7 +186,7 @@ class AutotuneCore @Inject constructor(
|
|||
// look at net deviations for each hour
|
||||
for (hour in 0..23) {
|
||||
var deviations = 0.0
|
||||
for (i in basalGlucose!!.indices) {
|
||||
for (i in basalGlucose.indices) {
|
||||
val BGTime = Calendar.getInstance()
|
||||
//var BGTime: Date? = null
|
||||
if (basalGlucose[i].date != 0L) {
|
||||
|
@ -300,7 +305,7 @@ class AutotuneCore @Inject constructor(
|
|||
//log.debug(CSFGlucose[0].mealAbsorption);
|
||||
//log.debug(CSFGlucose[0]);
|
||||
//autotune-core (lib/autotune/index.js) #346-#365
|
||||
for (i in csfGlucose!!.indices) {
|
||||
for (i in csfGlucose.indices) {
|
||||
//log.debug(CSFGlucose[i].mealAbsorption, i);
|
||||
if (csfGlucose[i].mealAbsorption === "start") {
|
||||
deviations = 0.0
|
||||
|
@ -412,7 +417,7 @@ class AutotuneCore @Inject constructor(
|
|||
val avgDeltas: MutableList<Double> = ArrayList()
|
||||
val ratios: MutableList<Double> = ArrayList()
|
||||
var count = 0
|
||||
for (i in isfGlucose!!.indices) {
|
||||
for (i in isfGlucose.indices) {
|
||||
val deviation = isfGlucose[i].deviation
|
||||
isfDeviations.add(deviation)
|
||||
val BGI = isfGlucose[i].bgi
|
||||
|
@ -497,13 +502,10 @@ class AutotuneCore @Inject constructor(
|
|||
previousAutotune.isf = isf
|
||||
previousAutotune.ic = Round.roundTo(carbRatio, 0.001)
|
||||
previousAutotune.basalUntuned = basalUntuned
|
||||
/* code prepared for future dia/peak integration
|
||||
previousAutotune.dia=newDia;
|
||||
previousAutotune.peak = newPeak ;
|
||||
if (diaDeviations || peakDeviations) {
|
||||
autotuneOutput.useCustomPeakTime = true;
|
||||
}
|
||||
*/
|
||||
previousAutotune.dia = newDia
|
||||
previousAutotune.peak = newPeak
|
||||
val localInsulin = LocalInsulin("Ins_$newPeak-$newDia", newPeak, newDia)
|
||||
previousAutotune.localInsulin = localInsulin
|
||||
previousAutotune.updateProfile()
|
||||
return previousAutotune
|
||||
}
|
||||
|
|
|
@ -384,6 +384,7 @@ class AutotuneFragment : DaggerFragment() {
|
|||
if (autotunePlugin.result.isNotBlank()) {
|
||||
var toMgDl = 1.0
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MMOL) toMgDl = Constants.MMOLL_TO_MGDL
|
||||
var isf_Format = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "%.2f" else "%.1f"
|
||||
binding.autotuneResults.addView(
|
||||
TableLayout(context).also { layout ->
|
||||
layout.addView(
|
||||
|
@ -395,8 +396,13 @@ class AutotuneFragment : DaggerFragment() {
|
|||
})
|
||||
autotunePlugin.tunedProfile?.let { tuned ->
|
||||
layout.addView(toTableRowHeader())
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.isf_short), Round.roundTo(autotunePlugin.pumpProfile.isf / toMgDl, 0.001), Round.roundTo(tuned.isf / toMgDl, 0.001)))
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.ic_short), Round.roundTo(autotunePlugin.pumpProfile.ic, 0.001), Round.roundTo(tuned.ic, 0.001)))
|
||||
val tuneInsulin = sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)
|
||||
if (tuneInsulin) {
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.insulin_peak), autotunePlugin.pumpProfile.localInsulin.peak.toDouble(), tuned.localInsulin.peak.toDouble(), "%.0f"))
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.dia), Round.roundTo(autotunePlugin.pumpProfile.localInsulin.dia, 0.1), Round.roundTo(tuned.localInsulin.dia, 0.1),"%.1f"))
|
||||
}
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.isf_short), Round.roundTo(autotunePlugin.pumpProfile.isf / toMgDl, 0.001), Round.roundTo(tuned.isf / toMgDl, 0.001), isf_Format))
|
||||
layout.addView(toTableRowValue(rh.gs(R.string.ic_short), Round.roundTo(autotunePlugin.pumpProfile.ic, 0.001), Round.roundTo(tuned.ic, 0.001), "%.2f"))
|
||||
layout.addView(
|
||||
TextView(context).apply {
|
||||
text = rh.gs(R.string.basal)
|
||||
|
@ -413,7 +419,7 @@ class AutotuneFragment : DaggerFragment() {
|
|||
val time = df.format(h.toLong()) + ":00"
|
||||
totalPump += autotunePlugin.pumpProfile.basal[h]
|
||||
totalTuned += tuned.basal[h]
|
||||
layout.addView(toTableRowValue(time, autotunePlugin.pumpProfile.basal[h], tuned.basal[h], tuned.basalUntuned[h].toString()))
|
||||
layout.addView(toTableRowValue(time, autotunePlugin.pumpProfile.basal[h], tuned.basal[h], "%.3f", tuned.basalUntuned[h].toString()))
|
||||
}
|
||||
layout.addView(toTableRowValue("∑", totalPump, totalTuned, " "))
|
||||
}
|
||||
|
@ -456,7 +462,7 @@ class AutotuneFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
|
||||
private fun toTableRowValue(hour: String, inputValue: Double, tunedValue: Double, missing: String = ""): TableRow =
|
||||
private fun toTableRowValue(hour: String, inputValue: Double, tunedValue: Double, format:String = "%.3f", missing: String = ""): TableRow =
|
||||
TableRow(context).also { row ->
|
||||
val percentValue = Round.roundTo(tunedValue / inputValue * 100 - 100, 1.0).toInt().toString() + "%"
|
||||
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f }
|
||||
|
@ -469,12 +475,12 @@ class AutotuneFragment : DaggerFragment() {
|
|||
row.addView(TextView(context).apply {
|
||||
layoutParams = lp.apply { column = 1 }
|
||||
textAlignment = TextView.TEXT_ALIGNMENT_CENTER
|
||||
text = String.format("%.3f", inputValue)
|
||||
text = String.format(format, inputValue)
|
||||
})
|
||||
row.addView(TextView(context).apply {
|
||||
layoutParams = lp.apply { column = 2 }
|
||||
textAlignment = TextView.TEXT_ALIGNMENT_CENTER
|
||||
text = String.format("%.3f", tunedValue)
|
||||
text = String.format(format, tunedValue)
|
||||
})
|
||||
row.addView(TextView(context).apply {
|
||||
layoutParams = lp.apply { column = 3 }
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.inject.Singleton
|
|||
* adaptation from oref0 autotune started by philoul on 2020 (complete refactoring of AutotunePlugin initialised by Rumen Georgiev on 1/29/2018.)
|
||||
*
|
||||
* TODO: replace Thread by Worker
|
||||
* TODO: future version (once first version validated): add DIA and Peak tune for insulin
|
||||
* TODO: future version: Allow day of the week selection to tune specifics days (training days, working days, WE days)
|
||||
*/
|
||||
|
||||
|
@ -94,7 +93,7 @@ class AutotunePlugin @Inject constructor(
|
|||
profileFunction.getProfile()?.let { currentProfile ->
|
||||
profile = profileStore.getSpecificProfile(profileToTune)?.let { ProfileSealed.Pure(it) } ?: currentProfile
|
||||
}
|
||||
var localInsulin = LocalInsulin("PumpInsulin", activePlugin.activeInsulin.peak, profile.dia) // var because localInsulin could be updated later with Tune Insulin peak/dia
|
||||
val localInsulin = LocalInsulin("PumpInsulin", activePlugin.activeInsulin.peak, profile.dia) // var because localInsulin could be updated later with Tune Insulin peak/dia
|
||||
|
||||
log("Start Autotune with $daysBack days back")
|
||||
autotuneFS.createAutotuneFolder() //create autotune subfolder for autotune files if not exists
|
||||
|
@ -120,7 +119,7 @@ class AutotunePlugin @Inject constructor(
|
|||
autotuneIob.initializeData(from, to, tunedProfile) //autotuneIob contains BG and Treatments data from history (<=> query for ns-treatments and ns-entries)
|
||||
autotuneFS.exportEntries(autotuneIob) //<=> ns-entries.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||
autotuneFS.exportTreatments(autotuneIob) //<=> ns-treatments.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine (include treatments ,tempBasal and extended
|
||||
preppedGlucose = autotunePrep.categorizeBGDatums(tunedProfile, localInsulin) //<=> autotune.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||
preppedGlucose = autotunePrep.categorize(tunedProfile) //<=> autotune.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||
}
|
||||
|
||||
if (preppedGlucose == null || tunedProfile == null) {
|
||||
|
@ -204,9 +203,14 @@ class AutotunePlugin @Inject constructor(
|
|||
var strResult = line
|
||||
strResult += rh.gs(R.string.autotune_log_title)
|
||||
strResult += line
|
||||
val tuneInsulin = sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)
|
||||
if (tuneInsulin) {
|
||||
strResult += rh.gs(R.string.autotune_log_peak, rh.gs(R.string.insulin_peak), pumpProfile.localInsulin.peak, tunedProfile.localInsulin.peak)
|
||||
strResult += rh.gs(R.string.autotune_log_dia, rh.gs(R.string.ic_short), pumpProfile.localInsulin.dia, tunedProfile.localInsulin.dia)
|
||||
}
|
||||
// show ISF and CR
|
||||
strResult += rh.gs(R.string.autotune_log_isf, rh.gs(R.string.isf_short), pumpProfile.isf, tunedProfile.isf)
|
||||
strResult += rh.gs(R.string.autotune_log_ic, rh.gs(R.string.ic_short), pumpProfile.ic, tunedProfile.ic)
|
||||
strResult += rh.gs(R.string.autotune_log_ic_isf, rh.gs(R.string.isf_short), pumpProfile.isf, tunedProfile.isf)
|
||||
strResult += rh.gs(R.string.autotune_log_ic_isf, rh.gs(R.string.ic_short), pumpProfile.ic, tunedProfile.ic)
|
||||
strResult += line
|
||||
var totalBasal = 0.0
|
||||
var totalTuned = 0.0
|
||||
|
@ -232,7 +236,7 @@ class AutotunePlugin @Inject constructor(
|
|||
val endDateString = dateUtil.toISOString(lastloopend - 24 * 60 * 60 * 1000L).substring(0,10)
|
||||
val nsUrl = sp.getString(R.string.key_nsclientinternal_url, "")
|
||||
val optCategorizeUam = if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) "-c=true" else ""
|
||||
val optInsulinCurve = ""
|
||||
val optInsulinCurve = if (sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)) "-i=true" else ""
|
||||
try {
|
||||
jsonSettings.put("datestring", dateUtil.toISOString(runDate))
|
||||
jsonSettings.put("dateutc", dateUtil.toISOAsUTC(runDate))
|
||||
|
|
|
@ -3,14 +3,13 @@ package info.nightscout.androidaps.plugins.general.autotune
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.LocalInsulin
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.BGDatum
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.CRDatum
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose
|
||||
import info.nightscout.androidaps.plugins.general.autotune.data.*
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.Carbs
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.MidnightTime
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -23,11 +22,121 @@ class AutotunePrep @Inject constructor(
|
|||
private val autotuneFS: AutotuneFS,
|
||||
private val autotuneIob: AutotuneIob
|
||||
) {
|
||||
fun categorize(tunedprofile: ATProfile): PreppedGlucose? {
|
||||
val preppedGlucose = categorizeBGDatums(tunedprofile, tunedprofile.localInsulin)
|
||||
val tuneInsulin = sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)
|
||||
if (tuneInsulin) {
|
||||
var minDeviations = 1000000.0
|
||||
val diaDeviations: MutableList<DiaDeviation> = ArrayList()
|
||||
val peakDeviations: MutableList<PeakDeviation> = ArrayList()
|
||||
val currentDIA = tunedprofile.localInsulin.dia
|
||||
val currentPeak = tunedprofile.localInsulin.peak
|
||||
|
||||
var dia = currentDIA - 2
|
||||
val endDIA = currentDIA + 2
|
||||
while (dia <= endDIA)
|
||||
{
|
||||
var sqrtDeviations = 0.0
|
||||
var deviations = 0.0
|
||||
var deviationsSq = 0.0
|
||||
val localInsulin = LocalInsulin("Ins_$currentPeak-$dia", currentPeak, dia)
|
||||
val curve_output = categorizeBGDatums(tunedprofile, localInsulin, false)
|
||||
val basalGlucose = curve_output?.basalGlucoseData
|
||||
|
||||
basalGlucose?.let {
|
||||
for (hour in 0..23) {
|
||||
for (i in 0..(basalGlucose.size-1)) {
|
||||
val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt()
|
||||
if (hour == myHour) {
|
||||
sqrtDeviations += Math.pow(Math.abs(basalGlucose[i].deviation), 0.5)
|
||||
deviations += Math.abs(basalGlucose[i].deviation)
|
||||
deviationsSq += Math.pow(basalGlucose[i].deviation, 2.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val meanDeviation = Round.roundTo(Math.abs(deviations / basalGlucose.size), 0.001)
|
||||
val smrDeviation = Round.roundTo(Math.pow(sqrtDeviations / basalGlucose.size, 2.0), 0.001)
|
||||
val rmsDeviation = Round.roundTo(Math.pow(deviationsSq / basalGlucose.size, 0.5), 0.001)
|
||||
log("insulinEndTime $dia meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)")
|
||||
diaDeviations.add(
|
||||
DiaDeviation(
|
||||
dia = dia,
|
||||
meanDeviation = meanDeviation,
|
||||
smrDeviation = smrDeviation,
|
||||
rmsDeviation = rmsDeviation
|
||||
)
|
||||
)
|
||||
}
|
||||
preppedGlucose?.diaDeviations = diaDeviations
|
||||
|
||||
deviations = Round.roundTo(deviations, 0.001)
|
||||
if (deviations < minDeviations)
|
||||
minDeviations = Round.roundTo(deviations, 0.001)
|
||||
dia += 1.0
|
||||
}
|
||||
|
||||
// consoleError('Optimum insulinEndTime', newDIA, 'mean deviation:', JSMath.Round(minDeviations/basalGlucose.length*1000)/1000, '(mg/dL)');
|
||||
//consoleError(diaDeviations);
|
||||
|
||||
minDeviations = 1000000.0
|
||||
var peak = currentPeak - 10
|
||||
val endPeak = currentPeak + 10
|
||||
while (peak <= endPeak)
|
||||
{
|
||||
var sqrtDeviations = 0.0
|
||||
var deviations = 0.0
|
||||
var deviationsSq = 0.0
|
||||
val localInsulin = LocalInsulin("Ins_$peak-$currentDIA", peak, currentDIA)
|
||||
val curve_output = categorizeBGDatums(tunedprofile, localInsulin, false)
|
||||
val basalGlucose = curve_output?.basalGlucoseData
|
||||
|
||||
basalGlucose?.let {
|
||||
for (hour in 0..23) {
|
||||
for (i in 0..(basalGlucose.size - 1)) {
|
||||
val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt()
|
||||
if (hour == myHour) {
|
||||
//console.error(basalGlucose[i].deviation);
|
||||
sqrtDeviations += Math.pow(Math.abs(basalGlucose[i].deviation), 0.5)
|
||||
deviations += Math.abs(basalGlucose[i].deviation)
|
||||
deviationsSq += Math.pow(basalGlucose[i].deviation, 2.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val meanDeviation = Round.roundTo(deviations / basalGlucose.size, 0.001)
|
||||
val smrDeviation = Round.roundTo(Math.pow(sqrtDeviations / basalGlucose.size, 2.0), 0.001)
|
||||
val rmsDeviation = Round.roundTo(Math.pow(deviationsSq / basalGlucose.size, 0.5), 0.001)
|
||||
log("insulinPeakTime $peak meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)")
|
||||
peakDeviations.add(
|
||||
PeakDeviation
|
||||
(
|
||||
peak = peak,
|
||||
meanDeviation = meanDeviation,
|
||||
smrDeviation = smrDeviation,
|
||||
rmsDeviation = rmsDeviation,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
deviations = Round.roundTo(deviations, 0.001);
|
||||
if (deviations < minDeviations)
|
||||
minDeviations = Round.roundTo(deviations, 0.001)
|
||||
peak += 5
|
||||
}
|
||||
//consoleError($"Optimum insulinPeakTime {newPeak} mean deviation: {JSMath.Round(minDeviations/basalGlucose.Count, 3)} (mg/dL)");
|
||||
//consoleError(peakDeviations);
|
||||
preppedGlucose?.peakDeviations = peakDeviations
|
||||
}
|
||||
|
||||
return preppedGlucose
|
||||
}
|
||||
|
||||
// private static Logger log = LoggerFactory.getLogger(AutotunePlugin.class);
|
||||
fun categorizeBGDatums(tunedprofile: ATProfile, localInsulin: LocalInsulin): PreppedGlucose? {
|
||||
fun categorizeBGDatums(tunedprofile: ATProfile, localInsulin: LocalInsulin, verbose: Boolean = true): PreppedGlucose? {
|
||||
//lib/meals is called before to get only meals data (in AAPS it's done in AutotuneIob)
|
||||
var treatments: MutableList<Carbs> = autotuneIob.meals
|
||||
var boluses: MutableList<Bolus> = autotuneIob.boluses
|
||||
val treatments: MutableList<Carbs> = autotuneIob.meals
|
||||
val boluses: MutableList<Bolus> = autotuneIob.boluses
|
||||
// Bloc between #21 and # 54 replaced by bloc below (just remove BG value below 39, Collections.sort probably not necessary because BG values already sorted...)
|
||||
val glucose = autotuneIob.glucose
|
||||
val glucoseData: MutableList<GlucoseValue> = ArrayList()
|
||||
|
@ -37,6 +146,7 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
}
|
||||
if (glucose.size == 0 || glucoseData.size == 0 ) {
|
||||
if (verbose)
|
||||
log("No BG value received")
|
||||
return null
|
||||
}
|
||||
|
@ -49,10 +159,12 @@ class AutotunePrep @Inject constructor(
|
|||
//val boluses = 0
|
||||
//val maxCarbs = 0
|
||||
if (treatments.size == 0) {
|
||||
if (verbose)
|
||||
log("No Carbs entries")
|
||||
//return null
|
||||
}
|
||||
if (autotuneIob.boluses.size == 0) {
|
||||
if (verbose)
|
||||
log("No treatment received")
|
||||
return null
|
||||
}
|
||||
|
@ -141,6 +253,7 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
avgDelta = (bg - bucketedData[i + 4].value) / 4
|
||||
} else {
|
||||
if (verbose)
|
||||
log("Could not find glucose data")
|
||||
}
|
||||
avgDelta = Round.roundTo(avgDelta, 0.01)
|
||||
|
@ -207,6 +320,7 @@ class AutotunePrep @Inject constructor(
|
|||
crInitialIOB = iob.iob
|
||||
crInitialBG = glucoseDatum.value
|
||||
crInitialCarbTime = glucoseDatum.date
|
||||
if (verbose)
|
||||
log("CRInitialIOB: " + crInitialIOB + " CRInitialBG: " + crInitialBG + " CRInitialCarbTime: " + dateUtil.toISOString(crInitialCarbTime))
|
||||
}
|
||||
// keep calculatingCR as long as we have COB or enough IOB
|
||||
|
@ -219,6 +333,7 @@ class AutotunePrep @Inject constructor(
|
|||
val crEndIOB = iob.iob
|
||||
val crEndBG = glucoseDatum.value
|
||||
val crEndTime = glucoseDatum.date
|
||||
if (verbose)
|
||||
log("CREndIOB: " + crEndIOB + " CREndBG: " + crEndBG + " CREndTime: " + dateUtil.toISOString(crEndTime))
|
||||
val crDatum = CRDatum(dateUtil)
|
||||
crDatum.crInitialBG = crInitialBG
|
||||
|
@ -234,6 +349,7 @@ class AutotunePrep @Inject constructor(
|
|||
|
||||
//log.debug(CREndTime - CRInitialCarbTime, CRElapsedMinutes);
|
||||
if (CRElapsedMinutes < 60 || i == 1 && mealCOB > 0) {
|
||||
if (verbose)
|
||||
log("Ignoring $CRElapsedMinutes m CR period.")
|
||||
} else {
|
||||
crData.add(crDatum)
|
||||
|
@ -262,6 +378,7 @@ class AutotunePrep @Inject constructor(
|
|||
//log.debug(type);
|
||||
if (type != "csf") {
|
||||
glucoseDatum.mealAbsorption = "start"
|
||||
if (verbose)
|
||||
log(glucoseDatum.mealAbsorption + " carb absorption")
|
||||
}
|
||||
type = "csf"
|
||||
|
@ -272,6 +389,7 @@ class AutotunePrep @Inject constructor(
|
|||
// check previous "type" value, and if it was csf, set a mealAbsorption end flag
|
||||
if (type == "csf") {
|
||||
csfGlucoseData[csfGlucoseData.size - 1].mealAbsorption = "end"
|
||||
if (verbose)
|
||||
log(csfGlucoseData[csfGlucoseData.size - 1].mealAbsorption + " carb absorption")
|
||||
}
|
||||
if (iob.iob > 2 * currentBasal || deviation > 6 || uam) {
|
||||
|
@ -282,12 +400,14 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
if (type != "uam") {
|
||||
glucoseDatum.uamAbsorption = "start"
|
||||
if (verbose)
|
||||
log(glucoseDatum.uamAbsorption + " unannnounced meal absorption")
|
||||
}
|
||||
type = "uam"
|
||||
uamGlucoseData.add(glucoseDatum)
|
||||
} else {
|
||||
if (type == "uam") {
|
||||
if (verbose)
|
||||
log("end unannounced meal absorption")
|
||||
}
|
||||
|
||||
|
@ -313,6 +433,7 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
}
|
||||
// debug line to print out all the things
|
||||
if (verbose)
|
||||
log((if (absorbing) 1 else 0).toString() + " mealCOB: " + Round.roundTo(mealCOB, 0.1) + " mealCarbs: " + Math.round(mealCarbs) + " basalBGI: " + Round.roundTo(basalBGI, 0.1) + " BGI: " + Round.roundTo(BGI, 0.1) + " IOB: " + iob.iob+ " Activity: " + iob.activity + " at " + dateUtil.timeStringWithSeconds(BGTime) + " dev: " + deviation + " avgDelta: " + avgDelta + " " + type)
|
||||
}
|
||||
|
||||
|
@ -328,16 +449,20 @@ class AutotunePrep @Inject constructor(
|
|||
val UAMLength = uamGlucoseData.size
|
||||
var basalLength = basalGlucoseData.size
|
||||
if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) {
|
||||
if (verbose)
|
||||
log("Categorizing all UAM data as basal.")
|
||||
basalGlucoseData.addAll(uamGlucoseData)
|
||||
} else if (CSFLength > 12) {
|
||||
if (verbose)
|
||||
log("Found at least 1h of carb: assuming meals were announced, and categorizing UAM data as basal.")
|
||||
basalGlucoseData.addAll(uamGlucoseData)
|
||||
} else {
|
||||
if (2 * basalLength < UAMLength) {
|
||||
//log.debug(basalGlucoseData, UAMGlucoseData);
|
||||
if (verbose) {
|
||||
log("Warning: too many deviations categorized as UnAnnounced Meals")
|
||||
log("Adding $UAMLength UAM deviations to $basalLength basal ones")
|
||||
}
|
||||
basalGlucoseData.addAll(uamGlucoseData)
|
||||
//log.debug(basalGlucoseData);
|
||||
// if too much data is excluded as UAM, add in the UAM deviations, but then discard the highest 50%
|
||||
|
@ -348,9 +473,11 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
//log.debug(newBasalGlucose);
|
||||
basalGlucoseData = newBasalGlucose
|
||||
if (verbose)
|
||||
log("and selecting the lowest 50%, leaving " + basalGlucoseData.size + " basal+UAM ones")
|
||||
}
|
||||
if (2 * ISFLength < UAMLength) {
|
||||
if (verbose)
|
||||
log("Adding $UAMLength UAM deviations to $ISFLength ISF ones")
|
||||
isfGlucoseData.addAll(uamGlucoseData)
|
||||
// if too much data is excluded as UAM, add in the UAM deviations to ISF, but then discard the highest 50%
|
||||
|
@ -361,6 +488,7 @@ class AutotunePrep @Inject constructor(
|
|||
}
|
||||
//console.error(newISFGlucose);
|
||||
isfGlucoseData = newISFGlucose
|
||||
if (verbose)
|
||||
log("and selecting the lowest 50%, leaving " + isfGlucoseData.size + " ISF+UAM ones")
|
||||
//log.error(ISFGlucoseData.length, UAMLength);
|
||||
}
|
||||
|
@ -368,171 +496,21 @@ class AutotunePrep @Inject constructor(
|
|||
basalLength = basalGlucoseData.size
|
||||
ISFLength = isfGlucoseData.size
|
||||
if (4 * basalLength + ISFLength < CSFLength && ISFLength < 10) {
|
||||
if (verbose) {
|
||||
log("Warning: too many deviations categorized as meals")
|
||||
//log.debug("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones");
|
||||
//var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData);
|
||||
log("Adding $CSFLength CSF deviations to $ISFLength ISF ones")
|
||||
}
|
||||
isfGlucoseData.addAll(csfGlucoseData)
|
||||
csfGlucoseData = ArrayList()
|
||||
}
|
||||
|
||||
// categorize.js Lines 437-444
|
||||
if (verbose)
|
||||
log("CRData: " + crData.size + " CSFGlucoseData: " + csfGlucoseData.size + " ISFGlucoseData: " + isfGlucoseData.size + " BasalGlucoseData: " + basalGlucoseData.size)
|
||||
// Here is the end of categorize.js file
|
||||
|
||||
/* bloc below is for --tune-insulin-curve not developed for the moment
|
||||
// these lines are in index.js file (autotune-prep folder)
|
||||
if (inputs.tune_insulin_curve) {
|
||||
if (opts.profile.curve === 'bilinear') {
|
||||
console.error('--tune-insulin-curve is set but only valid for exponential curves');
|
||||
} else {
|
||||
var minDeviations = 1000000;
|
||||
var newDIA = 0;
|
||||
var diaDeviations = [];
|
||||
var peakDeviations = [];
|
||||
var currentDIA = opts.profile.dia;
|
||||
var currentPeak = opts.profile.insulinPeakTime;
|
||||
|
||||
var consoleError = console.error;
|
||||
console.error = function() {};
|
||||
|
||||
var startDIA=currentDIA - 2;
|
||||
var endDIA=currentDIA + 2;
|
||||
for (var dia=startDIA; dia <= endDIA; ++dia) {
|
||||
var sqrtDeviations = 0;
|
||||
var deviations = 0;
|
||||
var deviationsSq = 0;
|
||||
|
||||
opts.profile.dia = dia;
|
||||
|
||||
var curve_output = categorize(opts);
|
||||
var basalGlucose = curve_output.basalGlucoseData;
|
||||
|
||||
for (var hour=0; hour < 24; ++hour) {
|
||||
for (var i=0; i < basalGlucose.length; ++i) {
|
||||
var BGTime;
|
||||
|
||||
if (basalGlucose[i].date) {
|
||||
BGTime = new Date(basalGlucose[i].date);
|
||||
} else if (basalGlucose[i].displayTime) {
|
||||
BGTime = new Date(basalGlucose[i].displayTime.replace('T', ' '));
|
||||
} else if (basalGlucose[i].dateString) {
|
||||
BGTime = new Date(basalGlucose[i].dateString);
|
||||
} else {
|
||||
consoleError("Could not determine last BG time");
|
||||
}
|
||||
|
||||
var myHour = BGTime.getHours();
|
||||
if (hour === myHour) {
|
||||
//console.error(basalGlucose[i].deviation);
|
||||
sqrtDeviations += Math.pow(parseFloat(Math.abs(basalGlucose[i].deviation)), 0.5);
|
||||
deviations += Math.abs(parseFloat(basalGlucose[i].deviation));
|
||||
deviationsSq += Math.pow(parseFloat(basalGlucose[i].deviation), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var meanDeviation = Math.round(Math.abs(deviations/basalGlucose.length)*1000)/1000;
|
||||
var SMRDeviation = Math.round(Math.pow(sqrtDeviations/basalGlucose.length,2)*1000)/1000;
|
||||
var RMSDeviation = Math.round(Math.pow(deviationsSq/basalGlucose.length,0.5)*1000)/1000;
|
||||
consoleError('insulinEndTime', dia, 'meanDeviation:', meanDeviation, 'SMRDeviation:', SMRDeviation, 'RMSDeviation:',RMSDeviation, '(mg/dL)');
|
||||
diaDeviations.push({
|
||||
dia: dia,
|
||||
meanDeviation: meanDeviation,
|
||||
SMRDeviation: SMRDeviation,
|
||||
RMSDeviation: RMSDeviation,
|
||||
});
|
||||
autotune_prep_output.diaDeviations = diaDeviations;
|
||||
|
||||
deviations = Math.round(deviations*1000)/1000;
|
||||
if (deviations < minDeviations) {
|
||||
minDeviations = Math.round(deviations*1000)/1000;
|
||||
newDIA = dia;
|
||||
}
|
||||
}
|
||||
|
||||
// consoleError('Optimum insulinEndTime', newDIA, 'mean deviation:', Math.round(minDeviations/basalGlucose.length*1000)/1000, '(mg/dL)');
|
||||
//consoleError(diaDeviations);
|
||||
|
||||
minDeviations = 1000000;
|
||||
|
||||
var newPeak = 0;
|
||||
opts.profile.dia = currentDIA;
|
||||
//consoleError(opts.profile.useCustomPeakTime, opts.profile.insulinPeakTime);
|
||||
if ( ! opts.profile.useCustomPeakTime === true && opts.profile.curve === "ultra-rapid" ) {
|
||||
opts.profile.insulinPeakTime = 55;
|
||||
} else if ( ! opts.profile.useCustomPeakTime === true ) {
|
||||
opts.profile.insulinPeakTime = 75;
|
||||
}
|
||||
opts.profile.useCustomPeakTime = true;
|
||||
|
||||
var startPeak=opts.profile.insulinPeakTime - 10;
|
||||
var endPeak=opts.profile.insulinPeakTime + 10;
|
||||
for (var peak=startPeak; peak <= endPeak; peak=(peak+5)) {
|
||||
sqrtDeviations = 0;
|
||||
deviations = 0;
|
||||
deviationsSq = 0;
|
||||
|
||||
opts.profile.insulinPeakTime = peak;
|
||||
|
||||
|
||||
curve_output = categorize(opts);
|
||||
basalGlucose = curve_output.basalGlucoseData;
|
||||
|
||||
for (hour=0; hour < 24; ++hour) {
|
||||
for (i=0; i < basalGlucose.length; ++i) {
|
||||
if (basalGlucose[i].date) {
|
||||
BGTime = new Date(basalGlucose[i].date);
|
||||
} else if (basalGlucose[i].displayTime) {
|
||||
BGTime = new Date(basalGlucose[i].displayTime.replace('T', ' '));
|
||||
} else if (basalGlucose[i].dateString) {
|
||||
BGTime = new Date(basalGlucose[i].dateString);
|
||||
} else {
|
||||
consoleError("Could not determine last BG time");
|
||||
}
|
||||
|
||||
myHour = BGTime.getHours();
|
||||
if (hour === myHour) {
|
||||
//console.error(basalGlucose[i].deviation);
|
||||
sqrtDeviations += Math.pow(parseFloat(Math.abs(basalGlucose[i].deviation)), 0.5);
|
||||
deviations += Math.abs(parseFloat(basalGlucose[i].deviation));
|
||||
deviationsSq += Math.pow(parseFloat(basalGlucose[i].deviation), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.error(deviationsSq);
|
||||
|
||||
meanDeviation = Math.round(deviations/basalGlucose.length*1000)/1000;
|
||||
SMRDeviation = Math.round(Math.pow(sqrtDeviations/basalGlucose.length,2)*1000)/1000;
|
||||
RMSDeviation = Math.round(Math.pow(deviationsSq/basalGlucose.length,0.5)*1000)/1000;
|
||||
consoleError('insulinPeakTime', peak, 'meanDeviation:', meanDeviation, 'SMRDeviation:', SMRDeviation, 'RMSDeviation:',RMSDeviation, '(mg/dL)');
|
||||
peakDeviations.push({
|
||||
peak: peak,
|
||||
meanDeviation: meanDeviation,
|
||||
SMRDeviation: SMRDeviation,
|
||||
RMSDeviation: RMSDeviation,
|
||||
});
|
||||
autotune_prep_output.diaDeviations = diaDeviations;
|
||||
|
||||
deviations = Math.round(deviations*1000)/1000;
|
||||
if (deviations < minDeviations) {
|
||||
minDeviations = Math.round(deviations*1000)/1000;
|
||||
newPeak = peak;
|
||||
}
|
||||
}
|
||||
|
||||
//consoleError('Optimum insulinPeakTime', newPeak, 'mean deviation:', Math.round(minDeviations/basalGlucose.length*1000)/1000, '(mg/dL)');
|
||||
//consoleError(peakDeviations);
|
||||
autotune_prep_output.peakDeviations = peakDeviations;
|
||||
|
||||
console.error = consoleError;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return PreppedGlucose(autotuneIob.startBG, crData, csfGlucoseData, isfGlucoseData, basalGlucoseData, dateUtil)
|
||||
|
||||
// and may be later
|
||||
// return new PreppedGlucose(crData, csfGlucoseData, isfGlucoseData, basalGlucoseData, diaDeviations, peakDeviations);
|
||||
}
|
||||
|
||||
//dosed.js full
|
||||
|
|
|
@ -3,15 +3,9 @@ package info.nightscout.androidaps.plugins.general.autotune.data
|
|||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
class DiaDatum {
|
||||
class DiaDeviation(var dia: Double = 0.0, var meanDeviation: Double = 0.0, var smrDeviation: Double = 0.0, var rmsDeviation: Double = 0.0) {
|
||||
|
||||
var dia = 0.0
|
||||
var meanDeviation = 0.0
|
||||
var smrDeviation = 0.0
|
||||
var rmsDeviation = 0.0
|
||||
|
||||
constructor() {}
|
||||
constructor(json: JSONObject) {
|
||||
constructor(json: JSONObject) : this() {
|
||||
try {
|
||||
if (json.has("dia")) dia = json.getDouble("dia")
|
||||
if (json.has("meanDeviation")) meanDeviation = json.getDouble("meanDeviation")
|
||||
|
@ -32,13 +26,4 @@ class DiaDatum {
|
|||
}
|
||||
return crjson
|
||||
}
|
||||
|
||||
fun equals(obj: DiaDatum): Boolean {
|
||||
var isEqual = true
|
||||
if (dia != obj.dia) isEqual = false
|
||||
if (meanDeviation != obj.meanDeviation) isEqual = false
|
||||
if (smrDeviation != obj.smrDeviation) isEqual = false
|
||||
if (rmsDeviation != obj.rmsDeviation) isEqual = false
|
||||
return isEqual
|
||||
}
|
||||
}
|
|
@ -3,17 +3,11 @@ package info.nightscout.androidaps.plugins.general.autotune.data
|
|||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
class PeakDatum {
|
||||
class PeakDeviation(var peak: Int = 0, var meanDeviation: Double = 0.0, var smrDeviation: Double = 0.0, var rmsDeviation: Double = 0.0) {
|
||||
|
||||
var peak = 0.0
|
||||
var meanDeviation = 0.0
|
||||
var smrDeviation = 0.0
|
||||
var rmsDeviation = 0.0
|
||||
|
||||
constructor() {}
|
||||
constructor(json: JSONObject) {
|
||||
constructor(json: JSONObject) : this() {
|
||||
try {
|
||||
if (json.has("peak")) peak = json.getDouble("peak")
|
||||
if (json.has("peak")) peak = json.getInt("peak")
|
||||
if (json.has("meanDeviation")) meanDeviation = json.getDouble("meanDeviation")
|
||||
if (json.has("SMRDeviation")) smrDeviation = json.getDouble("SMRDeviation")
|
||||
if (json.has("RMSDeviation")) rmsDeviation = json.getDouble("RMSDeviation")
|
||||
|
@ -32,13 +26,4 @@ class PeakDatum {
|
|||
}
|
||||
return crjson
|
||||
}
|
||||
|
||||
fun equals(obj: PeakDatum): Boolean {
|
||||
var isEqual = true
|
||||
if (peak != obj.peak) isEqual = false
|
||||
if (meanDeviation != obj.meanDeviation) isEqual = false
|
||||
if (smrDeviation != obj.smrDeviation) isEqual = false
|
||||
if (rmsDeviation != obj.rmsDeviation) isEqual = false
|
||||
return isEqual
|
||||
}
|
||||
}
|
|
@ -8,12 +8,12 @@ import java.util.*
|
|||
|
||||
class PreppedGlucose {
|
||||
|
||||
var crData: List<CRDatum>? = ArrayList()
|
||||
var csfGlucoseData: List<BGDatum>? = ArrayList()
|
||||
var isfGlucoseData: List<BGDatum>? = ArrayList()
|
||||
var basalGlucoseData: List<BGDatum>? = ArrayList()
|
||||
var diaDeviations: List<DiaDatum> = ArrayList()
|
||||
var peakDeviations: List<PeakDatum> = ArrayList()
|
||||
var crData: List<CRDatum> = ArrayList()
|
||||
var csfGlucoseData: List<BGDatum> = ArrayList()
|
||||
var isfGlucoseData: List<BGDatum> = ArrayList()
|
||||
var basalGlucoseData: List<BGDatum> = ArrayList()
|
||||
var diaDeviations: List<DiaDeviation> = ArrayList()
|
||||
var peakDeviations: List<PeakDeviation> = ArrayList()
|
||||
var from: Long = 0
|
||||
lateinit var dateUtil: DateUtil
|
||||
|
||||
|
@ -22,7 +22,7 @@ class PreppedGlucose {
|
|||
return toString(0)
|
||||
}
|
||||
|
||||
constructor(from: Long, crData: List<CRDatum>?, csfGlucoseData: List<BGDatum>?, isfGlucoseData: List<BGDatum>?, basalGlucoseData: List<BGDatum>?, dateUtil: DateUtil) {
|
||||
constructor(from: Long, crData: List<CRDatum>, csfGlucoseData: List<BGDatum>, isfGlucoseData: List<BGDatum>, basalGlucoseData: List<BGDatum>, dateUtil: DateUtil) {
|
||||
this.from = from
|
||||
this.crData = crData
|
||||
this.csfGlucoseData = csfGlucoseData
|
||||
|
@ -34,10 +34,10 @@ class PreppedGlucose {
|
|||
constructor(json: JSONObject?, dateUtil: DateUtil) {
|
||||
if (json == null) return
|
||||
this.dateUtil = dateUtil
|
||||
crData = null
|
||||
csfGlucoseData = null
|
||||
isfGlucoseData = null
|
||||
basalGlucoseData = null
|
||||
crData = ArrayList()
|
||||
csfGlucoseData = ArrayList()
|
||||
isfGlucoseData = ArrayList()
|
||||
basalGlucoseData = ArrayList()
|
||||
try {
|
||||
crData = JsonCRDataToList(json.getJSONArray("CRData"))
|
||||
csfGlucoseData = JsonGlucoseDataToList(json.getJSONArray("CSFGlucoseData"))
|
||||
|
@ -76,19 +76,19 @@ class PreppedGlucose {
|
|||
val json = JSONObject()
|
||||
try {
|
||||
val crjson = JSONArray()
|
||||
for (crd in crData!!) {
|
||||
for (crd in crData) {
|
||||
crjson.put(crd.toJSON())
|
||||
}
|
||||
val csfjson = JSONArray()
|
||||
for (bgd in csfGlucoseData!!) {
|
||||
for (bgd in csfGlucoseData) {
|
||||
csfjson.put(bgd.toJSON(true))
|
||||
}
|
||||
val isfjson = JSONArray()
|
||||
for (bgd in isfGlucoseData!!) {
|
||||
for (bgd in isfGlucoseData) {
|
||||
isfjson.put(bgd.toJSON(false))
|
||||
}
|
||||
val basaljson = JSONArray()
|
||||
for (bgd in basalGlucoseData!!) {
|
||||
for (bgd in basalGlucoseData) {
|
||||
basaljson.put(bgd.toJSON(false))
|
||||
}
|
||||
val diajson = JSONArray()
|
||||
|
|
|
@ -533,6 +533,7 @@
|
|||
<string name="key_insulin_oref_peak" translatable="false">insulin_oref_peak</string>
|
||||
<string name="insulin_oref_peak">IOB Curve Peak Time</string>
|
||||
<string name="insulin_peak_time">Peak Time [min]</string>
|
||||
<string name="insulin_peak">Peak</string>
|
||||
<string name="free_peak_oref">Free-Peak Oref</string>
|
||||
<string name="rapid_acting_oref">Rapid-Acting Oref</string>
|
||||
<string name="ultrarapid_oref">Ultra-Rapid Oref</string>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<PreferenceCategory
|
||||
android:key="@string/key_autotune_plugin"
|
||||
android:title="@string/autotune_settings"
|
||||
app:initialExpandedChildrenCount="0">
|
||||
app:initialExpandedChildrenCount="10">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
|
@ -18,6 +18,12 @@
|
|||
android:summary="@string/autotune_categorize_uam_as_basal_summary"
|
||||
android:title="@string/autotune_categorize_uam_as_basal_title" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_autotune_tune_insulin_curve"
|
||||
android:summary="@string/autotune_tune_insulin_curve_summary"
|
||||
android:title="@string/autotune_tune_insulin_curve_title" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="5"
|
||||
android:inputType="number"
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
<string name="key_insulin_oref_peak" translatable="false">insulin_oref_peak</string>
|
||||
<string name="key_autotune_auto" translatable="false">autotune_auto</string>
|
||||
<string name="key_autotune_categorize_uam_as_basal" translatable="false">categorize_uam_as_basal</string>
|
||||
<string name="key_autotune_tune_insulin_curve" translatable="false">autotune_tune_insulin_curve</string>
|
||||
<string name="key_autotune_default_tune_days" translatable="false">autotune_default_tune_days</string>
|
||||
<string name="key_autotune_circadian_ic_isf" translatable="false">autotune_circadian_ic_isf</string>
|
||||
<string name="key_autotune_additional_log" translatable="false">autotune_additional_log</string>
|
||||
|
@ -554,6 +555,8 @@
|
|||
<string name="autotune_auto_summary">If enabled, Autotune will automatically update and switch to input profile after calculation from an automation rule.</string>
|
||||
<string name="autotune_categorize_uam_as_basal_title">Categorize UAM as basal</string>
|
||||
<string name="autotune_categorize_uam_as_basal_summary">Enable only if you have reliably entered all carbs eaten, with this option sudden rises seen by Autotune will be used to recommend changes to the basal rate.</string>
|
||||
<string name="autotune_tune_insulin_curve_title">Tune insulin curve</string>
|
||||
<string name="autotune_tune_insulin_curve_summary">Enable only if you use free peak. This option will tune peak and DIA durations</string>
|
||||
<string name="autotune_default_tune_days_title">Number of days of data</string>
|
||||
<string name="autotune_circadian_ic_isf_title">Apply average result in circadian IC/ISF</string>
|
||||
<string name="autotune_circadian_ic_isf_summary">Autotune will not tune circadian variations, this option only apply the average tuning of IC and ISF to your circadian input profile</string>
|
||||
|
@ -589,8 +592,9 @@
|
|||
<string name="autotune_profile_invalid">Profile invalid</string>
|
||||
<string name="autotune_log_title" translatable="false">|Param|Profile|Tuned|%/Miss.\n</string>
|
||||
<string name="autotune_log_separator" translatable="false">+------------------------------------------\n</string>
|
||||
<string name="autotune_log_isf" translatable="false">| %1$4.4s |\t%2$3.3f |\t%3$3.3f |\n</string>
|
||||
<string name="autotune_log_ic" translatable="false">| %1$4.4s |\t%2$3.3f |\t%3$3.3f |\n</string>
|
||||
<string name="autotune_log_peak" translatable="false">| %1$4.4s |\t%2$d |\t%3$d |\n</string>
|
||||
<string name="autotune_log_dia" translatable="false">| %1$4.4s |\t%2$3.1f |\t%3$3.1f |\n</string>
|
||||
<string name="autotune_log_ic_isf" translatable="false">| %1$4.4s | %2$3.3f |\t%3$3.3f |\n</string>
|
||||
<string name="autotune_log_basal" translatable="false">|\t%1$02.0f\t| %2$3.3f |%3$3.3f\t| %5$.0f%% / %4$d\n</string>
|
||||
<string name="autotune_log_sum_basal" translatable="false">|\t∑\t|\t%1$3.1f |\t%2$3.1f |\n</string>
|
||||
<string name="autotune_run_without_autoswitch">Autotune runned without profile switch</string>
|
||||
|
|
Loading…
Reference in a new issue