Построчный разбор determine-basal.js в Android APS

3330374c81651c74005212f9e46d6d33

Давайте разберем файл determine-basal.js построчно.

Комментарий и Лицензия

/*
  Determine Basal

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/
  • Описание: Стандартный блок комментариев, который содержит информацию о лицензии MIT и отказ от ответственности.

Импорт функции round_basal

var round_basal = require('../round-basal');
  • Описание: Импортируется функция round_basal, которая используется для округления базальной дозы инсулина в зависимости от профиля пользователя.

Функция round: Округление значений

function round(value, digits)
{
    if (!digits) { digits = 0; }
    var scale = Math.pow(10, digits);
    return Math.round(value * scale) / scale;
}
  • Описание: Эта функция округляет переданное значение value до указанного числа знаков после запятой (digits). Если digits не указано, значение округляется до целого числа.

Функция calculate_expected_delta: Расчет ожидаемого изменения уровня глюкозы

function calculate_expected_delta(target_bg, eventual_bg, bgi) {
    var five_min_blocks = (2 * 60) / 5;
    var target_delta = target_bg - eventual_bg;
    return round(bgi + (target_delta / five_min_blocks), 1);
}
  • Описание: Эта функция рассчитывает ожидаемое изменение уровня глюкозы (expectedDelta) на основе текущей чувствительности к инсулину (BGI) и разницы между целевым и конечным прогнозируемым уровнем глюкозы.

Функция convert_bg: Конвертация значений глюкозы

function convert_bg(value, profile)
{
    if (profile.out_units === "mmol/L")
    {
        return round(value / 18, 1).toFixed(1);
    }
    else
    {
        return Math.round(value);
    }
}
  • Описание: Эта функция конвертирует уровень глюкозы в крови из мг/дл в ммоль/л, если в профиле указано использование ммоль/л. В противном случае значение возвращается в мг/дл.

Функция enable_smb: Включение функции SMB (Super Micro Bolus)

function enable_smb(
    profile,
    microBolusAllowed,
    meal_data,
    target_bg
) {
    if (!microBolusAllowed) {
        console.error("SMB disabled (!microBolusAllowed)");
        return false;
    } else if (!profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) {
        console.error("SMB disabled due to high temptarget of", target_bg);
        return false;
    } else if (meal_data.bwFound === true && profile.A52_risk_enable === false) {
        console.error("SMB disabled due to Bolus Wizard activity in the last 6 hours.");
        return false;
    }
    if (profile.enableSMB_always === true) {
        if (meal_data.bwFound) {
            console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard");
        } else {
            console.error("SMB enabled due to enableSMB_always");
        }
        return true;
    }
    if (profile.enableSMB_with_COB === true && meal_data.mealCOB) {
        if (meal_data.bwCarbs) {
            console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard");
        } else {
            console.error("SMB enabled for COB of", meal_data.mealCOB);
        }
        return true;
    }
    if (profile.enableSMB_after_carbs === true && meal_data.carbs) {
        if (meal_data.bwCarbs) {
            console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard");
        } else {
            console.error("SMB enabled for 6h after carb entry");
        }
        return true;
    }
    if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) {
        if (meal_data.bwFound) {
            console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard");
        } else {
            console.error("SMB enabled for temptarget of", convert_bg(target_bg, profile));
        }
        return true;
    }

    console.error("SMB disabled (no enableSMB preferences active or no condition satisfied)");
    return false;
}
  • Описание: Эта функция определяет, может ли быть включен режим Super Micro Bolus (SMB) на основе различных условий, таких как наличие углеводов на борту (COB), использование Bolus Wizard и другие параметры профиля пользователя.

Основная функция determine_basal

var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, flatBGsDetected) {
    var rT = {}; // short for requestedTemp
  • Описание: Основная функция determine_basal принимает множество параметров, которые включают данные о текущем уровне глюкозы, активном инсулине, профиле пользователя, и других данных. Она возвращает объект rT, содержащий результаты работы функции.

Определение времени выполнения

    var deliverAt = new Date();
    if (currentTime) {
        deliverAt = new Date(currentTime);
    }
  • Описание: Эта часть кода устанавливает текущее время, когда будет выполнена доставка инсулина. Если указано currentTime, оно используется вместо системного времени.

Проверка корректности профиля

    if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') {
        rT.error = 'Error: could not get current basal rate';
        return rT;
    }
    var profile_current_basal = round_basal(profile.current_basal, profile);
    var basal = profile_current_basal;
  • Описание: Проверяется, корректен ли профиль и определена ли текущая базальная доза. Если нет, функция возвращает ошибку. Если да, базальная доза округляется и сохраняется в переменной 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;
    var noise = glucose_status.noise;
  • Описание: Вычисляется время получения данных о глюкозе и разница во времени между текущим моментом и временем получения данных (minAgo). Также определяются текущий уровень глюкозы (bg) и уровень шума данных CGM (noise).

Проверка актуальности данных о глюкозе

    if (bg <= 10 || bg === 38 || noise >= 3) {  
        rT.reason = "CGM is calibrating, in ??? state, or noise is high";
    }
    if (minAgo > 12 || minAgo < -5) {  
        rT.reason = "If current system time " + systemTime + " is correct, then BG data is too old.";
    } else if (bg > 60 && flatBGsDetected) {
        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 <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || (bg > 60 && flatBGsDetected)) {
        if (currenttemp.rate > basal) { 
            rT.reason += ". Re

placing high temp basal of " + currenttemp.rate + " with neutral temp of " + basal;
            rT.deliverAt = deliverAt;
            rT.temp = 'absolute';
            rT.duration = 30;
            rT.rate = basal;
            return rT;
        } else if (currenttemp.rate === 0 && currenttemp.duration > 30) { 
            rT.reason += ". Shortening " + currenttemp.duration + "m long zero temp to 30m. ";
            rT.deliverAt = deliverAt;
            rT.temp = 'absolute';
            rT.duration = 30;
            rT.rate = 0;
            return rT;
        } else {
            rT.reason += ". Temp " + currenttemp.rate + " <= current basal " + round(basal, 2) + "U/hr; doing nothing. ";
            return rT;
        }
    }
  • Описание: В этом блоке проверяются условия, при которых временная базальная доза может быть скорректирована или сброшена на основе актуальности данных. Если данные неактуальны, корректировка базальной дозы производится на основе текущих условий.

Определение целевых значений глюкозы и расчет чувствительности

    var max_iob = profile.max_iob;

    var target_bg;
    var min_bg;
    var max_bg;
    if (typeof profile.min_bg !== 'undefined') {
        min_bg = profile.min_bg;
    }
    if (typeof profile.max_bg !== 'undefined') {
        max_bg = profile.max_bg;
    }
    if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') {
        target_bg = (profile.min_bg + profile.max_bg) / 2;
    } else {
        rT.error = 'Error: could not determine target_bg. ';
        return rT;
    }

    var sensitivityRatio;
    var high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity;
    var normalTarget = 100;
    if (profile.half_basal_exercise_target) {
        var halfBasalTarget = profile.half_basal_exercise_target;
    } else {
        halfBasalTarget = 160;
    }
  • Описание: Определяются минимальные, максимальные и целевые значения глюкозы на основе профиля пользователя. Также рассчитывается коэффициент чувствительности (sensitivityRatio), который может быть скорректирован в зависимости от условий, таких как режим упражнений или целевые значения глюкозы.

Внедрение динамического ISF и расчет чувствительности

    console.error("---------------------------------------------------------");
    console.error(" Dynamic ISF version Beta 2.0 ");
    console.error("---------------------------------------------------------");

    var variable_sens = profile.variable_sens;
    var TDD = profile.TDD;
    var insulinDivisor = profile.insulinDivisor;
  • Описание: Этот блок кода предназначен для динамического расчета чувствительности к инсулину (ISF). Здесь определяются переменные, используемые для расчетов, такие как переменная чувствительность (variable_sens), общая суточная доза инсулина (TDD) и делитель инсулина (insulinDivisor).

Определение коэффициента чувствительности

    if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget
        || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget) {
        var c = halfBasalTarget - normalTarget;
        sensitivityRatio = c / (c + target_bg - normalTarget);
        sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
        sensitivityRatio = round(sensitivityRatio, 2);
        console.log("Sensitivity ratio set to " + sensitivityRatio + " based on temp target of " + target_bg + "; ");
    } else if (typeof autosens_data !== 'undefined' && autosens_data) {
        sensitivityRatio = autosens_data.ratio;
        console.log("Autosens ratio: " + sensitivityRatio + "; ");
    }
    if (sensitivityRatio) {
        basal = profile.current_basal * sensitivityRatio;
        basal = round_basal(basal, profile);
        if (basal !== profile_current_basal) {
            console.log("Adjusting basal from " + profile_current_basal + " to " + basal + "; ");
        } else {
            console.log("Basal unchanged: " + basal + "; ");
        }
    }
  • Описание: В этом блоке рассчитывается и применяется коэффициент чувствительности (sensitivityRatio), который может корректироваться в зависимости от целевых значений глюкозы и данных автосенса. Если коэффициент изменен, пересчитывается и базальная доза.

Корректировка целевых значений глюкозы

    if (profile.temptargetSet) {
        // Temp target set, no adjustment
    } 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) {
            min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
            max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
            var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
            new_target_bg = Math.max(80, new_target_bg);
            if (target_bg === new_target_bg) {
                console.log("target_bg unchanged: " + new_target_bg + "; ");
            } else {
                console.log("target_bg from " + target_bg + " to " + new_target_bg + "; ");
            }
            target_bg = new_target_bg;
        }
    }
  • Описание: В этом блоке целевые значения глюкозы (min_bg, max_bg, target_bg) могут корректироваться в зависимости от коэффициента чувствительности, чтобы учитывать изменения в чувствительности или устойчивости пользователя.

Обработка ошибок данных IOB

    if (typeof iob_data === 'undefined') {
        rT.error = 'Error: iob_data undefined. ';
        return rT;
    }

    var iobArray = iob_data;
    if (typeof (iob_data.length) && iob_data.length > 1) {
        iob_data = iobArray[0];
    }

    if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined') {
        rT.error = 'Error: iob_data missing some property. ';
        return rT;
    }
  • Описание: В этом блоке проверяется наличие и корректность данных о инсулине на борту (IOB). Если данные отсутствуют или некорректны, функция возвращает ошибку.

Рассмотрение изменений уровня глюкозы и обработка временной базальной дозы

    var tick;
    if (glucose_status.delta > -0.5) {
        tick = "+" + round(glucose_status.delta, 0);
    } else {
        tick = round(glucose_status.delta, 0);
    }
    var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta);
    var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
    var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
  • Описание: Здесь вычисляются различные параметры, связанные с изменением уровня глюкозы: текущее изменение (delta), минимальное и максимальное изменения на основе коротких и длинных средних.

Рассмотрение последней временной базальной дозы

    var lastTempAge;
    if (typeof iob_data.lastTemp !== 'undefined') {
        lastTempAge = round((new Date(systemTime).getTime() - iob_data.lastTemp.date) / 60000);
    } else {
        lastTempAge = 0;
    }
    var tempModulus = (lastTempAge + currenttemp.duration) % 30;
    console.error("currenttemp:", round(currenttemp.rate, 2), "lastTempAge:", lastTempAge, "m", "tempModulus:", tempModulus, "m");
    rT.temp = 'absolute';
    rT.deliverAt = deliverAt;
  • Описание: Этот блок рассматривает возраст последней временной базальной дозы и текущую временную дозу, чтобы определить, требуется ли их корректировка.

Рассмотрение чувствительности к инсулину и расчет прогнозируемого воздействия инсулина

    var bgi = round((-iob_data.activity * sens * 5), 2);
    var deviation = round(30 / 5 * (minDelta - bgi));
    if (deviation < 0) {
        deviation = round((30 / 5) * (minAvgDelta - bgi));
        if (deviation < 0) {
            deviation = round((30 / 5) * (glucose_status.long_avgdelta - bgi));
        }
    }
    var naive_eventualBG = round(bg - (iob_data.i

ob * sens));
    var eventualBG = naive_eventualBG + deviation;
  • Описание: Рассчитывается прогнозируемое изменение уровня глюкозы на основе активности инсулина (bgi) и отклонений (deviation). Также вычисляется конечный прогнозируемый уровень глюкозы (eventualBG).

Этот построчный разбор продолжает идти по коду и определяет, как программа обрабатывает данные, прогнозирует уровни глюкозы, рассчитывает необходимые дозы инсулина и определяет, какие действия нужно предпринять на основе этих прогнозов.

Если вам нужно продолжение или пояснение конкретных строк, дайте знать.

© Habrahabr.ru