CalibrationService.swift 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import Foundation
  2. import Swinject
  3. struct Calibration: JSON, Hashable, Identifiable {
  4. let x: Double
  5. let y: Double
  6. var date = Date()
  7. static let zero = Calibration(x: 0, y: 0)
  8. var id = UUID()
  9. }
  10. protocol CalibrationService {
  11. var slope: Double { get }
  12. var intercept: Double { get }
  13. var calibrations: [Calibration] { get }
  14. func addCalibration(_ calibration: Calibration)
  15. func removeCalibration(_ calibration: Calibration)
  16. func removeAllCalibrations()
  17. func removeLast()
  18. func calibrate(value: Double) -> Double
  19. }
  20. final class BaseCalibrationService: CalibrationService, Injectable {
  21. private enum Config {
  22. static let minSlope = 0.8
  23. static let maxSlope = 1.25
  24. static let minIntercept = -100.0
  25. static let maxIntercept = 100.0
  26. }
  27. @Injected() var storage: FileStorage!
  28. private(set) var calibrations: [Calibration] = [] {
  29. didSet {
  30. storage.save(calibrations, as: OpenAPS.FreeAPS.calibrations)
  31. }
  32. }
  33. init(resolver: Resolver) {
  34. injectServices(resolver)
  35. calibrations = storage.retrieve(OpenAPS.FreeAPS.calibrations, as: [Calibration].self) ?? []
  36. }
  37. var slope: Double {
  38. guard calibrations.count >= 2 else {
  39. return 1
  40. }
  41. let xs = calibrations.map(\.x)
  42. let ys = calibrations.map(\.y)
  43. let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys)
  44. let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2)
  45. let slope = sum1 / sum2
  46. return min(max(slope, Config.minSlope), Config.maxSlope)
  47. }
  48. var intercept: Double {
  49. guard calibrations.count >= 1 else {
  50. return 0
  51. }
  52. let xs = calibrations.map(\.x)
  53. let ys = calibrations.map(\.y)
  54. let intercept = average(ys) - slope * average(xs)
  55. return min(max(intercept, Config.minIntercept), Config.maxIntercept)
  56. }
  57. func calibrate(value: Double) -> Double {
  58. linearRegression(value)
  59. }
  60. func addCalibration(_ calibration: Calibration) {
  61. calibrations.append(calibration)
  62. }
  63. func removeCalibration(_ calibration: Calibration) {
  64. calibrations.removeAll { $0 == calibration }
  65. }
  66. func removeAllCalibrations() {
  67. calibrations.removeAll()
  68. }
  69. func removeLast() {
  70. calibrations.removeLast()
  71. }
  72. private func average(_ input: [Double]) -> Double {
  73. input.reduce(0, +) / Double(input.count)
  74. }
  75. private func multiply(_ a: [Double], _ b: [Double]) -> [Double] {
  76. zip(a, b).map(*)
  77. }
  78. private func linearRegression(_ x: Double) -> Double {
  79. intercept + slope * x
  80. }
  81. }