Android 手机传感器 CSV 采集:时间戳、采样率、坐标系、存储与真机验收
从运行时硬件检查、SensorEvent 单调时间戳、设备坐标系、实际采样间隔到应用私有存储与系统导出,建立 Android 手机传感器 CSV 的可验收采集流程。
最后更新:2026 年 8 月。本文根据 Android 官方传感器与存储文档整理。不同手机的传感器型号、量程、分辨率、功耗、厂商滤波和实际调度都会不同,任何实验都必须在目标设备上重新验收。
先定义你真正需要的数据
不要从“把所有传感器都保存下来”开始。先写清任务:是观察静置噪声、识别动作、估计姿态,还是给后续 Matlab/Python 分析准备数据?不同任务需要的传感器、时长、采样间隔和标注完全不同。手机原始或系统融合传感器值也不能自动证明精确位移、导航轨迹或医疗指标。
每次会话至少记录设备型号、Android 版本、应用版本、传感器名称与类型、量程、分辨率、请求档位、会话 UTC 开始时间、单调时间戳和实验动作说明。没有这些上下文,同一列数值很难跨设备复现。
第一步:运行时检查硬件,不能假设每台手机都有
Android 官方Sensors Overview明确要求在运行时判断设备是否提供某个传感器。使用 getDefaultSensor() 或传感器列表获取实际能力;缺失时应禁用对应选项并给出说明,而不是让应用崩溃。
还要区分硬件传感器与系统融合传感器。加速度计、陀螺仪和磁力计常用于三轴原始测量;旋转矢量、重力和线性加速度可能经过系统融合。融合结果便于使用,但不能冒充某个单独硬件的原始读数。
第二步:理解坐标系、单位和值数量
传感器事件值通常基于设备坐标系,而不是世界坐标系。屏幕旋转也不意味着底层传感器坐标自动变成当前界面方向。实验前可做“静置—单轴正向—单轴反向—回到静置”动作,记录每个轴的符号和响应,再决定是否需要坐标变换。
不同类型的单位不同:加速度常用 m/s²,角速度常用 rad/s,磁场常用 μT,光照常用 lx,气压常用 hPa。不要把所有事件固定解释为三个值;例如旋转矢量可能提供额外分量,单值传感器也只需一个有效数值。CSV 可以预留固定列,但必须保留 sensor_type、sensor_name 和空值规则。
第三步:SensorEvent.timestamp 不是墙上时钟
SensorEvent 官方参考将 timestamp 定义为事件发生时的纳秒时间戳,并说明它使用与 SystemClock.elapsedRealtimeNanos() 相同的时间基准。它适合计算相邻样本间隔和会话相对时间,不应直接格式化为现实日期。
稳妥的数据合同可以同时保存:会话开始时的 UTC 文本、每行 timestamp_ns、以及相对第一条事件计算的 elapsed_seconds。这样既能定位会话,又不会把单调时钟冒充日历时间。
第四步:采样档位是请求,不是固定 Hz 合同
SENSOR_DELAY_NORMAL、UI 和 GAME 是系统请求档位。实际返回间隔仍受传感器、系统调度、功耗策略和设备实现影响。不要在商品或实验报告中宣称 GAME 一定等于 50 Hz。
验收时用连续时间戳差值计算实际间隔,报告样本数、总时长、平均频率、间隔 P50/P95、最大间隔和非递增时间戳数量。长时间采集还应分段检查掉样、发热、耗电与文件关闭是否正常。
遇到异常间隔时怎样定位
先不要用插值把问题藏起来。把异常按会话开始、屏幕交互、切换应用、设备发热和文件写入阶段分组;同时记录当时是否发生 UI 更新、垃圾回收或存储错误。若只有界面刷新时出现长间隔,应先降低 UI 更新频率;若长会话后逐渐恶化,应检查发热、系统功耗限制和文件写入策略。
对动作识别等任务,还要区分“缺少样本”和“动作本来不均匀”。保留原始时间戳,在模型前单独执行重采样或窗口化,并把重采样参数写入实验配置。不要在采集阶段悄悄生成等间隔时间轴。
第五步:回调中少做工作,离开前台就停止
传感器回调频率可能很高。避免在主线程进行大量格式化、磁盘写入或复杂推理。可将监听回调放到独立 HandlerThread,UI 仅限频展示;写入失败时应停止监听、关闭文件并明确告知用户。
普通教学型前台采集应用应在 Activity 进入后台时注销监听并关闭会话,避免用户不知情的持续采集、耗电和隐私风险。如果业务确实需要后台或前台服务采集,则必须单独设计生命周期、持续通知、权限、功耗和平台政策,不能沿用简单示例的结论。
第六步:先写应用私有目录,再让用户主动导出
Android 官方应用专属存储文档说明,内部应用专属文件无需系统存储权限,卸载应用时会被删除。适合先安全保存当前会话,但需要长期保留时必须在卸载前导出。
使用Storage Access Framework的 ACTION_CREATE_DOCUMENT,可以让用户通过系统文件选择器决定导出位置,无需申请广泛存储权限。应用应检查输出流是否可写,并在导出完成或失败时给出明确结果。
建议的九列 CSV 数据合同
timestamp_ns:事件单调纳秒时间戳;elapsed_seconds:相对会话第一条事件的秒数;sensor_type与sensor_name:避免跨设备误认;accuracy:系统提供的精度状态;value_0至value_3:按传感器类型解释,缺失项留空。
文本字段必须正确做 CSV 引号转义;NaN 和无穷值应有稳定规则。导出后重新读取文件,检查每行列数、时间戳单调性、数值可解析性、总行数和会话时长。
导出后做一次闭环验收
将导出的文件复制到电脑,用独立脚本重新读取,而不是只在手机界面上看“导出成功”。统计有效数据行、空行、错误列数、非数值字段、首末时间戳、会话持续时间和各 sensor_type 数量。再把这些统计与手机端显示的样本数比较;两者不一致时,先检查关闭文件、缓冲区刷新和导出时机。
建议保留一个十几行的合成样例做格式回归,但它只能证明解析器和字段约定,不能替代真机噪声、掉样、坐标轴与功耗验证。每次修改 CSV 结构后,应同时更新表头测试、解析脚本和公开字段说明。
购买前的免费验证路径
- 用免费规划器按传感器、请求档位和时长估算行数与文件容量;
- 下载合成 CSV,只核对字段、转义和空值约定;
- 查看 11 项代码与隐私静态验收结果;
- 如果你能自己实现以上流程,不需要购买;只有需要完整 Java 工程、已构建调试 APK、单测与可重跑验收脚本时再核对原创包。
公开样例是虚构合成数据,不是真机测量。调试 APK 仅用于教学自测,不是应用商店发行包,也不适合医疗、导航、安全关键或需要认证的任务。
真机最小验收清单
- 启动前展示设备实际存在的传感器,不存在时可安全降级;
- 静置和单轴动作能解释坐标轴、单位和符号;
- 时间戳严格递增,相对秒数与实际会话时长相符;
- 报告实际间隔分布,不把请求档位写成保证频率;
- 切到后台后立即停止,文件可重新打开且列数一致;
- 导出由用户主动选择位置;卸载前确认需要的数据已经导出;
- 在目标设备上完成至少一次短会话和一次预期最长会话。
Android 传感器 CSV 常见问题
SENSOR_DELAY_GAME 是否保证 50 Hz?
不保证。它是向系统提出的采样延迟档位,实际间隔取决于硬件、厂商实现、系统调度和功耗策略,应通过 SensorEvent 时间戳统计实际 P50/P95 间隔。
SensorEvent.timestamp 能直接转换成日期时间吗?
不应直接转换。它使用单调时钟基准,适合计算样本间隔和会话相对时间;现实日期可在会话开始时另存 UTC 时间。
屏幕旋转后传感器 x、y 轴会自动跟着界面旋转吗?
不能这样假设。传感器值以设备坐标系为基础;需要界面方向或世界坐标时,应明确做坐标变换,并通过单轴动作在目标设备上验收。
导出 CSV 是否需要存储权限?
示例先写应用内部专属目录,再通过 Storage Access Framework 的系统文件选择器让用户选择位置,不申请广泛存储权限。
合成样例和调试 APK 能否证明我的手机可用?
不能。样例只验证字段,调试 APK 只供教学自测。传感器存在性、频率、坐标、掉样、能耗和最长会话都必须在目标真机上重新验收。