Skip to content

Commit cdf94ba

Browse files
committed
add min and max to glucose stats
1 parent 189fd24 commit cdf94ba

File tree

2 files changed

+179
-37
lines changed

2 files changed

+179
-37
lines changed

summary/types/glucose.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,43 @@ func (rs *GlucoseRanges) CalculateDelta(current, previous *GlucoseRanges) {
201201
rs.AnyHigh.CalculateDelta(&current.AnyHigh, &previous.AnyHigh)
202202
}
203203

204+
type MinMax struct {
205+
Min float64 `json:"min,omitempty" bson:"min,omitempty"`
206+
Max float64 `json:"max,omitempty" bson:"max,omitempty"`
207+
}
208+
209+
func (m *MinMax) Update(record *glucoseDatum.Glucose) {
210+
normalizedValue := *glucose.NormalizeValueForUnits(record.Value, record.Units)
211+
212+
// we need to catch the starting min value of 0 which will always be impossibly low
213+
if m.Min == 0 || normalizedValue < m.Min {
214+
m.Min = normalizedValue
215+
}
216+
217+
if m.Max == 0 || normalizedValue > m.Max {
218+
m.Max = normalizedValue
219+
}
220+
}
221+
222+
func (m *MinMax) Add(new *MinMax) {
223+
if m.Min == 0 || new.Min < m.Min {
224+
m.Min = new.Min
225+
}
226+
227+
if m.Max == 0 || new.Max > m.Max {
228+
m.Max = new.Max
229+
}
230+
}
231+
232+
func (m *MinMax) CalculateDelta(current *MinMax, previous *MinMax) {
233+
m.Min = current.Min - previous.Min
234+
m.Max = current.Max - previous.Max
235+
}
236+
204237
type GlucoseBucket struct {
205-
GlucoseRanges `json:",inline" bson:",inline"`
238+
GlucoseRanges `json:",inline" bson:",inline"`
239+
MinMax `json:",inline" bson:",inline"`
240+
206241
LastRecordDuration int `json:"lastRecordDuration" bson:"lastRecordDuration"`
207242
}
208243

@@ -237,6 +272,7 @@ func (b *GlucoseBucket) Update(r data.Datum, lastData *time.Time) (bool, error)
237272
return false, nil
238273
}
239274

275+
b.MinMax.Update(record)
240276
b.GlucoseRanges.Update(record)
241277
b.LastRecordDuration = GetDuration(record)
242278

@@ -245,6 +281,8 @@ func (b *GlucoseBucket) Update(r data.Datum, lastData *time.Time) (bool, error)
245281

246282
type GlucosePeriod struct {
247283
GlucoseRanges `json:",inline" bson:",inline"`
284+
MinMax `json:",inline" bson:",inline"`
285+
248286
HoursWithData int `json:"hoursWithData,omitempty" bson:"hoursWithData,omitempty"`
249287
DaysWithData int `json:"daysWithData,omitempty" bson:"daysWithData,omitempty"`
250288

@@ -263,6 +301,7 @@ type GlucosePeriod struct {
263301

264302
func (p *GlucosePeriod) CalculateDelta(current *GlucosePeriod, previous *GlucosePeriod) {
265303
p.GlucoseRanges.CalculateDelta(&current.GlucoseRanges, &previous.GlucoseRanges)
304+
p.MinMax.CalculateDelta(&current.MinMax, &previous.MinMax)
266305

267306
Delta(&current.AverageGlucose, &previous.AverageGlucose, &p.AverageGlucose)
268307
Delta(&current.GlucoseManagementIndicator, &previous.GlucoseManagementIndicator, &p.GlucoseManagementIndicator)
@@ -322,7 +361,8 @@ func (p *GlucosePeriod) Update(bucket *Bucket[*GlucoseBucket, GlucoseBucket]) er
322361
}
323362
}
324363

325-
p.Add(&bucket.Data.GlucoseRanges)
364+
p.MinMax.Add(&bucket.Data.MinMax)
365+
p.GlucoseRanges.Add(&bucket.Data.GlucoseRanges)
326366

327367
return nil
328368
}

summary/types/glucose_test.go

Lines changed: 137 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,102 @@ var _ = Describe("Glucose", func() {
3131
bucketTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
3232
})
3333

34+
Context("MinMax", func() {
35+
Context("Update", func() {
36+
37+
It("Adding 1 value", func() {
38+
minMax := MinMax{}
39+
datum := NewGlucoseWithValue(continuous.Type, now, 5)
40+
41+
minMax.Update(datum)
42+
Expect(minMax.Max).To(Equal(5.0))
43+
Expect(minMax.Min).To(Equal(5.0))
44+
})
45+
46+
It("Adding 2 values, replacing Max", func() {
47+
minMax := MinMax{}
48+
49+
By("adding the first number")
50+
datum := NewGlucoseWithValue(continuous.Type, now, 3)
51+
minMax.Update(datum)
52+
Expect(minMax.Max).To(Equal(3.0))
53+
Expect(minMax.Min).To(Equal(3.0))
54+
55+
By("adding the second number")
56+
datum = NewGlucoseWithValue(continuous.Type, now, 7)
57+
minMax.Update(datum)
58+
Expect(minMax.Max).To(Equal(7.0))
59+
Expect(minMax.Min).To(Equal(3.0))
60+
})
61+
62+
It("Adding 2 values, replacing Min", func() {
63+
minMax := MinMax{}
64+
65+
By("adding the first number")
66+
datum := NewGlucoseWithValue(continuous.Type, now, 7)
67+
minMax.Update(datum)
68+
Expect(minMax.Max).To(Equal(7.0))
69+
Expect(minMax.Min).To(Equal(7.0))
70+
71+
By("adding the second number")
72+
datum = NewGlucoseWithValue(continuous.Type, now, 3)
73+
minMax.Update(datum)
74+
Expect(minMax.Max).To(Equal(7.0))
75+
Expect(minMax.Min).To(Equal(3.0))
76+
})
77+
78+
It("Adding one value, leaving unchanged", func() {
79+
minMax := MinMax{Min: 3, Max: 7}
80+
81+
datum := NewGlucoseWithValue(continuous.Type, now, 5)
82+
minMax.Update(datum)
83+
Expect(minMax.Max).To(Equal(7.0))
84+
Expect(minMax.Min).To(Equal(3.0))
85+
})
86+
87+
})
88+
89+
Context("Add", func() {
90+
91+
It("replacing Min", func() {
92+
minMax := MinMax{Min: 3, Max: 7}
93+
minMaxNew := MinMax{Min: 2, Max: 7}
94+
95+
minMax.Add(&minMaxNew)
96+
Expect(minMax.Max).To(Equal(7.0))
97+
Expect(minMax.Min).To(Equal(2.0))
98+
})
99+
100+
It("replacing Max", func() {
101+
minMax := MinMax{Min: 3, Max: 4}
102+
minMaxNew := MinMax{Min: 3, Max: 7}
103+
104+
minMax.Add(&minMaxNew)
105+
Expect(minMax.Max).To(Equal(7.0))
106+
Expect(minMax.Min).To(Equal(3.0))
107+
})
108+
109+
It("replacing both", func() {
110+
minMax := MinMax{Min: 4, Max: 5}
111+
minMaxNew := MinMax{Min: 3, Max: 7}
112+
113+
minMax.Add(&minMaxNew)
114+
Expect(minMax.Max).To(Equal(7.0))
115+
Expect(minMax.Min).To(Equal(3.0))
116+
})
117+
118+
It("replacing neither", func() {
119+
minMax := MinMax{Min: 3, Max: 7}
120+
minMaxNew := MinMax{Min: 4, Max: 5}
121+
122+
minMax.Add(&minMaxNew)
123+
Expect(minMax.Max).To(Equal(7.0))
124+
Expect(minMax.Min).To(Equal(3.0))
125+
})
126+
127+
})
128+
})
129+
34130
Context("Range", func() {
35131
It("range.UpdateTotal", func() {
36132
glucoseRange := Range{}
@@ -494,10 +590,9 @@ var _ = Describe("Glucose", func() {
494590
Expect(userBucket.Time).To(Equal(bucketTime))
495591
Expect(userBucket.Data.Target.Records).To(Equal(1))
496592
Expect(userBucket.Data.Target.Minutes).To(Equal(5))
593+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
594+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
497595
Expect(userBucket.IsModified()).To(BeTrue())
498-
499-
Expect(userBucket.Data.Target.Records).To(Equal(userBucket.Data.Total.Records))
500-
Expect(userBucket.Data.Target.Minutes).To(Equal(userBucket.Data.Total.Minutes))
501596
})
502597

503598
It("With a bgm value", func() {
@@ -513,10 +608,9 @@ var _ = Describe("Glucose", func() {
513608
Expect(userBucket.Time).To(Equal(bucketTime))
514609
Expect(userBucket.Data.Target.Records).To(Equal(1))
515610
Expect(userBucket.Data.Target.Minutes).To(Equal(0))
611+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
612+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
516613
Expect(userBucket.IsModified()).To(BeTrue())
517-
518-
Expect(userBucket.Data.Target.Records).To(Equal(userBucket.Data.Total.Records))
519-
Expect(userBucket.Data.Target.Minutes).To(Equal(userBucket.Data.Total.Minutes))
520614
})
521615

522616
It("With two cgm values within 5 minutes", func() {
@@ -531,6 +625,8 @@ var _ = Describe("Glucose", func() {
531625
Expect(userBucket.LastData).To(Equal(datumTime))
532626
Expect(userBucket.Data.Target.Records).To(Equal(1))
533627
Expect(userBucket.Data.Target.Minutes).To(Equal(5))
628+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
629+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
534630

535631
newDatumTime := bucketTime.Add(9 * time.Minute)
536632
cgmDatum = NewGlucoseWithValue(continuous.Type, newDatumTime, InTargetBloodGlucose)
@@ -541,6 +637,8 @@ var _ = Describe("Glucose", func() {
541637
Expect(userBucket.LastData).To(Equal(datumTime))
542638
Expect(userBucket.Data.Target.Records).To(Equal(1))
543639
Expect(userBucket.Data.Target.Minutes).To(Equal(5))
640+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
641+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
544642
})
545643

546644
It("With two bgm values within 5 minutes", func() {
@@ -555,6 +653,8 @@ var _ = Describe("Glucose", func() {
555653
Expect(userBucket.FirstData).To(Equal(datumTime))
556654
Expect(userBucket.Data.Target.Records).To(Equal(1))
557655
Expect(userBucket.Data.Target.Minutes).To(Equal(0))
656+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
657+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
558658

559659
newDatumTime := bucketTime.Add(9 * time.Minute)
560660
bgmDatum = NewGlucoseWithValue(selfmonitored.Type, newDatumTime, InTargetBloodGlucose)
@@ -565,29 +665,10 @@ var _ = Describe("Glucose", func() {
565665
Expect(userBucket.LastData).To(Equal(newDatumTime))
566666
Expect(userBucket.Data.Target.Records).To(Equal(2))
567667
Expect(userBucket.Data.Target.Minutes).To(Equal(0))
668+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
669+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
568670
})
569671

570-
// we no longer check this
571-
//It("With a smbg value in a cgm bucket", func() {
572-
// datumTime := bucketTime.Add(5 * time.Minute)
573-
// userBucket = NewBucket[*GlucoseBucket](userId, bucketTime, SummaryTypeCGM)
574-
// bgmDatum := NewGlucoseWithValue(selfmonitored.Type, datumTime, InTargetBloodGlucose)
575-
//
576-
// err = userBucket.Update(bgmDatum)
577-
// Expect(err).To(HaveOccurred())
578-
// Expect(err).To(MatchError("record for cgm calculation is of invald type smbg"))
579-
//})
580-
581-
//It("With a cbg value in a bgm bucket", func() {
582-
// datumTime := bucketTime.Add(5 * time.Minute)
583-
// userBucket = NewBucket[*GlucoseBucket](userId, bucketTime, SummaryTypeBGM)
584-
// cgmDatum = NewGlucoseWithValue(continuous.Type, datumTime, InTargetBloodGlucose)
585-
//
586-
// err = userBucket.Update(cgmDatum)
587-
// Expect(err).To(HaveOccurred())
588-
// Expect(err).To(MatchError("record for bgm calculation is of invald type cbg"))
589-
//})
590-
591672
It("With two values in a range", func() {
592673
datumTime := bucketTime.Add(5 * time.Minute)
593674
userBucket = NewBucket[*GlucoseBucket](userId, bucketTime, SummaryTypeCGM)
@@ -603,11 +684,10 @@ var _ = Describe("Glucose", func() {
603684
Expect(userBucket.Time).To(Equal(bucketTime))
604685
Expect(userBucket.Data.Target.Records).To(Equal(1))
605686
Expect(userBucket.Data.Target.Minutes).To(Equal(5))
687+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
688+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
606689
Expect(userBucket.IsModified()).To(BeTrue())
607690

608-
Expect(userBucket.Data.Target.Records).To(Equal(userBucket.Data.Total.Records))
609-
Expect(userBucket.Data.Target.Minutes).To(Equal(userBucket.Data.Total.Minutes))
610-
611691
secondDatumTime := datumTime.Add(5 * time.Minute)
612692
cgmDatum = NewGlucoseWithValue(continuous.Type, secondDatumTime, InTargetBloodGlucose)
613693

@@ -621,11 +701,9 @@ var _ = Describe("Glucose", func() {
621701
Expect(userBucket.Time).To(Equal(bucketTime))
622702
Expect(userBucket.Data.Target.Records).To(Equal(2))
623703
Expect(userBucket.Data.Target.Minutes).To(Equal(10))
704+
Expect(userBucket.Data.Min).To(Equal(InTargetBloodGlucose))
705+
Expect(userBucket.Data.Max).To(Equal(InTargetBloodGlucose))
624706
Expect(userBucket.IsModified()).To(BeTrue())
625-
626-
Expect(userBucket.Data.Target.Records).To(Equal(userBucket.Data.Total.Records))
627-
Expect(userBucket.Data.Target.Minutes).To(Equal(userBucket.Data.Total.Minutes))
628-
629707
})
630708

631709
It("With values in all ranges", func() {
@@ -640,6 +718,9 @@ var _ = Describe("Glucose", func() {
640718
ExtremeHighBloodGlucose + 0.1: &userBucket.Data.ExtremeHigh,
641719
}
642720

721+
expectedMin := 9999.9
722+
expectedMax := -1.0
723+
643724
expectedGlucose := 0.0
644725
expectedMinutes := 0
645726
expectedRecords := 0
@@ -701,7 +782,19 @@ var _ = Describe("Glucose", func() {
701782
Expect(userBucket.Data.VeryHigh.Records).To(Equal(expectedVeryHighRecords))
702783
Expect(userBucket.Data.VeryHigh.Minutes).To(Equal(expectedVeryHighMinutes))
703784

704-
// we should check that total gets variance
785+
if k > float64(expectedMax) {
786+
expectedMax = k
787+
}
788+
if k < float64(expectedMin) {
789+
expectedMin = k
790+
}
791+
Expect(userBucket.Data.Min).To(Equal(expectedMin))
792+
Expect(userBucket.Data.Max).To(Equal(expectedMax))
793+
794+
if offset > 0 {
795+
Expect(userBucket.Data.Total.Variance).ToNot(BeZero())
796+
}
797+
705798
offset++
706799
}
707800
})
@@ -760,18 +853,24 @@ var _ = Describe("Glucose", func() {
760853
Expect(period.Target.Records).To(Equal(1))
761854
Expect(period.HoursWithData).To(Equal(1))
762855
Expect(period.DaysWithData).To(Equal(1))
856+
Expect(period.Min).To(Equal(InTargetBloodGlucose))
857+
Expect(period.Max).To(Equal(InTargetBloodGlucose))
763858

764859
err = period.Update(bucketTwo)
765860
Expect(err).ToNot(HaveOccurred())
766861
Expect(period.Target.Records).To(Equal(2))
767862
Expect(period.HoursWithData).To(Equal(2))
768863
Expect(period.DaysWithData).To(Equal(1))
864+
Expect(period.Min).To(Equal(InTargetBloodGlucose))
865+
Expect(period.Max).To(Equal(InTargetBloodGlucose))
769866

770867
err = period.Update(bucketThree)
771868
Expect(err).ToNot(HaveOccurred())
772869
Expect(period.Target.Records).To(Equal(3))
773870
Expect(period.HoursWithData).To(Equal(3))
774871
Expect(period.DaysWithData).To(Equal(2))
872+
Expect(period.Min).To(Equal(InTargetBloodGlucose))
873+
Expect(period.Max).To(Equal(InTargetBloodGlucose))
775874
})
776875

777876
It("Finalize a 1d period", func() {
@@ -1130,6 +1229,7 @@ var _ = Describe("Glucose", func() {
11301229
Variance: 8,
11311230
},
11321231
},
1232+
MinMax: MinMax{Min: 3, Max: 5},
11331233
HoursWithData: 0,
11341234
DaysWithData: 1,
11351235
AverageGlucose: 2,
@@ -1205,6 +1305,7 @@ var _ = Describe("Glucose", func() {
12051305
Variance: 15,
12061306
},
12071307
},
1308+
MinMax: MinMax{Min: 5, Max: 6},
12081309
HoursWithData: 99,
12091310
DaysWithData: 98,
12101311
AverageGlucose: 97,
@@ -1265,6 +1366,7 @@ var _ = Describe("Glucose", func() {
12651366
Percent: -8,
12661367
},
12671368
},
1369+
MinMax: MinMax{Min: -2, Max: -1},
12681370
HoursWithData: -99,
12691371
DaysWithData: -97,
12701372
AverageGlucose: -95,

0 commit comments

Comments
 (0)