27、传感器数据存储与分析:本地数据库存储、CSV导出、数据可视化图表、机器学习预处理
传感器数据采集回来,只是第一步。真正头疼的,是怎么把这些原始数据变成有价值的东西。
我早期做的一个计步器项目,数据全存在内存里,用户一退出应用就丢了。被用户骂惨了。后来我学乖了——数据必须落地,而且要方便分析。
这一章,我们就来聊聊传感器数据的存储与分析。说白了,就是四个环节:存起来、导出去、画成图、喂给AI。
27.1 本地数据库存储:Room 实战
Android 官方推荐的本地数据库方案,就是 Room。它是对 SQLite 的一层封装,用起来比原生 API 舒服太多。
先定义一个传感器数据实体:
@Entity(tableName = "sensor_data")
public class SensorRecord {
@PrimaryKey(autoGenerate = true)
public long id;
public int sensorType; // 传感器类型,如 ACCELEROMETER
public float x, y, z; // 三轴数据
public long timestamp; // 采集时间戳(纳秒)
public long sessionId; // 会话ID,用于区分不同采集批次
}
然后定义 DAO 接口:
@Dao
public interface SensorDao {
@Insert
void insert(SensorRecord record);
@Query("SELECT * FROM sensor_data WHERE sessionId = :sessionId ORDER BY timestamp ASC")
List<SensorRecord> getRecordsBySession(long sessionId);
@Query("DELETE FROM sensor_data WHERE timestamp < :cutoff")
void deleteOldData(long cutoff);
}
最后是 Database 类:
@Database(entities = {SensorRecord.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract SensorDao sensorDao();
}
初始化时,我建议用单例模式:
AppDatabase db = Room.databaseBuilder(
getApplicationContext(),
AppDatabase.class,
"sensor_db"
).build();
27.2 CSV 导出:让数据走出手机
数据库里的数据,怎么给数据分析师看?CSV 是最通用的格式。Excel、Python、R 都能直接打开。
导出逻辑其实不复杂:
public File exportToCsv(List<SensorRecord> records, File file) throws IOException {
FileWriter writer = new FileWriter(file);
writer.write("timestamp,x,y,z\n");
for (SensorRecord r : records) {
writer.write(r.timestamp + "," + r.x + "," + r.y + "," + r.z + "\n");
}
writer.close();
return file;
}
导出后,我一般用 MediaStore 把文件存到 Downloads 目录,方便用户通过文件管理器找到。
27.3 数据可视化图表:用 MPAndroidChart 画出来
光看数字,很难发现规律。画成折线图,一眼就能看出趋势。
我常用的是 MPAndroidChart 库。画一个加速度计的三轴折线图,大概这样:
LineChart chart = findViewById(R.id.chart);
List<Entry> entriesX = new ArrayList<>();
List<Entry> entriesY = new ArrayList<>();
List<Entry> entriesZ = new ArrayList<>();
for (int i = 0; i < records.size(); i++) {
SensorRecord r = records.get(i);
entriesX.add(new Entry(i, r.x));
entriesY.add(new Entry(i, r.y));
entriesZ.add(new Entry(i, r.z));
}
LineDataSet setX = new LineDataSet(entriesX, "X轴");
setX.setColor(Color.RED);
LineDataSet setY = new LineDataSet(entriesY, "Y轴");
setY.setColor(Color.GREEN);
LineDataSet setZ = new LineDataSet(entriesZ, "Z轴");
setZ.setColor(Color.BLUE);
LineData lineData = new LineData(setX, setY, setZ);
chart.setData(lineData);
chart.invalidate();
嗯,这里要注意:如果数据点太多(比如超过 1000 个),图表会变得密密麻麻,根本看不清。我一般会做降采样——每 10 个点取一个平均值,或者只显示最近 200 个点。
27.4 机器学习预处理:把传感器数据喂给模型
传感器数据要喂给机器学习模型,不能直接扔进去。得先做预处理。
常见的预处理步骤包括:
- 去噪:用低通滤波器去掉高频噪声。我常用的是滑动平均滤波。
- 归一化:把数据缩放到 [0, 1] 或 [-1, 1] 区间。避免不同量纲影响模型。
- 滑动窗口:把连续数据切成固定长度的窗口。比如每 50 个采样点作为一个样本。
- 特征提取:从窗口里提取均值、方差、峰值、过零率等特征。
举个例子,滑动窗口切分:
public List<float[]> createWindows(float[] rawData, int windowSize, int step) {
List<float[]> windows = new ArrayList<>();
for (int i = 0; i + windowSize <= rawData.length; i += step) {
float[] window = Arrays.copyOfRange(rawData, i, i + windowSize);
windows.add(window);
}
return windows;
}
归一化我习惯用 Z-score 标准化:
public float[] normalize(float[] data) {
float mean = 0, std = 0;
for (float v : data) mean += v;
mean /= data.length;
for (float v : data) std += (v - mean) * (v - mean);
std = (float) Math.sqrt(std / data.length);
for (int i = 0; i < data.length; i++) {
data[i] = (data[i] - mean) / std;
}
return data;
}
27.5 知识体系总览
下面这张图,把传感器数据从采集到分析的完整链路画出来了。你可以对照着看,心里有个全局观。
你看,整个链路其实很清晰。从采集到存储,再到导出、可视化、预处理,每一步都有它的价值。我个人建议,在项目初期就把这套流程搭好,后面迭代会轻松很多。
好了,这一章的内容就到这里。传感器数据的存储与分析,说白了就是让数据流动起来,从手机里走到分析工具里,最后变成模型能理解的形式。每一步都不难,但每一步都值得认真对待。
公众号:蓝海资料掘金营,微信deep3321