实验数据采集:数据采集系统搭建、采样频率与精度选择、工况循环设计、数据预处理

大家好,我是你们的BMS算法讲师。今天咱们聊聊实验数据采集这块。

说实话,很多做SOC算法的同行,把精力全扑在算法模型上,却忽略了数据采集这个基础环节。我见过太多人,模型调得天花乱坠,一上实车数据就崩盘。为什么?因为数据本身就有问题。你想想看,垃圾进,垃圾出,再牛的算法也白搭。

数据采集系统搭建

先说说硬件层面的东西。我个人习惯把采集系统分成三层:传感器层、信号调理层、数据记录层。

  • 传感器层:电流传感器(霍尔或分流器)、电压采样芯片、温度传感器(NTC或PT1000)。
  • 信号调理层:滤波电路、隔离放大器、ADC转换模块。
  • 数据记录层:工控机或嵌入式板卡,配合CAN总线或以太网传输。

我在项目中遇到过一个问题:某次用霍尔传感器测电流,低频噪声特别大。后来发现是供电电源纹波没处理好。嗯,这里要注意,传感器的供电质量直接影响数据精度,别省那点钱。

我的小技巧:搭建系统时,先做一次“空跑测试”——不上电池,只采集噪声基线。这样能提前发现硬件问题。

采样频率与精度选择

采样频率怎么选?说白了,得看你的工况变化有多快。

对于UDC工况,电流变化相对平缓,1Hz采样就够了。但NEDC工况里有些急加速段,电流变化率可能超过100A/s。这时候,我建议采样频率至少10Hz,最好20Hz以上。

精度方面,我踩过坑。曾经用12位ADC采集电流,分辨率只有0.1A左右。结果做SOC估算时,静置阶段的微小电流根本测不准,导致自放电估算偏差很大。后来换成16位ADC,分辨率到了0.01A,问题才解决。

工况类型 推荐采样频率 推荐ADC位数 典型电流变化率
UDDS 1-5 Hz 12-14 bit ~20 A/s
NEDC 10-20 Hz 14-16 bit ~100 A/s
自定义急加速工况 50-100 Hz 16 bit ~300 A/s
注意:采样频率不是越高越好。频率太高,数据量爆炸,存储和处理的压力都大。而且高频噪声也会被引入。我一般遵循“奈奎斯特频率的5-10倍”这个经验法则。

工况循环设计

工况循环,说白了就是让电池“跑”起来的一套速度-时间曲线。标准的有UDDS和NEDC,但实际项目中,我更推荐自定义工况。

为什么?因为标准工况是给整车测试用的,对电池SOC估算来说,有些关键特征没覆盖到。比如:

  • 长时间静置(模拟停车自放电)
  • 小电流充放电(模拟BMS待机功耗)
  • 脉冲充放电(模拟能量回收)

我记得有一次,客户反馈SOC在低电量时跳变严重。我一看他们的测试数据,全是NEDC工况,根本没有低SOC下的静置段。后来我设计了一个自定义工况,在SOC 10%以下加入了30分钟的静置和微电流放电,果然复现了问题。

自定义工况设计要点
  1. 覆盖SOC全范围(0%-100%)
  2. 包含静置段(至少30分钟)
  3. 加入脉冲电流(模拟真实驾驶中的急加速/急减速)
  4. 温度变化(从-20°C到55°C,每10°C一个测试点)

数据预处理

数据采集完了,别急着用。原始数据里全是坑。我总结了三步预处理流程:滤波、去噪、异常值处理。

滤波

滤波的目的是去掉高频噪声。我常用的是滑动平均滤波和低通滤波。

# 滑动平均滤波示例
import numpy as np

def moving_average(data, window_size=5):
    return np.convolve(data, np.ones(window_size)/window_size, mode='same')

# 低通滤波(一阶RC)
def low_pass_filter(data, alpha=0.1):
    filtered = [data[0]]
    for i in range(1, len(data)):
        filtered.append(alpha * data[i] + (1-alpha) * filtered[-1])
    return filtered

我个人习惯先用滑动平均粗滤,再用低通精调。alpha值一般取0.05到0.2之间,具体看噪声水平。

去噪

去噪和滤波不太一样。滤波是平滑,去噪是剔除明显错误的数据点。比如:

  • 电流值突然跳变超过100A(传感器故障)
  • 电压值低于0V或高于4.5V(单节电芯)
  • 温度值超过-40°C到85°C范围

我曾经遇到过一批数据,电流在某个时间段全是0。查了半天,发现是CAN总线丢帧了。这种数据如果不剔除,SOC估算会直接飘走。

异常值处理

异常值处理,我推荐用3σ原则或IQR方法。

# 3σ原则剔除异常值
def remove_outliers_3sigma(data):
    mean = np.mean(data)
    std = np.std(data)
    return [x for x in data if abs(x - mean) <= 3 * std]

# IQR方法
def remove_outliers_iqr(data):
    q1 = np.percentile(data, 25)
    q3 = np.percentile(data, 75)
    iqr = q3 - q1
    lower_bound = q1 - 1.5 * iqr
    upper_bound = q3 + 1.5 * iqr
    return [x for x in data if lower_bound <= x <= upper_bound]
避坑指南:我曾经用3σ原则处理电流数据,结果把正常的急加速峰值给剔除了。后来发现,电流数据本身不是正态分布,用3σ不合适。对于非正态分布的数据,IQR方法更靠谱。

好了,数据预处理完,才算真正拿到了“干净”的数据。下一章,咱们聊聊如何用这些数据来标定OCV曲线。到时候见。