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
相关产品推荐
相关产品推荐

