V02max 总是被填充为 0.0。

huangapple go评论71阅读模式
英文:

V02max is always populated with 0.0

问题

我正在开发一个应用程序,旨在分析跑步锻炼,包括有氧健身。因此,我试图从HKWorkout中读取VO2max值,但对其他指标来说一切正常,但VO2max始终为0.0:

avgWatts = workout
    .statistics(for: .init(.runningPower))?
    .averageQuantity()?
    .doubleValue(for: .watt()) ?? 0

vo2max = workout
    .statistics(for: .init(.vo2Max))?
    .maximumQuantity()?
    .doubleValue(for: HKUnit(from: "ml/kg*min")) ?? 0.0

我认为我已正确设置权限:

func authorizationDetails(){
    let allTypes = Set([HKObjectType.workoutType(),
                        HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
                        HKObjectType.quantityType(forIdentifier: .distanceCycling)!,
                        HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                        HKObjectType.quantityType(forIdentifier: .heartRate)!,
                        HKObjectType.quantityType(forIdentifier: .runningStrideLength)!,
                        HKObjectType.quantityType(forIdentifier: .vo2Max)!])

    healthStore.requestAuthorization(toShare: allTypes, read: allTypes) { (success, error) in
        if !success {
            // 处理错误
        } else {
            self.isAuthorized = true
        }
    }
}

我不确定问题出在哪里,也无法在苹果的文档中找到相关信息。可能在HKWorkout中该数量类型不可用吗?

我还尝试使用sumQuantity而不是maximumQuantity,但它仍然没有提供数值:

vo2max = workout
    .statistics(for: .init(.vo2Max))?
    .sumQuantity()?
    .doubleValue(for: HKUnit(from: "ml/kg*min")) ?? 0.0

在其他应用程序(例如Health)中,我可以看到VO2max值,所以我认为数据实际上是可用的。

在此提前感谢任何建议。

英文:

I am developing an app, which aims to analyze running workouts including the cardio fitness. Therefore I am trying to read inter alia the vo2max value from HKWorkout.

This works fine for other measures, but V02max is always populated with 0.0:

                    avgWatts = workout
                        .statistics(for: .init(.runningPower))?
                        .averageQuantity()?
                        .doubleValue(for: .watt()) ?? 0
                    
                    vo2max = workout
                        .statistics(for: .init(.vo2Max))?
                        .maximumQuantity()?
                        .doubleValue(for: HKUnit(from: "ml/kg*min")) ?? 0.0

I am the opinion that I also have the permission correctly set:

    func authorizationDetails(){
        let allTypes = Set([HKObjectType.workoutType(),
                            HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
                            HKObjectType.quantityType(forIdentifier: .distanceCycling)!,
                            HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                            HKObjectType.quantityType(forIdentifier: .heartRate)!,
                            HKObjectType.quantityType(forIdentifier: .runningStrideLength)!,
                            HKObjectType.quantityType(forIdentifier: .vo2Max)!])
        
        
        healthStore.requestAuthorization(toShare: allTypes, read: allTypes) { (success, error) in
            if !success {
                // Handle the error here.
            }else{
                self.isAuthorized=true
            }
        }
        
    }

I am not sure what the problem is and I cannot find the respective information in apples documentation. Is that quantity type maybe not available in HKWorkout?

I was also trying to use sumQuantity instead of maximumQuantity, but it still does not provide values:

                    vo2max = workout
                        .statistics(for: .init(.vo2Max))?
                        .sumQuantity()?
                        .doubleValue(for: HKUnit(from: "ml/kg*min")) ?? 0.0

In other apps (e.g. Health) I can see the vo2max value, so I assume that the data is actually available.

Thank you in advance for any suggestions.

答案1

得分: 1

vo2max 的单位是 ml/kg/min 而不是 ml/kg*min。返回 0.0 是因为当它为 nil 时,你赋予它的值。为了进一步调试,我会验证表达式的每一步,确保它是你期望的。statistics 调用是否返回一个值?它是否有 averageQuantity?等等。(但我强烈怀疑问题在最后的转换,因为单位不正确。)

此外,请确保你查看的锻炼实际上附有 VO2Max 值。它经常没有记录(有很多要求)。

英文:

The unit for vo2max is ml/kg/min not ml/kg*min. It's returning 0.0 because that's what you assign when it's nil. To debug further, I would verify each step of the expression to make sure it's what you expect it to be. Does the statistics call return a value? Does it have an averageQuantity? etc. (But I strongly expect the problem is the last transform, since it's the wrong unit.)

Also definitely make sure that you're looking at a workout that actually has a VO2Max value attached. It often isn't recorded (it has a lot of requirements).

答案2

得分: 0

I'm developing an app dedicated for running and also encountered the same issue. I didn't find a solution elsewhere, so I spent time to investigate it myself. This question was raised 6 months ago. I'm not sure if you have figured out a solution, but I've got one and want to share it here for your (as well as others') reference.

The short answer to why it doesn't work with statistics method for vo2Max is that vo2Max doesn't even exist in statistics. I tried allStatistics to see all the keys that can be used to query and didn't see vo2Max.

My best guess is that vo2Max is not recorded with a strong relationship with the corresponding run as we expected. I tried to query it with a predicate created by passing the workout to HKQuery.predicateForObjects just like what I did for heart rates but got nothing. Why? I observered the data in Health app and noticed that vo2Max was recorded automatically some time after the workout has been submitted.

All the above investigation resulted in my solution to this problem. I query vo2Max with the start time as the end time of the workout and set a window to 5 minutes and then take the first vo2Max record. If you look at the time of the recorded vo2Max and the corresponding workout, you'll notice that vo2Max is usually recorded within 1 minute after the workout. So a 5-minute window would be enough, but you can change it as you see fit.

Below is the complete code that I use in my app:

private func queryVO2Max(for workout: HKWorkout) async -> Double? {
    Logger.shared.info("Querying VO2 max for a run from health store")
    Logger.shared.debug("Running HealthStoreManager.queryVO2Max")
        
    guard hasPermission else {
        return nil
    }
        
    // Note: It seems that VO2 max doesn't have a recorded relationship with a workout.
    // The strategy here is to fetch the first VO2 max after the workout end time.
    // Usually VO2 max will be recorded within 1 minute after a workout ends.
    // Here we set a 5 minute window for query.
    let vo2MaxType = HKQuantityType(.vo2Max)
    let timePredicate = HKQuery.predicateForSamples(withStart: workout.endDate, end: workout.endDate.addingTimeInterval(TimeInterval(5 * 60)))
    let queryDescriptor = HKSampleQueryDescriptor(
        predicates: [.quantitySample(type: vo2MaxType, predicate: timePredicate)],
        sortDescriptors: []
    )
    do {
        let queryResult = try await queryDescriptor.result(for: healthStore)
        let vo2Max = queryResult.first?.quantity.doubleValue(for: HKUnit.vo2MaxUnit())
        Logger.shared.info("VO2 max: \(vo2Max.toString())")
        return vo2Max
    } catch {
        return nil
    }
}

One more thing, the unit for vo2max is "ml/kg/min" as mentioned in the Health app. But if you use that to construct HKUnit, you will get an error. "ml/kg*min" is the String you should used to construct HKUnit.

Hope that helps.

英文:

I'm developing an app dedicated for running and also encountered the same issue. I didn't find a solution elsewhere, so I spent time to investigate it myself. This question was raised 6 months ago. I'm not sure if you have figured out a solution, but I've got one and want to share it here for your (as well as others') reference.

The short answer to why it doesn't work with statistics method for vo2Max is that vo2Max doesn't even exist in statistics. I tried allStatistics to see all the keys that can be used to query and didn't see vo2Max.

My best guess is that vo2Max is not recorded with a strong relationship with the corresponding run as we expected. I tried to query it with a predicate created by passing the workout to HKQuery.predicateForObjects just like what I did for heart rates but got nothing. Why? I observered the data in Health app and noticed that vo2Max was recorded automatically some time after the workout has been submitted.

All the above investigation resulted in my solution to this problem. I query vo2Max with the start time as the end time of the workout and set a window to 5 minutes and then take the first vo2Max record. If you look at the time of the recorded vo2Max and the corresponding workout, you'll notice that vo2Max is usually recorded within 1 minute after the workout. So a 5-minute window would be enough, but you can change it as you see fit.

Below is the complete code that I use in my app:

private func queryVO2Max(for workout: HKWorkout) async -> Double? {
    Logger.shared.info("Querying VO2 max for a run from health store")
    Logger.shared.debug("Running HealthStoreManager.queryVO2Max")
        
    guard hasPermission else {
        return nil
    }
        
    // Note: It seems that VO2 max doesn't have a recorded relationship with a workout.
    // The strategy here is to fetch the first VO2 max after the workout end time.
    // Usually VO2 max will be recorded within 1 minute after a workout ends.
    // Here we set a 5 minute window for query.
    let vo2MaxType = HKQuantityType(.vo2Max)
    let timePredicate = HKQuery.predicateForSamples(withStart: workout.endDate, end: workout.endDate.addingTimeInterval(TimeInterval(5 * 60)))
    let queryDescriptor = HKSampleQueryDescriptor(
        predicates: [.quantitySample(type: vo2MaxType, predicate: timePredicate)],
        sortDescriptors: []
    )
    do {
        let queryResult = try await queryDescriptor.result(for: healthStore)
        let vo2Max = queryResult.first?.quantity.doubleValue(for: HKUnit.vo2MaxUnit())
        Logger.shared.info("VO2 max: \(vo2Max.toString())")
        return vo2Max
    } catch {
        return nil
    }
}

One more thing, the unit for vo2max is "ml/kg/min" as mentioned in the Health app. But if you use that to construct HKUnit, you will get an error. "ml/kg*min" is the String you should used to construct HKUnit.

Hope that helps.

huangapple
  • 本文由 发表于 2023年2月18日 23:49:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494489.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定