HealthKit以公里为单位运行拆分代码不准确 - 为什么?

时间:2015-11-20 12:38:44

标签: swift health-kit

以下是我到目前为止所获得的代码,无法弄清楚为什么我会收到不准确的数据。

不考虑暂停事件但不应影响前两公里的不准确性......

因此输出将是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)

}

Actual Output Output Log

1 个答案:

答案 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%的准确性。如果我知道的话,我会更新这个答案。但我相信我已经解决了这里的主要问题。