Hi, came across this while working with the same API and wanted to flag something in the snippet that's easy to miss.
The precededByGap handling drops the flagged beat, but the interval loop still diffs every consecutive pair:
swift
if !precededByGap {
timePoints.append(timeSinceSeriesStart)
}
So if beats land at t₁, t₂, [gap], t₅, t₆: t₅ gets discarded, and the loop then computes t₆ − t₂ and reports it as a single IBI. That value spans both the gap and the dropped beat, so you end up with intervals roughly 2–3× a normal one scattered through the output.
The flag is telling you the interval leading into this beat isn't valid, not that the beat's timestamp is bad. So keep every timestamp and skip the interval instead:
swift
struct Beat {
let time: TimeInterval
let precededByGap: Bool
}
var beats: [Beat] = []
// in the HKHeartbeatSeriesQuery handler:
beats.append(Beat(time: timeSinceSeriesStart, precededByGap: precededByGap))
if done {
for i in 1..<beats.count {
guard !beats[i].precededByGap else { continue } // interval spans a gap
let ibi = (beats[i].time - beats[i-1].time) * 1000
self.ibiValues.append(ibi)
}
}
Two benefits: the invalid interval goes away, and you recover the valid t₆ − t₅ interval the original version was throwing out.
Worth sorting before you benchmark against the Galaxy values, given you're computing stress from HRV. RMSSD squares successive differences, so one inflated interval can dominate a window, and in the frequency domain it injects broadband energy right across the LF/HF boundary. A couple of these per window will move your metric more than any real difference between the two devices.
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags: