以下是我到目前为止所获得的代码,无法弄清楚为什么我会收到不准确的数据。
不考虑暂停事件但不应影响前两公里的不准确性......
因此输出将是1km的距离和km所用的持续时间。 有任何改进的想法,请帮忙吗?
func getHealthKitWorkouts(){
print("HealthKit Workout:")
/* Boris here: Looks like we need some sort of Health Kit manager */
let healthStore:HKHealthStore = HKHealthStore()
let durationFormatter = NSDateComponentsFormatter()
var workouts = [HKWorkout]()
// Predicate to read only running workouts
let predicate = HKQuery.predicateForWorkoutsWithWorkoutActivityType(HKWorkoutActivityType.Running)
// Order the workouts by date
let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)
// Create the query
let sampleQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: predicate, limit: 0, sortDescriptors: [sortDescriptor])
{ (sampleQuery, results, error ) -> Void in
if let queryError = error {
print( "There was an error while reading the samples: \(queryError.localizedDescription)")
}
workouts = results as! [HKWorkout]
let target:Int = 0
print(workouts[target].workoutEvents)
print("Energy ", workouts[target].totalEnergyBurned)
print(durationFormatter.stringFromTimeInterval(workouts[target].duration))
print((workouts[target].totalDistance!.doubleValueForUnit(HKUnit.meterUnit())))
self.coolMan(workouts[target])
self.coolManStat(workouts[target])
}
// Execute the query
healthStore.executeQuery(sampleQuery)
}
func coolMan(let workout: HKWorkout){
let expectedOutput = [
NSTimeInterval(293),
NSTimeInterval(359),
NSTimeInterval(359),
NSTimeInterval(411),
NSTimeInterval(810)
]
let healthStore:HKHealthStore = HKHealthStore()
let distanceType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let workoutPredicate = HKQuery.predicateForObjectsFromWorkout(workout)
let startDateSort = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true)
let query = HKSampleQuery(sampleType: distanceType!, predicate: workoutPredicate,
limit: 0, sortDescriptors: [startDateSort]) {
(sampleQuery, results, error) -> Void in
// Process the detailed samples...
if let distanceSamples = results as? [HKQuantitySample] {
var count = 0.00, countPace = 0.00, countDistance = 0.0, countPacePerMeterSum = 0.0
var countSplits = 0
var firstStart = distanceSamples[0].startDate
let durationFormatter = NSDateComponentsFormatter()
print(" Time Splits: ")
for (index, element) in distanceSamples.enumerate() {
count += element.quantity.doubleValueForUnit(HKUnit.meterUnit())
/* Calculate Pace */
let duration = ((element.endDate.timeIntervalSinceDate(element.startDate)))
let distance = distanceSamples[index].quantity
let pacePerMeter = distance.doubleValueForUnit(HKUnit.meterUnit()) / duration
countPace += duration
countPacePerMeterSum += pacePerMeter
if count > 1000 {
/* Account for extra bits */
let percentageUnder = (1000 / count)
//countPace = countPace * percentageUnder
// 6.83299013038 * 2.5
print(" Reached Kilometer \(count) ")
// MARK: Testing
let testOutput = durationFormatter.stringFromTimeInterval(NSTimeInterval.init(floatLiteral: test)),
testOutputExpected = durationFormatter.stringFromTimeInterval(expectedOutput[countSplits])
print(" Output Accuracy (", round(test - expectedOutput[countSplits]) , "): expected \(testOutputExpected) versus \(testOutput)")
print(" ", firstStart, " until ", element.endDate)
/* Print The Split Time Taken */
firstStart = distanceSamples[index].endDate;
count = (count % 1000) //0.00
countPace = (count % 1000) * pacePerMeter
countSplits++
/* Noise
\(countSplits) – \(count) – Pace \(countPace) – Pace Per Meter \(pacePerMeter) – Summed Pace Per Meter \(countPacePerMeterSum) – \(countPacePerMeterSum / Double.init(index))"
*/
}
/* Account for the last entry */
if (distanceSamples.count - 1 ) == index {
print("We started a kilometer \(countSplits+1) – \(count)")
let pacePerKM = (count / countPace) * 1000
print(durationFormatter.stringFromTimeInterval(NSTimeInterval.init(floatLiteral: (pacePerKM ))))
}
}
}else {
// Perform proper error handling here...
print("*** An error occurred while adding a sample to " + "the workout: \(error!.localizedDescription)")
abort()
}
}
healthStore.executeQuery(query)
}
func coolManStat(let workout: HKWorkout){
let healthStore:HKHealthStore = HKHealthStore()
let stepsCount = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let sumOption = HKStatisticsOptions.CumulativeSum
let statisticsSumQuery = HKStatisticsQuery(quantityType: stepsCount!, quantitySamplePredicate: HKQuery.predicateForObjectsFromWorkout(workout),
options: sumOption)
{ (query, result, error) in
if let sumQuantity = result?.sumQuantity() {
let numberOfSteps = Int(sumQuantity.doubleValueForUnit(HKUnit.meterUnit()))/1000
print(" Right -O: ",numberOfSteps)
}
}
healthStore.executeQuery(statisticsSumQuery)
}
答案 0 :(得分:3)
我确定你现在已经过了两年多了这个问题!但我相信其他人将来会遇到这个帖子,所以我想我会分享答案。
我开始使用您的代码版本(非常感谢!!)并遇到了同样的问题。我不得不做一些改变。并非所有这些变化都与您所看到的问题有关,但无论如何,这是我到目前为止所考虑的所有考虑因素:
<强>漂移强>
你不会处理“漂移”,尽管这并不是导致你输出中出现大错误的原因。我的意思是你的代码说:
如果计数&gt; 1000
但是你不能做任何超过1000的剩余时间,所以你的公里时间不是1000米,而是,比方说,1001米。所以你的时间对于当前的km来说都是不准确的,并且它包括从下一公里跑的一些,所以时间也是错误的。从长远来看,这可能会引起明显的问题。但是短期内并不是什么大不了的事情,因为我不认为这种差距在很短的距离上是非常显着的。但它绝对值得修复。在我的代码中,我假设跑步者在当前样本中以恒定的速度移动(这显然不是完美的,但我不认为那里有更好的方式),而且我&#39 ;然后简单地找到当前样本距离的一小部分,使得分割距离超过1000米,并获得当前样本的持续时间的相同部分并将其从当前km的时间中移除,并添加它(和距离)到下一个分裂。
GPS丢弃
结果的真正问题在于您无法处理GPS丢弃。我目前正在处理的方法是将当前样本的startDate与前一个样本的endDate进行比较。如果它们不相同则会出现GPS下降。您需要将前一个endDate和当前startDate之间的差异添加到当前分割。 编辑:您还需要使用活动的startDate和第一个示例的startDate执行此操作。 GPS正在连接时,这两个日期之间会有差距。
暂停
上述GPS掉线问题有轻微的复杂性。如果用户暂停了锻炼,那么当前样本的startDate和前一个样本的endDate之间也会有差异。因此,您需要能够检测到这种情况,而不是在这种情况下调整分割。但是,如果用户的GPS掉线并且在此期间它们也暂停了,那么在将其添加到分割之前,您需要从丢失的时间中减去暂停时间。
不幸的是,我的分组仍未与Apple Workouts应用程序100%同步。但他们已经从可能的分钟时间变成了大部分在1秒内。我见过的最糟糕的是3秒。我只在这工作了几个小时,所以我打算继续努力获得100%的准确性。如果我知道的话,我会更新这个答案。但我相信我已经解决了这里的主要问题。