ソースを参照

Add Dynamic ISF for the IOB forecast

Sam King 10 ヶ月 前
コミット
974d654fb1

+ 2 - 0
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasalGenerator.swift

@@ -208,7 +208,9 @@ enum DeterminationGenerator {
             iobData: iobData,
             mealData: mealData,
             profile: profile,
+            preferences: preferences,
             trioCustomOrefVariables: trioCustomOrefVariables,
+            dynamicIsfResult: dynamicIsfResult,
             targetGlucose: adjustedGlucoseTargets.targetGlucose,
             adjustedSensitivity: sensitivity,
             sensitivityRatio: sensitivityRatio,

+ 24 - 6
Trio/Sources/APS/OpenAPSSwift/DynamicISF.swift

@@ -29,12 +29,7 @@ enum DynamicISF {
         currentGlucose: Decimal,
         trioCustomOrefVariables: TrioCustomOrefVariables
     ) -> DynamicISFResult? {
-        let tdd: Decimal
-        if profile.weightPercentage < 1, trioCustomOrefVariables.weightedAverage > 1 {
-            tdd = trioCustomOrefVariables.weightedAverage
-        } else {
-            tdd = trioCustomOrefVariables.currentTDD
-        }
+        let tdd = trioCustomOrefVariables.tdd(profile: profile)
 
         guard preferences.useNewFormula, tdd > 0, var sensitivity = profile.sens,
               let profileTarget = profile.profileTarget(trioCustomOrefVariables: trioCustomOrefVariables)
@@ -111,3 +106,26 @@ extension Decimal {
         Decimal(Foundation.log(Double(x)))
     }
 }
+
+extension TrioCustomOrefVariables {
+    func tdd(profile: Profile) -> Decimal {
+        if profile.weightPercentage < 1, weightedAverage > 1 {
+            return weightedAverage
+        } else {
+            return currentTDD
+        }
+    }
+}
+
+enum DynamicIsfState {
+    case off
+    case sigmoid
+    case logrithmic
+}
+
+extension Preferences {
+    func dynamicIsfState() -> DynamicIsfState {
+        guard useNewFormula else { return .off }
+        return sigmoid ? .sigmoid : .logrithmic
+    }
+}

+ 23 - 2
Trio/Sources/APS/OpenAPSSwift/Forecasts/ForecastGenerator+Forecasts.swift

@@ -6,12 +6,33 @@ extension ForecastGenerator {
     static func forecastIOB(
         startingGlucose: Decimal,
         glucoseImpactSeries: [Decimal],
+        iobData: [IobResult],
         carbImpact: Decimal,
+        dynamicIsfState: DynamicIsfState,
+        insulinFactor: Decimal?,
+        tdd: Decimal,
+        adjustmentFactorLogrithmic: Decimal
     ) -> [Decimal] {
         var result = [startingGlucose]
-        for glucoseImpact in glucoseImpactSeries {
+        for (glucoseImpact, iob) in zip(glucoseImpactSeries, iobData) {
             let forecastedDeviation = carbImpact * (1 - min(1, Decimal(result.count) / (60 / 5)))
-            let next = result.last! + glucoseImpact.jsRounded(scale: 2) + forecastedDeviation
+            let lastForecast = result.last!
+            let next: Decimal
+            if let insulinFactor = insulinFactor, dynamicIsfState == .logrithmic {
+                // The JS code is extremely difficult to understand, so I tried
+                // to break down the components with the JS snippet listed above
+
+                // (Math.max( IOBpredBGs[IOBpredBGs.length-1],39) / insulinFactor )
+                let adjustedLastForecast = max(lastForecast, 39) / insulinFactor
+                // ( tdd * adjustmentFactor * (Math.log(adjustedLastForecast + 1 ) ) )
+                let adjustedTdd = tdd * adjustmentFactorLogrithmic * Decimal.log(adjustedLastForecast + 1)
+                // round(( -iobTick.activity * (1800 / adjustedTdd) * 5 ),2)
+                let adjustedGlucoseImpact = (-iob.activity * (1800 / adjustedTdd) * 5).jsRounded(scale: 2)
+
+                next = lastForecast + adjustedGlucoseImpact + forecastedDeviation
+            } else {
+                next = lastForecast + glucoseImpact.jsRounded(scale: 2) + forecastedDeviation
+            }
             if result.count < 48 { result.append(next) }
         }
         let clampedResult = result.map { $0.clamp(lowerBound: 39, upperBound: 401) }

+ 8 - 1
Trio/Sources/APS/OpenAPSSwift/Forecasts/ForecastGenerator.swift

@@ -8,10 +8,12 @@ enum ForecastGenerator {
         currentGlucoseImpact: Decimal,
         glucoseImpactSeries: [Decimal],
         glucoseImpactSeriesWithZeroTemp: [Decimal],
-        iobData _: [IobResult],
+        iobData: [IobResult],
         mealData: ComputedCarbs,
         profile: Profile,
+        preferences: Preferences,
         trioCustomOrefVariables: TrioCustomOrefVariables,
+        dynamicIsfResult: DynamicISFResult?,
         targetGlucose: Decimal,
         adjustedSensitivity: Decimal,
         sensitivityRatio: Decimal,
@@ -55,7 +57,12 @@ enum ForecastGenerator {
         let iobForecast = forecastIOB(
             startingGlucose: glucose,
             glucoseImpactSeries: glucoseImpactSeries,
+            iobData: iobData,
             carbImpact: carbImpact,
+            dynamicIsfState: preferences.dynamicIsfState(),
+            insulinFactor: dynamicIsfResult?.insulinFactor,
+            tdd: trioCustomOrefVariables.tdd(profile: profile),
+            adjustmentFactorLogrithmic: profile.adjustmentFactor
         )
 
         let cobForecast = forecastCOB(