Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions Sources/LoopAlgorithm/Experiments/GuardAndRunwayOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public struct GuardAndRunwayOutput: Equatable {
public var volatility: Double
/// False when active carbs kept the volatility band off.
public var bandApplied: Bool
/// The most the band lowered any point of the forecast, mg/dL; 0 when it was off. A forecast with no
/// points near 60 min, where the band is deepest, is lowered less.
public var bandDepth: Double
/// How far the target for automatic dosing was lowered, mg/dL. Manual recommendations keep the target.
public var runwayShift: Double
/// True while the post-low cut scales down the rising side of retrospective correction.
Expand All @@ -23,11 +26,6 @@ public struct GuardAndRunwayOutput: Equatable {
/// The band's depth multiplier, from the volatility baseline.
public var bandGain: Double { band.gain }

/// How far the band lowers the forecast at its deepest point (60 min), mg/dL; 0 when it was off.
public var bandDepth: Double {
bandApplied ? band.gain * volatility * pow(band.horizon.minutes / 5.0, band.exponent) : 0
}

/// `glucose` lowered by the band as this run applied it; unchanged when the band was off.
public func guarded(_ glucose: [PredictedGlucoseValue]) -> [PredictedGlucoseValue] {
bandApplied ? LoopAlgorithm.volatilityBanded(glucose, band: band, volatility: volatility) : glucose
Expand Down
9 changes: 7 additions & 2 deletions Sources/LoopAlgorithm/LoopAlgorithm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,16 @@ public struct LoopAlgorithm {
}
if let band = experimentParameters.volatilityBand, let volatility {
let bandApplied = !(band.carbGate && (prediction.activeCarbs ?? 0) > 0)
var bandDepth = 0.0
if bandApplied {
prediction.glucose = volatilityBanded(prediction.glucose, band: band, volatility: volatility)
let banded = volatilityBanded(prediction.glucose, band: band, volatility: volatility)
bandDepth = zip(prediction.glucose, banded).map {
$0.quantity.doubleValue(for: .milligramsPerDeciliter) - $1.quantity.doubleValue(for: .milligramsPerDeciliter)
}.max() ?? 0
prediction.glucose = banded
}
guardAndRunway = GuardAndRunwayOutput(
volatility: volatility, bandApplied: bandApplied, runwayShift: runwayShift,
volatility: volatility, bandApplied: bandApplied, bandDepth: bandDepth, runwayShift: runwayShift,
postLowRiseCutActive: experimentParameters.postLowRiseCut?.isActive(glucoseHistory: input.glucoseHistory) ?? false,
band: band)
}
Expand Down
3 changes: 1 addition & 2 deletions Tests/LoopAlgorithmTests/AlgorithmExperimentsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,7 @@ final class AlgorithmExperimentsTests: XCTestCase {
XCTAssertFalse(output.postLowRiseCutActive)
XCTAssertEqual(output.guarded(standard.predictedGlucose), runway.predictedGlucose)
let deepest = zip(plain, banded).map { $0 - $1 }.max()!
XCTAssertLessThanOrEqual(deepest, output.bandDepth + 1e-9)
XCTAssertGreaterThan(deepest, 0.9 * output.bandDepth, "forecast points fall near the 60 min horizon")
XCTAssertEqual(output.bandDepth, deepest, accuracy: 1e-9)
if type == .tempBasal {
XCTAssertGreaterThan(runway.recommendation!.automatic!.basalAdjustment.unitsPerHour,
standard.recommendation!.automatic!.basalAdjustment.unitsPerHour)
Expand Down