Apple健康数据准确性与可靠性
概述
尽管多年来一直从事Apple Health相关工作并撰写过相关博客,但我从未真正写过关于其准确性的内容。虽然已有他人发表过相关文章,且我的观点与已发布细节差异不大,但我认为这里有一些有价值的信息值得了解。
技术细节
分析文件
我们将重点分析以下两个文件:
/private/var/mobile/Library/Health/healthdb_secure.sqlite/private/var/root/Library/Caches/location/cache_encryptedC.db
Apple健康测试主要关注healthdb_secure.sqlite和cache_encryptedC.db中的数据,以确定设备在车辆行驶过程中是否可能错误记录爬楼层数事件或步数/距离。
Cache_encryptedC.db分析
Cache_encryptedC.db中的StepCountHistory表包含多个与时间戳相关的字段:
startTime
该字段始终包含与身体活动相关的时间戳值
timestamp
该字段像时间戳一样持续递增,但无法转换为典型的时间戳值
activeTime
该字段像时间戳一样持续递增,但无法转换为典型的时间戳值
firstStepTime
该字段并非总是包含值,但当有值时通常比startTime早约3秒
表中的其余字段跟踪总步数、行进距离、上升或下降的楼层数等。
在引用此数据库中的记录时,选择startTime字段作为最合适的时间戳字段,活动情况通过字段值的差异推断。
例如,如果存在以下记录:
| startTime | floorsAscended |
|---|---|
| 12:00:02 | 100 |
| 12:00:08 | 101 |
这表明在12:00:08时,设备检测到上升了一个楼层,因为该值与前一条记录相差1。
同样,如果存在以下记录:
| startTime | count |
|---|---|
| 12:00:10 | 1000 |
| 12:00:20 | 1005 |
这表明在12:00:10到12:00:20之间,设备检测到走了5步,因为两个记录之间的值相差5。
爬楼层数时间对比:Healthdb_secure.sqlite vs cache_encryptedC.sqlite
测试场景
本测试旨在找出健康数据库和cache_encryptedC数据库中记录的时间戳的准确性。
测试涉及将8部iPhone(各种型号/iOS版本)放在托盘上,两次爬升2段楼梯。顶部和底部之间的总海拔差略超过6米。在中途点有一个约3米长的平台。
第一次爬升发生在11:53:00到11:53:15之间,在平台上暂停45秒后开始第二段爬升。第二段爬升发生在11:54:00到11:54:16之间。
第二次爬升从11:55:30开始,持续25秒,在平台上没有长时间暂停。
根据Apple对"楼层"的定义(约3米海拔增益超过16级台阶),可以合理假设设备应记录4个楼层。
测试结果 - HealthDB_secure.db [样本]
| 设备 | iOS版本 | 开始时间 | 结束时间 | 爬楼层数 |
|---|---|---|---|---|
| iPhone 8 | 14.2 | 11:53:27 | 11:56:00 | 3 |
| iPhone X | 15.2.1 | 11:53:28 | 11:56:09 | 4 |
| iPhone 6s | 15.8.3 | 11:53:28 | 11:56:13 | 4 |
| iPhone X | 16.7.5 | 11:53:27 | 11:56:09 | 4 |
| iPhone X | 16.7.10 | 11:53:28 | 11:56:10 | 4 |
| iPhone SE (2) | 17.5.1 | 11:53:19 | 11:56:10 | 4 |
| iPhone Xs | 17.6.1 | 11:53:21 | 11:56:10 | 3 |
| iPhone 12 | 18.1 | 11:53:26 | 11:56:11 | 4 |
从上表可以看出,大多数设备按预期记录了4个爬楼层数。2部设备仅记录了3个楼层。
通常,记录的开始时间比实际爬升开始时间晚20到30秒,结束时间比爬升完成时间晚10到15秒。
测试结果 - cache_encryptedc.db [StepCountHistory]
| 设备 | iOS版本 | 第一楼层 | 第二楼层 | 第三楼层 | 第四楼层 |
|---|---|---|---|---|---|
| iPhone 8 | 14.2 | 11:53:30 | 11:54:46 | 11:56:00 | - |
| iPhone X | 15.2.1 | 11:54:07 | 11:54:50 | 11:55:59 | 11:56:09 |
| iPhone 6s | 15.8.3 | 11:54:06 | 11:54:47 | 11:56:00 | 11:56:13 |
| iPhone X | 16.7.5 | 11:53:30 | 11:54:49 | 11:56:00 | 11:56:10 |
| iPhone X | 16.7.10 | 11:54:06 | 11:54:51 | 11:56:00 | 11:56:10 |
| iPhone SE (2) | 17.5.1 | 11:54:05 | 11:54:46 | 11:59:59 | 11:56:10 |
| iPhone Xs | 17.6.1 | 11:53:29 | - | 11:56:00 | 11:56:10 |
| iPhone 12 | 18.1 | 11:54:07 | <11:55:37 | 11:56:00 | 11:56:11 |
cache_encryptedC.db数据允许更细致地查看数据,并实际看到每个楼层被记录为完成的时间(我说完成是因为这些时间来源于设备记录flightsClimbed字段增加的时间 - 所以虽然它没有告诉我爬升何时开始,但我知道海拔差异何时被识别)。
结论
从这些测试中得出的结论是,显示的时间戳不一定是活动发生的确切时间。可能很明显,但iOS设备对海拔增加是反应性的,需要设备检测到海拔增加才能创建记录。这被明确观察到发生在楼层爬升完成后。
Apple Health提供的时间段很好地概括了楼层爬升活动发生的时间,cache_encryptedC.db数据(如果存在)可以提供额外的精确度,尽管时间戳通常比实际爬升晚约15到35秒。
步数与距离
本测试旨在评估记录的健康事件期间步数和距离的准确性。
测试场景
访问了一个已知球门柱之间距离的橄榄球场。根据场地规格,球门线之间的距离应在94到100米之间。
使用Google Maps的"测量距离"功能测量距离,发现为91.5米。
还使用每个球门柱的GPS坐标计算距离,发现为91.41米。
测试使用了3部iPhone X设备,在测试开始前都处于"关闭"状态。
一部设备放在右裤袋中,一部放在左裤袋中,一部设备像正在查看一样手持。
在15:46:00,测试开始,设备从一条球门线走到另一条,于15:47:18到达,走了118步。此时,又走了3步以转身180度准备返回。
在15:54:00,开始往回走,于15:56:25结束,走了119步。
然后设备再次关闭。
总共行走时走了237步 + 转身3步,总共覆盖了183米。
提取设备后,检查了它们来自HealthDB_Secure和cache_encryptedC.db的数据。
设备1:iPhone X with iOS15.2.1
此设备放在右裤袋中。
HealthDB_Secure.db记录了2个样本:
| 开始时间 | 结束时间 | 步数 | 距离(米) |
|---|---|---|---|
| 15:46:04 | 15:48:39 | 218 | 119.6 |
| 15:56:05 | 15:56:21 | 21 | 13.9 |
合并后,这些记录显示总共239步,覆盖133.5米。
总步数接近预期,但覆盖距离比实际距离短约50米。
Cache_encryptedC.db记录了53条记录,可分为两个不同的组:
- 15:46:07到15:48:39 - 19条记录显示119步
- 15:55:03到15:56:23 - 32条记录显示120步
总共239步,与健康数据库提供的数据匹配。
设备2:iPhone X with iOS16.7.10
此设备放在左裤袋中。
HealthDB_Secure.db记录了2个样本:
| 开始时间 | 结束时间 | 步数 | 距离(米) |
|---|---|---|---|
| 15:46:05 | 15:56:03 | 210 | 123.4 |
| 15:56:03 | 15:56:23 | 25 | 14.9 |
合并后,这些记录显示总共235步,覆盖138.3米。
总步数非常接近实际步数,但覆盖距离仍比实际距离短约50米。
Cache_encryptedC.db记录了64条记录,可分为两个不同的组:
- 15:46:05到15:47:29 - 33条记录显示118步
- 15:55:04到15:56:23 - 32条记录显示117步
总共235步,与健康数据库提供的数据匹配。
设备3:iPhone X with iOS16.7.5
此设备手持。
HealthDB_Secure.db记录了5个样本时间:
| 开始时间 | 结束时间 | 步数 | 距离(米) |
|---|---|---|---|
| 15:46:03 | 15:56:03 | 218 | 158.4 |
| 15:56:03 | 15:56:08 | 8 | 18.2 |
| 15:56:08 | 15:56:13 | 7 | - |
| 15:56:13 | 15:56:19 | 8 | - |
| 15:56:19 | 15:56:21 | 3 | - |
合并后,这些记录显示总共244步,覆盖176.6米。
总步数略高于实际步数,但覆盖距离是所有测试设备中最接近的。
Cache_encryptedC.db记录了64条记录,可分为两个不同的组:
- 15:46:03到15:47:33 - 34条记录显示123步
- 15:55:04到15:56:23 - 32条记录显示121步
总共244步,与健康数据库提供的数据匹配。
所有来自cache_encryptedC.db数据库的结果都绘制在下图中。阴影区域表示实际发生行走活动的时间。
结论
健康数据库和cache_encryptedC.db给出的步数都非常接近实际步数。
Cache_encryptedc.db在大多数情况下还提供了高度细致的数据视图。
总体而言,所走的步数及其发生的时间段是相当准确的。
每部设备记录的行进距离通常被低估。
投掷/摇晃设备
此测试涉及在保持静止的同时摇晃和投掷手机,以查看在没有横向移动时是否会记录步数或爬楼层数活动。
测试场景
以各种方式和速度摇晃、摆动和投掷多部设备,以查看是否记录任何健康数据。
结论
发现cache_encryptedC.db在摇晃/摆动/投掷活动期间记录了步数的少量增加。这些记录最终作为步行步数聚合到主健康数据库中。从未记录过爬楼层数事件。
车辆旅行(测试1)
测试场景
2部设备进行了一次旅程,时间在16:30到19:30之间,包括几次停留。
在设备运动的所有时间,Apple Maps都保持屏幕开启,以确保持续记录位置数据。
由于Apple Health分段记录数据,设备在旅程开始前一个多小时放入车内,在旅程结束后一个多小时后取出,以避免数据污染。
第1段:16:30 - 16:45
在第1段旅程中,设备静态放置在支架中。它们受到的唯一移动是车辆运动时的自然移动和振动。
第1段包括上下坡道路,以及各种限速从30kph到80kph不等的道路。
设备1:未记录步数/距离或爬楼层数事件。 设备2:未记录步数/距离或爬楼层数事件。
第2段:17:25 - 17:56
在第2段旅程中,设备保持静态在支架中。
第2段主要是平坦道路,只有很小的海拔变化,主要是50kph的道路。
设备1:未记录步数/距离或爬楼层数事件。 设备2:未记录步数/距离或爬楼层数事件。
第3段:19:05 - 19:30
在第3段,两部设备都由车内乘客手持。它们没有被交互,但现在受到持有者手臂对车辆移动反应引起的额外移动的影响。
第3段包括上下坡道路,通常约为50kph。
设备1:记录了329步/258米和13个爬楼层数。 设备2:记录了352步/274米和14个爬楼层数。
结论
此测试证明,在车辆中旅行时由人持有的设备能够记录步数、距离和爬楼层数事件,而放置在支架中的设备似乎不受此问题影响。
车辆旅行(测试2)
测试场景
3部iPhone X设备在同一山坡上行驶3次。
根据https://en-ca.topographic-map.com,山坡海拔从1118米增加到1158米。
使用指南针应用程序中可用的高度计信息在山坡底部和顶部监测设备的海拔。
所有设备在山坡底部的高度计读数均为1120米,所有设备在山坡顶部的高度计读数均为1160米或1170米,增加了40米-50米。
根据Apple的爬楼层数定义(每层3米),40米约等于13.3层。
设备详情
- 手机1 - iPhone X with iOS 16.7.5
- 手机2 - iPhone X with iOS 15.2.1
- 手机3 - iPhone X with iOS 16.7.10
第一次,手机1以与测试1中相同的松散方式手持,而手机2和手机3放在座位上。
第二次上山旅程,手机2手持,而手机1和手机3放在座位上。
最后一次旅程,手机3手持,而手机1和手机2放在座位上。
速度保持在平均45到50 kph(28-31mph),所有3部手机都有数据连接,并专注于Apple Maps以确保持续的位置数据。
手机1 - iPhone X with iOS 16.7.5
手机1的测试旅程发生在11:41:55和11:44:00之间。
在healthdb_secure.sqlite中记录了一个健康事件,时间在18:41:53和18:43:02之间,包括54步超过41米距离,但在此时间或整个3次旅程测试期间,在Healthdb_secure或cache_encryptedc.db中均未记录爬楼层数事件。
手机2 - iPhone X with iOS 15.2.1
手机2的测试旅程发生在11:46:22和11:48:26之间。
在healthdb_secure中记录了两个健康事件。第一个事件在11:46:33和11:48:22之间,包括180步超过147米。第二个事件是爬楼层数事件,发生在11:47:08和11:48:30之间,包括13个爬楼层数事件。
在此旅程之外未记录额外的楼层。
| 时间戳 | 计数变化 | 总楼层数 |
|---|---|---|
| 11:47:11 | 24 > 28 | 4 |
| 11:47:26 | 28 > 29 | 5 |
| 11:47:36 | 29 > 30 | 6 |
| 11:47:41 | 30 > 31 | 7 |
| 11:47:47 | 31 > 32 | 8 |
| 11:47:57 | 32 > 33 | 9 |
| 11:47:59 | 33 > 34 | 10 |
| 11:48:10 | 34 > 35 | 11 |
| 11:48:17 | 35 > 36 | 12 |
| 11:48:30 | 36 > 37 | 13 |
手机3 - iPhone X with iOS 16.7.10
手机3的测试旅程发生在11:50:55和11:52:56之间。
在healthdb_secure中记录了两个健康事件。第一个事件在11:50:57和12:00:49之间,包括256步超过208米。第二个事件是爬楼层数事件,发生在11:51:09和11:52:56之间,包括13个爬楼层数事件。
在此旅程之外未记录额外的楼层。
| 时间戳 | 计数变化 | 总楼层数 |
|---|---|---|
| 11:51:12 | 68 > 69 | 1 |
| 11:51:27 | 69 > 70 | 2 |
| 11:51:35 | 70 > 71 | 3 |
| 11:51:42 | 71 > 72 | 4 |
| 11:51:58 | 72 > 73 | 5 |
| 11:52:11 | 73 > 74 | 6 |
| 11:52:13 | 74 > 75 | 7 |
| 11:52:15 | 75 > 76 | 8 |
| 11:52:21 | 76 > 77 | 9 |
| 11:52:28 | 77 > 78 | 10 |
| 11:52:43 | 78 > 79 | 11 |
| 11:52:49 | 79 > 80 | 12 |
| 11:52:56 | 80 > 81 | 13 |
此图显示了来自每个设备的爬楼层数事件信息。
总结
上述测试证明了几个重要事项:
- Cache_EncryptedC.db可能能够提供比HealthDB_secure.db更细致的粒度
- 记录的步数在行走时是步数的相当可靠的指标
- 距离不如步数可靠
- 如果设备被手持,在车辆中可能记录步数和爬楼层数
总体而言,健康应用程序是取证数据的很好来源,但与大多数来源一样,需要理解其中的细微差别。