You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python读取Android传感器二进制.dat文件实现EDA数据处理

Python+pandas解析Android传感器二进制.dat文件实现

你之前用pd.read_table读取二进制文件得到乱码是正常的,该方法仅适配分隔符文本格式,处理定长二进制数据包需要先按字节规则拆包再转换为DataFrame结构。以下实现完全匹配你给出的MATLAB解析逻辑,可直接用于后续数据清洗和EDA流程。

解析规则匹配

严格对应大端序二进制包结构:

  • 三轴类传感器(accelerometer、gravity、gyroscope、magnetic_field):单包总长20字节,格式为int64时间戳 + 3个single类型XYZ轴值
  • 单值类传感器(light、pressure、proximity):单包总长12字节,格式为int64时间戳 + 1个single类型测量值
  • 步测器(step_detector):单包总长8字节,仅包含int64时间戳

核心解析代码

依赖标准库struct做二进制拆包,配合pandas做结构化处理,无需额外第三方工具:

import os
import struct
import pandas as pd
import numpy as np

def parse_android_sensor_dat(file_path: str, sensor_type: str, file_start_timestamp_ms: int) -> pd.DataFrame:
    # 传感器解析配置:struct格式串、单包字节长度、输出列名
    # 格式串前缀>代表大端序,q对应8字节int64,f对应4字节single浮点数
    sensor_config = {
        "accelerometer": (">q3f", 20, ["timestamp_raw", "x", "y", "z"]),
        "gravity": (">q3f", 20, ["timestamp_raw", "x", "y", "z"]),
        "gyroscope": (">q3f", 20, ["timestamp_raw", "x", "y", "z"]),
        "magnetic_field": (">q3f", 20, ["timestamp_raw", "x", "y", "z"]),
        "light": (">qf", 12, ["timestamp_raw", "value"]),
        "pressure": (">qf", 12, ["timestamp_raw", "value"]),
        "proximity": (">qf", 12, ["timestamp_raw", "value"]),
        "step_detector": (">q", 8, ["timestamp_raw"])
    }
    if sensor_type not in sensor_config:
        raise ValueError(f"不支持的传感器类型: {sensor_type}")
    
    fmt, packet_len, columns = sensor_config[sensor_type]
    # 二进制只读模式加载全文件内容
    with open(file_path, "rb") as f:
        file_bytes = f.read()
    
    # 自动截断采集异常导致的末尾不完整包
    tail_pad = len(file_bytes) % packet_len
    if tail_pad != 0:
        print(f"警告:文件{os.path.basename(file_path)}存在{tail_pad}字节不完整末尾,已自动截断")
        file_bytes = file_bytes[:len(file_bytes) - tail_pad]
    
    # 批量拆包转换为DataFrame
    parsed_records = [
        struct.unpack(fmt, file_bytes[i:i+packet_len]) 
        for i in range(0, len(file_bytes), packet_len)
    ]
    df = pd.DataFrame(parsed_records, columns=columns)

    # 时间校准:Android传感器原始时间戳为设备开机纳秒数,结合文件名起始时间转Unix时间
    raw_start_offset = df["timestamp_raw"].iloc[0]
    file_start_ns = file_start_timestamp_ms * 1_000_000
    df["timestamp_unix_ns"] = file_start_ns + (df["timestamp_raw"] - raw_start_offset)
    # 转换为pandas可直接处理的时间格式
    df["datetime"] = pd.to_datetime(df["timestamp_unix_ns"], unit="ns")
    # 按时间排序、去重完成基础清洗
    df = df.sort_values("timestamp_unix_ns").drop_duplicates(subset=["timestamp_unix_ns"]).reset_index(drop=True)
    return df

批量读取用法

如果你的文件是按「根目录/传感器类型子文件夹/xxx_起始时间戳.dat」结构存储,可直接用以下代码批量加载所有数据:

# 替换为你的数据根目录路径
data_root = "./android_sensor_data"
sensor_data_dict = {}

for sensor_type in os.listdir(data_root):
    sensor_folder = os.path.join(data_root, sensor_type)
    if not os.path.isdir(sensor_folder):
        continue
    single_sensor_dfs = []
    for file_name in os.listdir(sensor_folder):
        if not file_name.endswith(".dat"):
            continue
        # 按你的文件名规则提取13位毫秒级起始Unix时间戳,示例为文件名最后一段为时间戳的格式
        start_ts_ms = int(file_name.split("_")[-1].replace(".dat", ""))
        file_path = os.path.join(sensor_folder, file_name)
        single_df = parse_android_sensor_dat(file_path, sensor_type, start_ts_ms)
        single_sensor_dfs.append(single_df)
    if single_sensor_dfs:
        sensor_data_dict[sensor_type] = pd.concat(single_sensor_dfs, ignore_index=True)

# 后续EDA可直接按传感器类型取DataFrame,例如取加速度计数据
acc_data = sensor_data_dict["accelerometer"]

Windows端十六进制排查方法

不需要安装第三方工具,直接用系统自带PowerShell即可实现和Mac端od -x等效的十六进制查看效果:

进入.dat文件所在文件夹,按住Shift右键空白处选择「在此处打开PowerShell窗口」,执行命令Format-Hex 目标文件名.dat即可查看文件十六进制内容,用于校验解析逻辑是否正确。

常见问题排查

  • 解析出的数值量级明显异常:先检查大小端配置,若大端序>解析结果不对,可将格式串前缀改为小端序<测试;再确认传感器类型和子文件夹是否对应,避免用错解析规则。
  • 时间偏移错误:确认从文件名提取的起始时间戳为13位毫秒级Unix时间,不要传入10位秒级时间戳。
  • 三轴传感器某一轴数值为空:检查采集配置是否开启了对应轴的数据输出。

内容的提问来源于stack exchange,提问作者Charles SAS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:39:18