传感器文件格式说明
基本文件格式如下:
Zhongpu Labenius [MAJOR] [MINOR] [SENSOR_TYPE] [DATA_UNIT]
TimeStamp(long: 64bit) [Value]*[ITEM_NUM]
TimeStamp(long: 64bit) [Value]*[ITEM_NUM]
...
TimeStamp(long: 64bit) [Value]*[ITEM_NUM]
其中:
- MAJOR: 主版本号,当前只有A
- MINOR:次版本号,当前有1或2,其区别请参考“注意”
- SENSOR_TYPE:传感器类型
- DATA_UNIT:单位
- TimeStamp:时间戳
- VALUE: 数值
- ITEM_NUM:一组数据包含的数值个数
当传感器类型不同时,各项内容不同:
Sensor | SENSOR_TYPE | TimeStamp单位 | DATA_UNIT | ITEM_NUM | Value类型 | 数据含义 |
---|---|---|---|---|---|---|
加速度 | acceleration | ns | m/s^2 | 3 | float 32bit | X,Y,Z方向的加速度 |
重力 | gravity | ns | m/s^2 | 3 | float 32bit | X,Y,Z方向的重力分量 |
陀螺仪 | gyroscope | ns | rad/s | 3 | float 32bit | X,Y,Z轴的旋转角速度 |
线型加速度 | linear_acceleration | ns | m/s^2 | 3 | float 32bit | X,Y,Z方向的加速度减去重力分量 |
压力 | pressure | ns | hPa | 1 | float 32bit | |
温度 | ambient_temperature | ns | °C | 1 | float 32bit | |
相对湿度 | relative_humidity | ns | % | 1 | float 32bit | |
位置 | ms UTCTime | deg_deg_m | 3 | double 64bit | 纬度、经度和海拔 | |
速度 | speed | ms UTCTime | m/s | 1 | float 32bit | 注意:A2版本后加入,A1版本错误的写成了TLocation |
注意:
A1版本文件,当传感器类型为TLocation时,'zhongpu'前面可能有‘00 1F’,且没有单位信息。
文件头的字符串后面以'\n'结尾,后面立即开始存储二进制数据
注意数据的大小端问题,AndroidSDK指定为大端,但仍可能与您使用的android设备有关。
示例程序
- Python
# -*- coding: utf-8 -*-
"""
Hangzhou Zhonpu Inc.
Record file read example code for Vibration Calculator A1&A2 format
Date: 2021-11-24
Author: zgy
"""
import struct
import matplotlib.pyplot as plt
import numpy as np
def read_word(fd):
word = []
ch = fd.read(1)
while ch != b' ' and ch != b'\n':
word.append(struct.unpack('B', ch)[0])
ch = fd.read(1)
return bytes(word).decode()
def sensor_data_num(sensor_type):
if sensor_type == 'TLocation' or sensor_type == 'acceleration' or sensor_type == 'gravity' or sensor_type == 'gyroscope' or sensor_type == 'linear_acceleration':
return 3
return 1
def read_recfile(filename):
f = open(filename, 'rb')
zhongpu = read_word(f)
labgenius = read_word(f)
major = read_word(f)
minor = read_word(f)
sensor_type = read_word(f)
unit = ''
if sensor_type != 'TLocation':
unit = read_word(f)
elif zhongpu == 'Zhongpu':
#must be A2
unit = read_word(f)
else:
# TLocation have no zero after string but with 2 bytes for string length at the beginning in Version A1
zhongpu = zhongpu[2:]
print(zhongpu, labgenius, major, minor, sensor_type, unit)
if zhongpu != 'Zhongpu' or labgenius != 'Labenius':
raise Exception("File is not created by Zhongpu LabGenius")
# Notice: data endian may be different from devices and data types
# On my device, int64 and double is big endian, but float is little endian.
num = sensor_data_num(sensor_type)
timestamps = []
values=[]
dendian = '>'
dtype = 'f'
dsize = 4
if sensor_type == 'TLocation':
dendian='>'
dtype = 'd'
dsize = 8
try:
while True:
tb = f.read(8);
t = struct.unpack('>Q', tb)[0]
tds = f.read(dsize * num)
d = struct.unpack(dendian + dtype*num, tds)
timestamps.append(t)
values.append(d)
except:
pass
return sensor_type, unit, np.array(timestamps), np.array(values)
if __name__ == '__main__':
filename = r"I:/lgsc/2021-11-24 10_02_04/linear_acceleration"
sensor_type, unit, t, v= read_recfile(filename)
plt.figure()
t = (t - t[0])/1E9
plt.plot(t, v[:,0],t, v[:,1],t, v[:,2])
plt.title("linear acceleration")
filename = r"I:/lgsc/2021-11-24 10_02_04/gyroscope"
sensor_type, unit, t, v= read_recfile(filename)
plt.figure()
t = (t - t[0])/1E9
plt.plot(t, v[:,0], t, v[:,1], t, v[:,2])
plt.title("gyroscope")
filename = r"I:/lgsc/2021-11-24 10_02_04/acceleration"
sensor_type, unit, t, v= read_recfile(filename)
plt.figure()
t = (t - t[0])/1E9
plt.plot(t, v[:,0], t, v[:,1], t, v[:,2])
plt.title("acceleration")
filename = r"I:/lgsc/2021-11-24 10_02_04/gravity"
sensor_type, unit, t, v= read_recfile(filename)
plt.figure()
t = (t - t[0])/1E9
plt.plot(t, v[:,0], t, v[:,1], t, v[:,2])
plt.title("gravity")
filename = r"I:/lgsc/2021-11-24 10_57_59/speed"
sensor_type, unit, t, v= read_recfile(filename)
t = (t - t[0])/1E3
plt.figure()
plt.plot(t, v[:,0])
plt.title("speed")
filename = r"I:/lgsc/2021-11-24 10_02_04/location"
sensor_type, unit, t, v= read_recfile(filename)
t = (t - t[0])/1E3
print(v)
- C++
/*
Hangzhou Zhonpu Inc.
Record file read example code for Vibration Calculator A1&A2 format
Date: 2021-11-24
Author: zgy
*/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
struct Value {
double value[3];
};
bool read_word(FILE* f, char* buffer, int buflen, std::string& holder) {
char ch;
int idx = 0;
int ret = fread(&ch, 1, 1, f);
while (ret) {
if (ch != ' ' && ch != '\n' && ch != 0) {
if (idx < buflen - 1)
buffer[idx++] = ch;
else
return false;
}
else{
break;
}
ret = fread(&ch, 1, 1, f);
}
buffer[idx] = 0;
if (idx) {
holder = buffer;
}
return idx > 0;
}
struct DataInfo {
int byteSize;
int itemCount;
double tick;
};
DataInfo GetDataInfo(const char* sensor) {
if (strcmp(sensor, "acceleration") == 0 ||
strcmp(sensor, "gravity") == 0 ||
strcmp(sensor, "gyroscope") == 0 ||
strcmp(sensor, "linear_acceleration") == 0 ) {
return { 4, 3, 1E9};
}
else if (strcmp(sensor, "TLocation") == 0) {
return { 8, 3, 1E3 };
}
else if (strcmp(sensor, "speed") == 0) {
return { 4, 1, 1E3 };
}
else {
return { 4, 1, 1E9 };
}
}
void BigEndianToLittleEndian(char* buffer, int len) {
char ch = 0;
for (int i = 0; i < len / 2; ++i) {
ch = buffer[i];
buffer[i] = buffer[len - i - 1];
buffer[len - i - 1] = ch;
}
}
unsigned _int64 BytesToTick(char* buffer, int len) {
//big-little
BigEndianToLittleEndian(buffer, len);
return *(unsigned _int64*)buffer;
}
double BytesToValue(char* buffer, int len) {
BigEndianToLittleEndian(buffer, len);
if (len == 4) {
return *(float*)buffer;
}
else if (len == 8) {
return *(double*)buffer;
}
return 0.0;
}
int read_file(const char* filename, std::vector<double>& times, std::vector<Value>& values) {
int ret = 0;
FILE* file = fopen(filename, "rb");
if (file) {
const int BUFFER_LEN = 1024;
char buffer[BUFFER_LEN];
std::string zp, lg, major, minor, sensor, unit;
if (read_word(file, buffer, BUFFER_LEN, zp) &&
read_word(file, buffer, BUFFER_LEN, lg) &&
read_word(file, buffer, BUFFER_LEN, major) &&
read_word(file, buffer, BUFFER_LEN, minor) &&
read_word(file, buffer, BUFFER_LEN, sensor)) {
bool success = true;
if (lg != "Labenius" || major != "A" || (minor!="1" && minor!="2")) {
//header error
success = false;
}
else if (minor == "1" && sensor == "TLocation") {
//For A1 TLocation
if (zp != "\x00\x1FZhongpu") {
//header error
success = false;
}
}
else if(!(zp == "Zhongpu" && read_word(file, buffer, BUFFER_LEN, unit))) {
//header error
success = false;
}
if (success) {
DataInfo dataInfo = GetDataInfo(sensor.c_str());
unsigned _int64 startTick = 0;
unsigned _int64 curTick = 0;
double time = 0;
bool bFirst = true;
while (true)
{
int rv = fread(buffer, 8, 1, file);
if (rv == 1) {
curTick = BytesToTick(buffer, 8);
if (bFirst) {
startTick = curTick;
bFirst = false;
}
time = (curTick - startTick) / dataInfo.tick;
Value val;
int i = 0;
for (i = 0; i < dataInfo.itemCount; ++i) {
rv = fread(buffer, dataInfo.byteSize, 1, file);
if (rv == 1) {
val.value[i] = BytesToValue(buffer, dataInfo.byteSize);
}
else {
break;
}
}
if (i == dataInfo.itemCount) {
times.push_back(time);
values.push_back(val);
}
else {
break;
}
}
else {
break;
}
}
if (!values.empty()) {
ret = dataInfo.itemCount;
}
}
}
fclose(file);
}
return ret;
}
int main()
{
std::vector<double> time;
std::vector<Value> values;
int items = read_file("I:/lgsc/2021-11-24 10_02_04/linear_acceleration", time, values);
time.clear();
values.clear();
items = read_file("I:/lgsc/2021-11-24 10_02_04/location", time, values);
time.clear();
values.clear();
items = read_file("I:/lgsc/2021-11-24 10_02_04/speed", time, values);
time.clear();
values.clear();
items = read_file("I:/lgsc/2021-11-24 10_02_04/gyroscope", time, values);
return 0;
}