|
|
@@ -1,3 +1,4 @@
|
|
|
+import Accelerate
|
|
|
import Combine
|
|
|
import Foundation
|
|
|
import LoopKit
|
|
|
@@ -239,11 +240,6 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
loopStats(loopStatRecord: loopStatRecord)
|
|
|
|
|
|
- // Create a statistics.json
|
|
|
- if settings.displayStatistics {
|
|
|
- statistics()
|
|
|
- }
|
|
|
-
|
|
|
if settings.closedLoop {
|
|
|
reportEnacted(received: error == nil)
|
|
|
}
|
|
|
@@ -662,9 +658,6 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
storage.save(enacted, as: OpenAPS.Enact.enacted)
|
|
|
|
|
|
- // Create a tdd.json
|
|
|
- tdd(enacted_: enacted)
|
|
|
-
|
|
|
debug(.apsManager, "Suggestion enacted. Received: \(received)")
|
|
|
DispatchQueue.main.async {
|
|
|
self.broadcaster.notify(EnactedSuggestionObserver.self, on: .main) {
|
|
|
@@ -672,10 +665,18 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
}
|
|
|
}
|
|
|
nightscout.uploadStatus()
|
|
|
+
|
|
|
+ // Update the tdd.json
|
|
|
+ tdd(enacted_: enacted)
|
|
|
+ // Update statistics.json. Only run if enabled in preferences
|
|
|
+ if settingsManager.settings.displayStatistics {
|
|
|
+ statistics()
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func tdd(enacted_: Suggestion) {
|
|
|
+ let tddStartedAt = Date()
|
|
|
// Add to tdd.json:
|
|
|
let preferences = settingsManager.preferences
|
|
|
let currentTDD = enacted_.tdd ?? 0
|
|
|
@@ -685,39 +686,24 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
timestamp: Date(),
|
|
|
id: UUID().uuidString
|
|
|
)
|
|
|
+
|
|
|
+ var allTDD: [Decimal] = [0]
|
|
|
var uniqEvents: [TDD] = []
|
|
|
storage.transaction { storage in
|
|
|
storage.append(tdd, to: file, uniqBy: \.id)
|
|
|
uniqEvents = storage.retrieve(file, as: [TDD].self)?
|
|
|
- .filter { $0.timestamp.addingTimeInterval(14.days.timeInterval) > Date() }
|
|
|
+ .filter { $0.timestamp.addingTimeInterval(14.days.timeInterval) > Date() && $0.TDD != 0 }
|
|
|
.sorted { $0.timestamp > $1.timestamp } ?? []
|
|
|
- var total: Decimal = 0
|
|
|
- var indeces: Decimal = 0
|
|
|
- for uniqEvent in uniqEvents {
|
|
|
- if uniqEvent.TDD > 0 {
|
|
|
- total += uniqEvent.TDD
|
|
|
- indeces += 1
|
|
|
- }
|
|
|
- }
|
|
|
- let entriesPast2hours = storage.retrieve(file, as: [TDD].self)?
|
|
|
+
|
|
|
+ var totalAmount: [Decimal] = [0]
|
|
|
+ allTDD = uniqEvents.map({ allTDD in allTDD.TDD }) // .reduce(0, +)
|
|
|
+ let average14 = allTDD.reduce(0, +) / Decimal(allTDD.count)
|
|
|
+
|
|
|
+ let entriesPast2hours = uniqEvents // storage.retrieve(file, as: [TDD].self)?
|
|
|
.filter { $0.timestamp.addingTimeInterval(2.hours.timeInterval) > Date() }
|
|
|
- .sorted { $0.timestamp > $1.timestamp } ?? []
|
|
|
- var totalAmount: Decimal = 0
|
|
|
- var nrOfIndeces: Decimal = 0
|
|
|
- for entry in entriesPast2hours {
|
|
|
- if entry.TDD > 0 {
|
|
|
- totalAmount += entry.TDD
|
|
|
- nrOfIndeces += 1
|
|
|
- }
|
|
|
- }
|
|
|
- if indeces == 0 {
|
|
|
- indeces = 1
|
|
|
- }
|
|
|
- if nrOfIndeces == 0 {
|
|
|
- nrOfIndeces = 1
|
|
|
- }
|
|
|
- let average14 = total / indeces
|
|
|
- let average2hours = totalAmount / nrOfIndeces
|
|
|
+ totalAmount = entriesPast2hours.map({ totalAmount in totalAmount.TDD }) // .reduce(0, +)
|
|
|
+ let average2hours = totalAmount.reduce(0, +) / Decimal(totalAmount.count)
|
|
|
+
|
|
|
let weight = preferences.weightPercentage
|
|
|
let weighted_average = weight * average2hours + (1 - weight) * average14
|
|
|
let averages = TDD_averages(
|
|
|
@@ -729,6 +715,7 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
storage.save(averages, as: OpenAPS.Monitor.tdd_averages)
|
|
|
storage.save(Array(uniqEvents), as: file)
|
|
|
}
|
|
|
+ print("Test time of tdd() computation: \(-1 * tddStartedAt.timeIntervalSinceNow) s")
|
|
|
}
|
|
|
|
|
|
private func roundDecimal(_ decimal: Decimal, _ digits: Double) -> Decimal {
|
|
|
@@ -756,16 +743,15 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
// Add to statistics.JSON
|
|
|
private func statistics() {
|
|
|
+ let statisticsStartedAt = Date()
|
|
|
var testFile: [Statistics] = []
|
|
|
var testIfEmpty = 0
|
|
|
storage.transaction { storage in
|
|
|
testFile = storage.retrieve(OpenAPS.Monitor.statistics, as: [Statistics].self) ?? []
|
|
|
testIfEmpty = testFile.count
|
|
|
}
|
|
|
-
|
|
|
let updateThisOften = Int(settingsManager.preferences.updateInterval)
|
|
|
-
|
|
|
- // Only run every 30 minutesl
|
|
|
+ // Only run every 30 minutes of according to setting.
|
|
|
if testIfEmpty != 0 {
|
|
|
guard testFile[0].created_at.addingTimeInterval(updateThisOften.minutes.timeInterval) < Date()
|
|
|
else {
|
|
|
@@ -781,17 +767,9 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
if tdds?.count ?? 0 > 0 {
|
|
|
currentTDD = tdds?[0].TDD ?? 0
|
|
|
}
|
|
|
- let carbs_length = carbs?.count ?? 0
|
|
|
- var carbTotal: Decimal = 0
|
|
|
- if carbs_length != 0 {
|
|
|
- for each in carbs! {
|
|
|
- if each.carbs != 0 {
|
|
|
- carbTotal += each.carbs
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- var algo_ = "Oref0"
|
|
|
|
|
|
+ var algo_ = "Oref0"
|
|
|
+ let carbTotal = carbs?.map({ carbs in carbs.carbs }).reduce(0, +) ?? 0
|
|
|
if preferences.sigmoid, preferences.enableDynamicCR {
|
|
|
algo_ = "Dynamic ISF + CR: Sigmoid"
|
|
|
} else if preferences.sigmoid, !preferences.enableDynamicCR {
|
|
|
@@ -842,11 +820,9 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
if !lsData.isEmpty {
|
|
|
var i = 0.0
|
|
|
-
|
|
|
if let loopEnd = lsData[0].end {
|
|
|
previousTimeLoop = loopEnd
|
|
|
}
|
|
|
-
|
|
|
for each in lsData {
|
|
|
if let loopEnd = each.end, let loopDuration = each.duration {
|
|
|
if each.loopStatus.contains("Success") {
|
|
|
@@ -855,36 +831,30 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
errorNR += 1
|
|
|
}
|
|
|
i += 1
|
|
|
-
|
|
|
timeIntervalLoops = (previousTimeLoop - each.start).timeInterval / 60
|
|
|
+
|
|
|
if timeIntervalLoops > 0.0, i != 1 {
|
|
|
timeIntervalLoopArray.append(timeIntervalLoops)
|
|
|
}
|
|
|
-
|
|
|
if timeIntervalLoops > maximumInt {
|
|
|
maximumInt = timeIntervalLoops
|
|
|
}
|
|
|
if timeIntervalLoops < minimumInt, i != 1 {
|
|
|
minimumInt = timeIntervalLoops
|
|
|
}
|
|
|
-
|
|
|
timeForOneLoop = loopDuration
|
|
|
-
|
|
|
timeForOneLoopArray.append(timeForOneLoop)
|
|
|
averageLoopTime += timeForOneLoop
|
|
|
|
|
|
if timeForOneLoop >= maximumLoopTime, timeForOneLoop != 0.0 {
|
|
|
maximumLoopTime = timeForOneLoop
|
|
|
}
|
|
|
-
|
|
|
if timeForOneLoop <= minimumLoopTime, timeForOneLoop != 0.0 {
|
|
|
minimumLoopTime = timeForOneLoop
|
|
|
}
|
|
|
-
|
|
|
previousTimeLoop = loopEnd
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
successRate = (successNR / Double(i)) * 100
|
|
|
averageIntervalLoops = ((lsData[0].end ?? lsData[lsData.count - 1].start) - lsData[lsData.count - 1].start)
|
|
|
.timeInterval / 60 / Double(i)
|
|
|
@@ -899,71 +869,69 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
if minimumLoopTime == 9999.0 {
|
|
|
minimumLoopTime = 0.0
|
|
|
}
|
|
|
+
|
|
|
+ // Filter glucose storage to 90 days
|
|
|
+ let uniqEvents_ = storage.retrieve(OpenAPS.Monitor.glucose_data, as: [BloodGlucose].self)?
|
|
|
+ .filter { $0.dateString.addingTimeInterval(90.days.timeInterval) > Date() }
|
|
|
+ .sorted { $0.dateString > $1.dateString } ?? []
|
|
|
+ let glucose = Array(uniqEvents_)
|
|
|
+ storage.save(glucose, as: OpenAPS.Monitor.glucose_data)
|
|
|
+
|
|
|
// Time In Range (%) and Average Glucose (24 hours). This will be refactored later after some testing.
|
|
|
- let glucose = storage.retrieve(OpenAPS.Monitor.glucose_data, as: [GlucoseDataForStats].self)
|
|
|
- let length_ = glucose?.count ?? 0
|
|
|
+ let length_ = glucose.count
|
|
|
let endIndex = length_ - 1
|
|
|
var bg: Decimal = 0
|
|
|
+
|
|
|
var bgArray: [Double] = []
|
|
|
var bgArray_1_: [Double] = []
|
|
|
var bgArray_7_: [Double] = []
|
|
|
var bgArray_30_: [Double] = []
|
|
|
+
|
|
|
var bgArrayForTIR: [(bg_: Double, date_: Date)] = []
|
|
|
var bgArray_1: [(bg_: Double, date_: Date)] = []
|
|
|
var bgArray_7: [(bg_: Double, date_: Date)] = []
|
|
|
var bgArray_30: [(bg_: Double, date_: Date)] = []
|
|
|
+
|
|
|
var medianBG = 0.0
|
|
|
var nr_bgs: Decimal = 0
|
|
|
- var nr_bgs_1: Decimal = 0
|
|
|
- var nr_bgs_7: Decimal = 0
|
|
|
- var nr_bgs_30: Decimal = 0
|
|
|
|
|
|
var startDate = Date("1978-02-22T11:43:54.659Z")
|
|
|
if endIndex >= 0 {
|
|
|
- startDate = glucose?[0].date
|
|
|
+ startDate = glucose[0].dateString
|
|
|
}
|
|
|
- var end1 = false
|
|
|
- var end7 = false
|
|
|
- var end30 = false
|
|
|
var bg_1: Decimal = 0
|
|
|
var bg_7: Decimal = 0
|
|
|
var bg_30: Decimal = 0
|
|
|
var bg_total: Decimal = 0
|
|
|
var j = -1
|
|
|
+ var conversionFactor: Decimal = 1
|
|
|
+ if units == .mmolL {
|
|
|
+ conversionFactor = 0.0555
|
|
|
+ }
|
|
|
|
|
|
// Make arrays for median calculations and calculate averages
|
|
|
if endIndex >= 0 {
|
|
|
- for entry in glucose! {
|
|
|
+ for entry in glucose {
|
|
|
j += 1
|
|
|
- if entry.glucose > 0 {
|
|
|
- bg += Decimal(entry.glucose)
|
|
|
- bgArray.append(Double(entry.glucose))
|
|
|
- bgArrayForTIR.append((Double(entry.glucose), entry.date))
|
|
|
+ if entry.glucose ?? 0 > 0 {
|
|
|
+ bg += Decimal(entry.glucose ?? 0) * conversionFactor
|
|
|
+ bgArray.append(Double(entry.glucose ?? 0) * Double(conversionFactor))
|
|
|
+ bgArrayForTIR.append((Double(entry.glucose ?? 0), entry.dateString))
|
|
|
nr_bgs += 1
|
|
|
-
|
|
|
- if (startDate! - entry.date).timeInterval >= 8.64E4, !end1 {
|
|
|
- end1 = true
|
|
|
+ if (startDate! - entry.dateString).timeInterval <= 24.hours.timeInterval {
|
|
|
bg_1 = bg / nr_bgs
|
|
|
bgArray_1 = bgArrayForTIR
|
|
|
bgArray_1_ = bgArray
|
|
|
- nr_bgs_1 = nr_bgs
|
|
|
- // time_1 = ((startDate ?? Date()) - entry.date).timeInterval
|
|
|
}
|
|
|
- if (startDate! - entry.date).timeInterval >= 6.048E5, !end7 {
|
|
|
- end7 = true
|
|
|
+ if (startDate! - entry.dateString).timeInterval <= 7.days.timeInterval {
|
|
|
bg_7 = bg / nr_bgs
|
|
|
bgArray_7 = bgArrayForTIR
|
|
|
bgArray_7_ = bgArray
|
|
|
- nr_bgs_7 = nr_bgs
|
|
|
- // time_7 = ((startDate ?? Date()) - entry.date).timeInterval
|
|
|
}
|
|
|
- if (startDate! - entry.date).timeInterval >= 2.592E6, !end30 {
|
|
|
- end30 = true
|
|
|
+ if (startDate! - entry.dateString).timeInterval <= 30.days.timeInterval {
|
|
|
bg_30 = bg / nr_bgs
|
|
|
bgArray_30 = bgArrayForTIR
|
|
|
bgArray_30_ = bgArray
|
|
|
- nr_bgs_30 = nr_bgs
|
|
|
- // time_30 = ((startDate ?? Date()) - entry.date).timeInterval
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -972,14 +940,6 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
if nr_bgs > 0 {
|
|
|
// Up to 91 days
|
|
|
bg_total = bg / nr_bgs
|
|
|
-
|
|
|
- // If less then 24 hours of glucose data, use total instead
|
|
|
- if bg_1 == 0 {
|
|
|
- bg_1 = bg_total
|
|
|
- bgArray_1 = bgArrayForTIR
|
|
|
- end1 = true
|
|
|
- nr_bgs_1 = nr_bgs
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
// Total median
|
|
|
@@ -988,7 +948,7 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
var fullTime = 0.0
|
|
|
|
|
|
if length_ > 0 {
|
|
|
- fullTime = (startDate! - glucose![endIndex].date).timeInterval
|
|
|
+ fullTime = (startDate! - glucose[endIndex].dateString).timeInterval
|
|
|
daysBG = fullTime / 8.64E4
|
|
|
}
|
|
|
|
|
|
@@ -1000,24 +960,20 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
var i = -1
|
|
|
var lastIndex = false
|
|
|
let endIndex = array.count - 1
|
|
|
-
|
|
|
var hypoLimit = settingsManager.preferences.low
|
|
|
var hyperLimit = settingsManager.preferences.high
|
|
|
if units == .mmolL {
|
|
|
hypoLimit = hypoLimit / 0.0555
|
|
|
hyperLimit = hyperLimit / 0.0555
|
|
|
}
|
|
|
-
|
|
|
var full_time = 0.0
|
|
|
if endIndex > 0 {
|
|
|
full_time = (array[0].date_ - array[endIndex].date_).timeInterval
|
|
|
}
|
|
|
-
|
|
|
while i < endIndex {
|
|
|
i += 1
|
|
|
let currentTime = array[i].date_
|
|
|
var previousTime = currentTime
|
|
|
-
|
|
|
if i + 1 <= endIndex {
|
|
|
previousTime = array[i + 1].date_
|
|
|
} else {
|
|
|
@@ -1044,43 +1000,40 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
// HbA1c estimation (%, mmol/mol) 1 day
|
|
|
var NGSPa1CStatisticValue: Decimal = 0.0
|
|
|
var IFCCa1CStatisticValue: Decimal = 0.0
|
|
|
- if end1, bg_1 > 0 {
|
|
|
- NGSPa1CStatisticValue = (46.7 + bg_1) / 28.7 // NGSP (%)
|
|
|
+ if nr_bgs > 0 {
|
|
|
+ NGSPa1CStatisticValue = ((bg_1 / conversionFactor) + 46.7) / 28.7 // NGSP (%)
|
|
|
IFCCa1CStatisticValue = 10.929 *
|
|
|
(NGSPa1CStatisticValue - 2.152) // IFCC (mmol/mol) A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
|
|
|
}
|
|
|
// 7 days
|
|
|
var NGSPa1CStatisticValue_7: Decimal = 0.0
|
|
|
var IFCCa1CStatisticValue_7: Decimal = 0.0
|
|
|
- if end7 {
|
|
|
- NGSPa1CStatisticValue_7 = (46.7 + bg_7) / 28.7 // NGSP (%)
|
|
|
- IFCCa1CStatisticValue_7 = 10.929 *
|
|
|
- (NGSPa1CStatisticValue_7 - 2.152) // IFCC (mmol/mol) A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
|
|
|
+ if nr_bgs > 0 {
|
|
|
+ NGSPa1CStatisticValue_7 = ((bg_7 / conversionFactor) + 46.7) / 28.7
|
|
|
+ IFCCa1CStatisticValue_7 = 10.929 * (NGSPa1CStatisticValue_7 - 2.152)
|
|
|
}
|
|
|
// 30 days
|
|
|
var NGSPa1CStatisticValue_30: Decimal = 0.0
|
|
|
var IFCCa1CStatisticValue_30: Decimal = 0.0
|
|
|
- if end30 {
|
|
|
- NGSPa1CStatisticValue_30 = (46.7 + bg_30) / 28.7 // NGSP (%)
|
|
|
- IFCCa1CStatisticValue_30 = 10.929 *
|
|
|
- (NGSPa1CStatisticValue_30 - 2.152) // IFCC (mmol/mol) A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
|
|
|
+ if nr_bgs > 0 {
|
|
|
+ NGSPa1CStatisticValue_30 = ((bg_30 / conversionFactor) + 46.7) / 28.7
|
|
|
+ IFCCa1CStatisticValue_30 = 10.929 * (NGSPa1CStatisticValue_30 - 2.152)
|
|
|
}
|
|
|
// Total days
|
|
|
var NGSPa1CStatisticValue_total: Decimal = 0.0
|
|
|
var IFCCa1CStatisticValue_total: Decimal = 0.0
|
|
|
if nr_bgs > 0 {
|
|
|
- NGSPa1CStatisticValue_total = (46.7 + bg_total) / 28.7 // NGSP (%)
|
|
|
+ NGSPa1CStatisticValue_total = ((bg_total / conversionFactor) + 46.7) / 28.7
|
|
|
IFCCa1CStatisticValue_total = 10.929 *
|
|
|
- (NGSPa1CStatisticValue_total - 2.152) // IFCC (mmol/mol) A1C(mmol/mol) = 10.929 * (A1C(%) - 2.15)
|
|
|
+ (NGSPa1CStatisticValue_total - 2.152)
|
|
|
}
|
|
|
|
|
|
- var median = Durations(
|
|
|
- day: roundDecimal(Decimal(medianCalculation(array: bgArray_1.map(\.bg_))), 1),
|
|
|
- week: roundDecimal(Decimal(medianCalculation(array: bgArray_7.map(\.bg_))), 1),
|
|
|
- month: roundDecimal(Decimal(medianCalculation(array: bgArray_30.map(\.bg_))), 1),
|
|
|
+ let median = Durations(
|
|
|
+ day: roundDecimal(Decimal(medianCalculation(array: bgArray_1_)), 1),
|
|
|
+ week: roundDecimal(Decimal(medianCalculation(array: bgArray_7_)), 1),
|
|
|
+ month: roundDecimal(Decimal(medianCalculation(array: bgArray_30_)), 1),
|
|
|
total: roundDecimal(Decimal(medianBG), 1)
|
|
|
)
|
|
|
-
|
|
|
var hbs = Durations(
|
|
|
day: roundDecimal(NGSPa1CStatisticValue, 1),
|
|
|
week: roundDecimal(NGSPa1CStatisticValue_7, 1),
|
|
|
@@ -1090,20 +1043,7 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
// Convert to user-preferred unit
|
|
|
let overrideHbA1cUnit = settingsManager.preferences.overrideHbA1cUnit
|
|
|
-
|
|
|
if units == .mmolL {
|
|
|
- bg_1 = bg_1.asMmolL
|
|
|
- bg_7 = bg_7.asMmolL
|
|
|
- bg_30 = bg_30.asMmolL
|
|
|
- bg_total = bg_total.asMmolL
|
|
|
-
|
|
|
- median = Durations(
|
|
|
- day: roundDecimal(Decimal(medianCalculation(array: bgArray_1.map(\.bg_))).asMmolL, 1),
|
|
|
- week: roundDecimal(Decimal(medianCalculation(array: bgArray_7.map(\.bg_))).asMmolL, 1),
|
|
|
- month: roundDecimal(Decimal(medianCalculation(array: bgArray_30.map(\.bg_))).asMmolL, 1),
|
|
|
- total: roundDecimal(Decimal(medianBG).asMmolL, 1)
|
|
|
- )
|
|
|
-
|
|
|
// Override if users sets overrideHbA1cUnit: true
|
|
|
if !overrideHbA1cUnit {
|
|
|
hbs = Durations(
|
|
|
@@ -1137,10 +1077,10 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
median_interval: roundDecimal(Decimal(medianInterval), 1),
|
|
|
min_interval: roundDecimal(Decimal(minimumInt), 1),
|
|
|
max_interval: roundDecimal(Decimal(maximumInt), 1),
|
|
|
- avg_duration: Decimal(roundDouble(averageLoopTime, 2)),
|
|
|
- median_duration: Decimal(roundDouble(medianLoopTime, 2)),
|
|
|
- min_duration: roundDecimal(Decimal(minimumLoopTime), 2),
|
|
|
- max_duration: Decimal(roundDouble(maximumLoopTime, 1))
|
|
|
+ avg_duration: Decimal(roundDouble(averageLoopTime * 60, 2)), // Use seconds
|
|
|
+ median_duration: Decimal(roundDouble(medianLoopTime * 60, 2)), // Use seconds
|
|
|
+ min_duration: roundDecimal(Decimal(minimumLoopTime * 60), 2), // Use seconds
|
|
|
+ max_duration: Decimal(roundDouble(maximumLoopTime * 60, 1)) // Use seconds
|
|
|
)
|
|
|
|
|
|
// TIR calcs for every case
|
|
|
@@ -1150,16 +1090,10 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
var totalDays_: (TIR: Double, hypos: Double, hypers: Double) = (0.0, 0.0, 0.0)
|
|
|
|
|
|
// Get all TIR calcs for every case
|
|
|
- if end1 {
|
|
|
+ if nr_bgs > 0 {
|
|
|
oneDay_ = tir(bgArray_1)
|
|
|
- }
|
|
|
- if end7 {
|
|
|
sevenDays_ = tir(bgArray_7)
|
|
|
- }
|
|
|
- if end30 {
|
|
|
thirtyDays_ = tir(bgArray_30)
|
|
|
- }
|
|
|
- if nr_bgs > 0 {
|
|
|
totalDays_ = tir(bgArrayForTIR)
|
|
|
}
|
|
|
|
|
|
@@ -1204,38 +1138,6 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
scheduled_basal: suggestion?.insulin?.scheduled_basal ?? 0
|
|
|
)
|
|
|
|
|
|
- // SD and CV calculations for all durations:
|
|
|
-
|
|
|
- var sumOfSquares: Decimal = 0
|
|
|
- var sumOfSquares_1: Decimal = 0
|
|
|
- var sumOfSquares_7: Decimal = 0
|
|
|
- var sumOfSquares_30: Decimal = 0
|
|
|
-
|
|
|
- // Total
|
|
|
- for array in bgArray {
|
|
|
- if units == .mmolL {
|
|
|
- sumOfSquares += pow(Decimal(array).asMmolL - bg_total, 2)
|
|
|
- } else { sumOfSquares += pow(Decimal(array) - bg_total, 2) }
|
|
|
- }
|
|
|
- // One day
|
|
|
- for array_1 in bgArray_1_ {
|
|
|
- if units == .mmolL {
|
|
|
- sumOfSquares_1 += pow(Decimal(array_1).asMmolL - bg_1, 2)
|
|
|
- } else { sumOfSquares_1 += pow(Decimal(array_1) - bg_1, 2) }
|
|
|
- }
|
|
|
- // week
|
|
|
- for array_7 in bgArray_7_ {
|
|
|
- if units == .mmolL {
|
|
|
- sumOfSquares_7 += pow(Decimal(array_7).asMmolL - bg_7, 2)
|
|
|
- } else { sumOfSquares_7 += pow(Decimal(array_7) - bg_7, 2) }
|
|
|
- }
|
|
|
- // month
|
|
|
- for array_30 in bgArray_30_ {
|
|
|
- if units == .mmolL {
|
|
|
- sumOfSquares_30 += pow(Decimal(array_30).asMmolL - bg_30, 2)
|
|
|
- } else { sumOfSquares_30 += pow(Decimal(array_30) - bg_30, 2) }
|
|
|
- }
|
|
|
-
|
|
|
// Standard deviation and Coefficient of variation
|
|
|
var sd_total = 0.0
|
|
|
var cv_total = 0.0
|
|
|
@@ -1247,27 +1149,20 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
var cv_30 = 0.0
|
|
|
|
|
|
// Avoid division by zero
|
|
|
- if avgs.total < 1 || nr_bgs < 1 { sd_total = 0
|
|
|
- cv_total = 0 } else {
|
|
|
- sd_total = sqrt(Double(sumOfSquares / nr_bgs))
|
|
|
+ if bg_total > 0 {
|
|
|
+ sd_total = sqrt(vDSP.rootMeanSquare(bgArray))
|
|
|
cv_total = sd_total / Double(bg_total) * 100
|
|
|
}
|
|
|
- if avgs.day < 1 || nr_bgs_1 < 1 {
|
|
|
- sd_1 = 0
|
|
|
- cv_1 = 0
|
|
|
- } else {
|
|
|
- sd_1 = sqrt(Double(sumOfSquares_1 / nr_bgs_1))
|
|
|
+ if bg_1 > 0 {
|
|
|
+ sd_1 = sqrt(vDSP.rootMeanSquare(bgArray_1_))
|
|
|
cv_1 = sd_1 / Double(bg_1) * 100
|
|
|
}
|
|
|
- if avgs.week < 1 || nr_bgs_7 < 1 {
|
|
|
- sd_7 = 0
|
|
|
- cv_7 = 0
|
|
|
- } else {
|
|
|
- sd_7 = sqrt(Double(sumOfSquares_7 / nr_bgs_7))
|
|
|
+ if bg_7 > 0 {
|
|
|
+ sd_7 = sqrt(vDSP.rootMeanSquare(bgArray_7_))
|
|
|
cv_7 = sd_7 / Double(bg_7) * 100
|
|
|
}
|
|
|
- if avgs.month < 1 || nr_bgs_30 < 1 { sd_30 = 0
|
|
|
- cv_30 = 0 } else { sd_30 = sqrt(Double(sumOfSquares_30 / nr_bgs_30))
|
|
|
+ if bg_30 > 0 {
|
|
|
+ sd_30 = sqrt(vDSP.rootMeanSquare(bgArray_30_))
|
|
|
cv_30 = sd_30 / Double(bg_30) * 100
|
|
|
}
|
|
|
|
|
|
@@ -1306,6 +1201,7 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
peakActivityTime: iPa,
|
|
|
Carbs_24h: carbTotal,
|
|
|
GlucoseStorage_Days: Decimal(daysBG),
|
|
|
+ TimeOfComputation: Decimal(-1 * roundDouble(statisticsStartedAt.timeIntervalSinceNow, 1)),
|
|
|
Statistics: Stats(
|
|
|
Distribution: TimeInRange,
|
|
|
Glucose: avg,
|
|
|
@@ -1318,30 +1214,28 @@ final class BaseAPSManager: APSManager, Injectable {
|
|
|
|
|
|
storage.transaction { storage in
|
|
|
storage.append(dailystat, to: file, uniqBy: \.created_at)
|
|
|
- var uniqeEvents: [Statistics] = storage.retrieve(file, as: [Statistics].self)?
|
|
|
+ let uniqeEvents: [Statistics] = storage.retrieve(file, as: [Statistics].self)?
|
|
|
.filter { $0.created_at.addingTimeInterval(24.hours.timeInterval) > Date() }
|
|
|
.sorted { $0.created_at > $1.created_at } ?? []
|
|
|
-
|
|
|
storage.save(Array(uniqeEvents), as: file)
|
|
|
}
|
|
|
-
|
|
|
nightscout.uploadStatistics(dailystat: dailystat)
|
|
|
- nightscout.uploadPreferences()
|
|
|
+ // nightscout.uploadPreferences()
|
|
|
+ print("Test time of statistics computation: \(-1 * statisticsStartedAt.timeIntervalSinceNow) s")
|
|
|
}
|
|
|
|
|
|
private func loopStats(loopStatRecord: LoopStats) {
|
|
|
+ let LoopStatsStartedAt = Date()
|
|
|
let file = OpenAPS.Monitor.loopStats
|
|
|
-
|
|
|
var uniqEvents: [LoopStats] = []
|
|
|
-
|
|
|
storage.transaction { storage in
|
|
|
storage.append(loopStatRecord, to: file, uniqBy: \.start)
|
|
|
uniqEvents = storage.retrieve(file, as: [LoopStats].self)?
|
|
|
.filter { $0.start.addingTimeInterval(24.hours.timeInterval) > Date() }
|
|
|
.sorted { $0.start > $1.start } ?? []
|
|
|
-
|
|
|
storage.save(Array(uniqEvents), as: file)
|
|
|
}
|
|
|
+ print("Test time of LoopStats computation: \(-1 * LoopStatsStartedAt.timeIntervalSinceNow) s")
|
|
|
}
|
|
|
|
|
|
private func processError(_ error: Error) {
|