Skip to content

Commit 86c82f8

Browse files
authored
Merge pull request #342 from tidepool-org/ps2/LOOP-2492/use-glucose-velocity
LOOP-2492: Use glucose velocity instead of ICE for meal detection
2 parents 96e0055 + 85ea465 commit 86c82f8

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

Loop/Models/LoopConstants.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,9 @@ enum LoopConstants {
5252
static let defaultWatchCarbPickerValue = 15 // grams
5353

5454
static let defaultWatchBolusPickerValue = 1.0 // %
55+
56+
/// Missed Meal warning constants
57+
static let missedMealWarningGlucoseRiseThreshold = 3.0 // mg/dL/m
58+
static let missedMealWarningGlucoseRecencyWindow = TimeInterval(minutes: 20)
59+
static let missedMealWarningVelocitySampleMinDuration = TimeInterval(minutes: 12)
5560
}

Loop/View Controllers/CarbEntryViewController.swift

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -216,23 +216,29 @@ final class CarbEntryViewController: LoopChartsTableViewController, Identifiable
216216
private var foodKeyboard: EmojiInputController!
217217

218218
private func updateDisplayAccurateCarbEntryWarning() {
219-
deviceManager.loopManager.getLoopState { [weak self] (_, state) in
220-
let endDate = Date()
221-
let startDate = endDate.addingTimeInterval(.minutes(-20))
222-
let threshold = HKQuantity(unit: GlucoseEffectVelocity.unit, doubleValue: 3)
223-
224-
let filteredInsulinCounteractionEffects = state.insulinCounteractionEffects.filterDateRange(startDate, endDate)
219+
let now = Date()
220+
let startDate = now.addingTimeInterval(-LoopConstants.missedMealWarningGlucoseRecencyWindow)
225221

222+
deviceManager.glucoseStore.getGlucoseSamples(start: startDate, end: nil) { [weak self] (result) -> Void in
226223
DispatchQueue.main.async {
227-
// at least 3 insulin counteraction effects are required to calculate the average
228-
guard filteredInsulinCounteractionEffects.count >= 3,
229-
let averageInsulinCounteractionEffect = filteredInsulinCounteractionEffects.average(unit: GlucoseEffectVelocity.unit) else
230-
{
224+
switch result {
225+
case .failure:
231226
self?.shouldDisplayAccurateCarbEntryWarning = false
232-
return
227+
case .success(let samples):
228+
let filteredSamples = samples.filterDateRange(startDate, now)
229+
guard let startSample = filteredSamples.first, let endSample = filteredSamples.last else {
230+
self?.shouldDisplayAccurateCarbEntryWarning = false
231+
return
232+
}
233+
let duration = endSample.startDate.timeIntervalSince(startSample.startDate)
234+
guard duration >= LoopConstants.missedMealWarningVelocitySampleMinDuration else {
235+
self?.shouldDisplayAccurateCarbEntryWarning = false
236+
return
237+
}
238+
let delta = endSample.quantity.doubleValue(for: .milligramsPerDeciliter) - startSample.quantity.doubleValue(for: .milligramsPerDeciliter)
239+
let velocity = delta / duration.minutes // Unit = mg/dL/m
240+
self?.shouldDisplayAccurateCarbEntryWarning = velocity > LoopConstants.missedMealWarningGlucoseRiseThreshold
233241
}
234-
235-
self?.shouldDisplayAccurateCarbEntryWarning = averageInsulinCounteractionEffect >= threshold
236242
}
237243
}
238244
}

0 commit comments

Comments
 (0)