О чем статья
Попробуем развить мысль на счет прогноза глюкозы в AndroidAPS. Ранее в статье я описывал какие прогнозы существуют и в общих чертах описал как принимаются решения. Сейчас уточним и улучшим понимание прогноза глюкозы. Ведь финально нас интересует не прогноз сам по себе, а сколько инсулина на основе всех вводных данных система примет решение нам подать, чтобы отрегулировать глюкозу в крови. Это важно, так как в системе есть несколько прогнозов, а не один единственный и правильный, как можно было бы предположить. Так что давайте начнем решать эту задачу с конца.
Разбирать будем не базовый AndroidAPS от Милоша, а версию от Метью (MTR93600, ссылка на ГитХаб), я же работаю непосредственно вот в этой (ссылка на ГитХаб) версии, которая является измененный вариантом приложения Метью в части прогноза). Идея состоит в том чтобы вывести для отображения самый релевантный прогноз и ввести отдельные коэффициенты для трех типов нагрузок (легкой, средней и тяжелой), а так же отдельный интерфейс для удобного взаимодействия с нагрузками, вывести приложение в часы. Напишите в комментарии, была бы вам такая доработка актуальна? А пока продолжу по теме...
Дисклеймер
Кстати! Эта статья все еще попытка осмысления алгоритма прогнозирования в программе AndroidAPS и предполагает дискуссию. Не стоит воспринимать ее как финальную истину в отношения прогноза. Я стараюсь приводить код и аргументы, которые вы самостоятельно можете оценить и если у вас есть возможность посмотреть код - то и оспорить представленную логику.
Как строится финальный прогноз
Параметр финального подсчета требуемого инсулина
Итак, у нас есть такой параметр как insulinReq - это сколько на основе всех ранее рассчитанных данных нам нужно получить инсулина для того чтобы привести глюкозу к цели.
Для начала определимся с логикой какого файла будем работать, у нас на выбор OpenAPSSMBAutoISF/determine-basal.js и OpenAPSSMBDynamicISF/determine-basal.js, я выберу последний, что подразумевает включенную в функциях настройку динамического ISF.
Вот расчет insulinReq
(Путь OpenAPSSMBDynamicISF/determine-basal.js)
var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / future_sens);
minPredBG
— минимальный предсказанный уровень глюкозы, рассчитанный на основе различных сценариев (например, активного инсулина, углеводов и автономного управления углеводами).eventualBG
— итоговый прогноз уровня глюкозы, рассчитанный на основе логики, которая будет подробно рассмотрена ниже.target_bg
— целевой уровень глюкозы.future_sens
— чувствительность к инсулину в будущем (вероятно этот параметр мы будем менять для работы с нагрузками).
Система может принять решение о подаче инсулина через микро-болюс (SMB) или временную базальную скорость
Прогноз уровня глюкозы: eventualBG и minPredBG
Прежде чем рассчитывать дозу инсулина, система строит прогнозы. Финально прогнозы строятся на базе параметра eventualBG с ограничением в виде minPredBG.
Сам eventualBG считается разными способами и учитывает в зависимости от разных факторов naive_eventualBG + deviation; IOBpredBGs, UAMpredBGs, ZTpredGGs, COBpredBGs.
Так как мы планируем построить свой прогноз, наиболее приближенный к финальному, то приведу логику построения прогноза на основе вышеприведенных параметров:
naive_eventualBG
var eventualBG = naive_eventualBG + deviation;
Этот способ базируется на прогнозе уровня глюкозы с учётом отклонений, основывающихся на текущей динамике изменения уровня глюкозы. Однако этот метод не учитывает более сложные сценарии, такие как активные углеводы или UAM.
Использование прогнозов на основе IOB, COB и UAM:
Рассмотрим указанные прогнозы
if (meal_data.carbs) {
// Если UAM не включён, и есть прогноз на основе COB, выбирается максимальное значение между IOB и COB
if (!enableUAM && minCOBPredBG < 999) {
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG));
}
// Если есть прогноз на основе COB и UAM включён
else if (minCOBPredBG < 999) {
var blendedMinPredBG = fractionCarbsLeft * minCOBPredBG + (1 - fractionCarbsLeft) * minZTUAMPredBG;
minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG));
}
// Если только UAM включен, используется прогноз UAM
else if (enableUAM) {
minPredBG = minZTUAMPredBG;
}
// Если нет данных о COB или UAM, используется Guard прогноз
else {
minPredBG = minGuardBG;
}
}
Разбор условий:
Если углеводы были потреблены (то есть
meal_data.carbs
имеет значение) и не включён UAM (неучтённые приемы пищи), то минимальное значение уровня глюкозы рассчитывается как максимальное значение между прогнозом на основе IOB (minIOBPredBG
) и прогнозом на основе COB (minCOBPredBG
).Если включён UAM и присутствуют данные по углеводам (COB), вычисляется смешанный прогноз (
blendedMinPredBG
), который учитывает как активные углеводы, так и прогнозы UAM.blendedMinPredBG
var blendedMinPredBG = fractionCarbsLeft * minCOBPredBG + (1 - fractionCarbsLeft) * minZTUAMPredBG;
Если только включён UAM, но данные по углеводам отсутствуют или не актуальны, используется прогноз на основе UAM (
minZTUAMPredBG
).Если нет данных ни по углеводам, ни по UAM, прогноз основывается на Guard, который является предохранительным значением (
minGuardBG
), защищающим от гипогликемии.fractionCarbsLeft — это доля оставшихся к усвоению углеводов, которые ещё не были поглощены организмом. Эта доля помогает взвесить вклад каждого прогноза.
minCOBPredBG — прогноз на основе активных углеводов.
minZTUAMPredBG — прогноз на основе данных UAM (учёт неучтённых приёмов пищи).
Таким образом, этот смешанный прогноз даёт больше веса прогнозам на основе углеводов, если углеводов осталось много, и прогнозам UAM, если углеводы уже практически полностью усвоены.
Отдельный случай для UAM без углеводов:
Если углеводы не были зарегистрированы, но включён UAM:
else if (enableUAM) {
minPredBG = round(Math.max(minIOBPredBG, minZTUAMPredBG));
}
В этом случае система просто берёт максимальное значение между прогнозами IOB и UAM.
Окончательная корректировка minPredBG
:
minPredBG = Math.min(minPredBG, avgPredBG);
В конце минимальное прогнозируемое значение корректируется таким образом, чтобы не превышать среднее прогнозируемое значение (avgPredBG
), чтобы избежать слишком оптимистичных прогнозов.
avgPredBG
Это среднее прогнозируемое значение уровня глюкозы, которое рассчитывается с учётом всех доступных прогнозов. Оно используется для того, чтобы скорректировать минимальное прогнозируемое значение (minPredBG
), не допуская слишком пессимистичных или, наоборот, слишком оптимистичных прогнозов.
Вот код, который рассчитывает среднее прогнозируемое значение уровня глюкозы, avgPredBG
, на основе различных предсказаний:
var avgPredBG;
if (minUAMPredBG < 999 && minCOBPredBG < 999) {
// если активны оба прогноза UAM и COB, считаем среднее, взвешенное на основе остаточных углеводов
avgPredBG = round((1 - fractionCarbsLeft) * UAMpredBG + fractionCarbsLeft * COBpredBG);
} else if (minCOBPredBG < 999) {
// если нет UAM, но есть прогноз COB, берем среднее между IOB и COB
avgPredBG = round((IOBpredBG + COBpredBG) / 2);
} else if (minUAMPredBG < 999) {
// если есть UAM, но нет COB, берем среднее между IOB и UAM
avgPredBG = round((IOBpredBG + UAMpredBG) / 2);
} else {
// если есть только IOB-прогноз
avgPredBG = round(IOBpredBG);
}
Расшифровка:
avgPredBG
— это среднее прогнозируемое значение уровня глюкозы, рассчитанное на основе доступных прогнозов. Оно играет роль для финальной коррекции минимального предсказанного значения (minPredBG
), чтобы избежать слишком резких или оптимистичных прогнозов.Если доступны оба прогноза — UAM и COB, то система рассчитывает взвешенное среднее между ними. Вклад каждого прогноза определяется на основе остаточных углеводов (
fractionCarbsLeft
).Если доступен только прогноз на основе COB (активных углеводов), система усредняет значения IOB и COB.
Если доступен только прогноз на основе UAM, система берет среднее между IOB и UAM.
Если нет ни прогноза COB, ни прогноза UAM, используется только прогноз на основе IOB.
Как соотносятся naive_eventualBG и IOBpredBGs
Прогнозы на основе naive_eventualBG
и IOBpredBGs
имеют разную цель и учитывают разные факторы, но могут работать вместе в зависимости от ситуации. Давайте рассмотрим их взаимодействие и когда они используются:
naive_eventualBG:
Описание: Это простой прогноз, который рассчитывается на основе текущего уровня активного инсулина (IOB) и чувствительности к инсулину (ISF). Он предполагает, что в будущем не произойдет никаких значительных изменений, таких как прием пищи или значительное изменение уровня активности.
Формула расчета:
var naive_eventualBG = round( bg - (iob_data.iob * sens) );
Здесь bg — это текущий уровень глюкозы, а iob_data.iob — количество активного инсулина, который остается в системе, умноженное на чувствительность к инсулину sens.
Когда используется: Он применяется как основной прогноз, когда система не имеет информации о принятых углеводах (COB) или других факторах, влияющих на уровень глюкозы, таких как активность (UAM). Это самый базовый подход к прогнозу, и его точность может быть ограничена, если не учтены дополнительные факторы.
IOBpredBGs:
Описание: Это прогноз, который основан на динамике инсулина, учитывающий, как инсулин будет действовать на протяжении времени. Прогнозы IOBpredBGs строятся на основе нескольких будущих моментов времени, оценивая, как инсулин будет снижать уровень сахара в крови в зависимости от его активности.
Формула расчета:
var predBGI = round((-iobTick.activity * sens * 5), 2); 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;
Здесь iobTick.activity — это активность инсулина в каждый момент времени (например, через 5 минут), умноженная на чувствительность к инсулину.
Когда используется: IOBpredBGs всегда используется, даже если нет данных о приеме пищи (COB) или активной углеводной активности (UAM). Это более динамичный прогноз, так как он строится с учетом изменения действия инсулина в будущем и более точен, чем
naive_eventualBG
.
Как они соотносятся?
Работают ли вместе?
В некоторых случаях, они могут работать вместе. naive_eventualBG
может использоваться как простой базовый прогноз, когда система имеет мало информации (например, нет углеводов или неактивна функция UAM), и может быть учтён наряду с другими данными. Однако, если доступны более точные прогнозы, такие как IOBpredBGs, система будет их предпочитать.
В коде есть ситуации, где наивный прогноз (naive_eventualBG
) комбинируется с другими прогнозами, чтобы дать более точный результат:
Например, код может использовать eventualBG
, который включает в себя корректировки на основе IOBpredBGs, deviation (отклонения), а также может учитывать naive_eventualBG
, если других данных нет:
var eventualBG = naive_eventualBG + deviation;
Пример взаимодействия:
naive_eventualBG
используется, если у системы нет информации о COB и UAM.IOBpredBGs
используется всегда, независимо от наличия данных по углеводам или активности.Если есть данные COB и UAM, они также могут быть учтены для более точного прогнозирования (COBpredBGs и UAMpredBGs).
Когда используется только один из них?
Если система имеет минимальные данные и нет информации о приеме пищи (COB) или активной углеводной активности (UAM), то прогноз будет базироваться на
naive_eventualBG
.Если доступна полная информация об инсулине, углеводах и других факторах, система будет использовать более сложные прогнозы, такие как IOBpredBGs, COBpredBGs и UAMpredBGs, при этом роль
naive_eventualBG
становится второстепенной.Итого,
naive_eventualBG
— это резервный прогноз, который может быть полезен в отсутствие других данных, но IOBpredBGs используется всегда, так как этот прогноз более точный и учитывает временное действие инсулина. Эти прогнозы могут работать вместе, но если есть более сложные данные, такие как COB или UAM, то система предпочтет их для более точного предсказания уровня глюкозы.
Вывод
Финальный прогноз глюкозы представляет из себя eventualBG, представляющий из себя вывод из других прогнозов и ограниченный minPredBG.