StandardRetrospectiveCorrection.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //
  2. // StandardRetrospectiveCorrection.swift
  3. // Loop
  4. //
  5. // Created by Dragan Maksimovic on 10/27/18.
  6. // Copyright © 2018 LoopKit Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import HealthKit
  10. /**
  11. Standard Retrospective Correction (RC) calculates a correction effect in glucose prediction based on the most recent discrepancy between observed glucose movement and movement expected based on insulin and carb models. Standard retrospective correction acts as a proportional (P) controller aimed at reducing modeling errors in glucose prediction.
  12. In the above summary, "discrepancy" is a difference between the actual glucose and the model predicted glucose over retrospective correction grouping interval (set to 30 min in LoopSettings)
  13. */
  14. public class StandardRetrospectiveCorrection: RetrospectiveCorrection {
  15. public static let retrospectionInterval = TimeInterval(minutes: 30)
  16. /// RetrospectiveCorrection protocol variables
  17. /// Standard effect duration
  18. let effectDuration: TimeInterval
  19. /// Overall retrospective correction effect
  20. public var totalGlucoseCorrectionEffect: HKQuantity?
  21. /// All math is performed with glucose expressed in mg/dL
  22. private let unit = HKUnit.milligramsPerDeciliter
  23. public init(effectDuration: TimeInterval) {
  24. self.effectDuration = effectDuration
  25. }
  26. public func computeEffect(
  27. startingAt startingGlucose: GlucoseValue,
  28. retrospectiveGlucoseDiscrepanciesSummed: [GlucoseChange]?,
  29. recencyInterval: TimeInterval,
  30. insulinSensitivity: HKQuantity,
  31. basalRate: Double,
  32. correctionRange: ClosedRange<HKQuantity>,
  33. retrospectiveCorrectionGroupingInterval: TimeInterval
  34. ) -> [GlucoseEffect] {
  35. // Last discrepancy should be recent, otherwise clear the effect and return
  36. let glucoseDate = startingGlucose.startDate
  37. guard let currentDiscrepancy = retrospectiveGlucoseDiscrepanciesSummed?.last,
  38. glucoseDate.timeIntervalSince(currentDiscrepancy.endDate) <= recencyInterval
  39. else {
  40. totalGlucoseCorrectionEffect = nil
  41. return []
  42. }
  43. // Standard retrospective correction math
  44. let currentDiscrepancyValue = currentDiscrepancy.quantity.doubleValue(for: unit)
  45. totalGlucoseCorrectionEffect = HKQuantity(unit: unit, doubleValue: currentDiscrepancyValue)
  46. let retrospectionTimeInterval = currentDiscrepancy.endDate.timeIntervalSince(currentDiscrepancy.startDate)
  47. let discrepancyTime = max(retrospectionTimeInterval, retrospectiveCorrectionGroupingInterval)
  48. let velocity = HKQuantity(unit: unit.unitDivided(by: .second()), doubleValue: currentDiscrepancyValue / discrepancyTime)
  49. // Update array of glucose correction effects
  50. return startingGlucose.decayEffect(atRate: velocity, for: effectDuration)
  51. }
  52. public var debugDescription: String {
  53. let report: [String] = [
  54. "## StandardRetrospectiveCorrection",
  55. ""
  56. ]
  57. return report.joined(separator: "\n")
  58. }
  59. }