4. 特征工程(上):时域特征提取(均值、方差、峰峰值)

好,咱们进入特征工程这个环节。说实话,这是整个故障预测模型里最吃经验的部分。数据清洗完了,原始信号摆在那,你不能直接扔给模型——它看不懂。你得帮它提炼出有用的信息。

时域特征,说白了就是直接在时间轴上算统计量。我刚开始做储能BMS数据分析那会儿,也犯过傻,恨不得把所有统计量都算一遍。后来发现,真正管用的就那么几个。今天咱们先聊三个最基础的:均值、方差、峰峰值。

核心观点:时域特征提取,本质上是把一段连续波形压缩成几个有物理意义的数字。压缩得巧,模型就聪明;压缩得糙,模型就笨。

4.1 均值(Mean)—— 信号的“重心”

均值,就是平均值。简单吧?但在储能场景下,它的含义可不简单。

对于电压信号,均值反映了电池的静态工作点。比如一个电芯在静置状态下,均值就是它的开路电压。但在充放电过程中,均值会随着SOC变化而漂移。我遇到过一个问题:某批次电池在恒流充电阶段,电压均值比正常值低了50mV。后来排查发现是内阻偏大导致的。你看,一个简单的均值,就能暴露问题。

数学上,均值的定义是:

μ = (1/N) * Σ x_i

其中N是采样点数,x_i是第i个采样值。

在Python里,用NumPy一行搞定:

import numpy as np

# 假设 voltage 是一个一维数组,包含一段时间的电压采样值
voltage = np.array([3.52, 3.53, 3.51, 3.54, 3.52, 3.53])
mean_voltage = np.mean(voltage)
print(f"电压均值: {mean_voltage:.3f} V")
# 输出: 电压均值: 3.525 V

我的经验:均值对异常值很敏感。如果信号里有一个尖峰噪声,均值会被拉偏。所以我在提取均值前,通常会先做一次简单的滤波,比如中值滤波。别小看这一步,它能省掉你后面很多麻烦。

4.2 方差(Variance)—— 信号的“波动程度”

方差衡量的是信号偏离均值的程度。方差越大,说明信号越“躁动”。

在储能系统里,方差特别有用。你想想看,一个健康的电池,电压波动应该是平稳的。但如果电芯内部开始出现微短路,或者连接片松动,电压就会开始抖动。方差就是捕捉这种抖动的利器。

我曾经处理过一个案例:某储能电站的1号电池簇,电压方差突然从0.001飙升到0.05。一开始运维人员以为是采样问题,后来我坚持让他们去现场检查,结果发现是某个模组的汇流排螺丝松了。嗯,从那以后,方差就成了我必看的特征之一。

方差公式:

σ² = (1/N) * Σ (x_i - μ)²

代码实现:

variance_voltage = np.var(voltage)
print(f"电压方差: {variance_voltage:.5f} V²")
# 输出: 电压方差: 0.00011 V²

注意:方差的单位是原始单位的平方。比如电压单位是V,方差单位就是V²。这有时候不太直观。所以很多人更喜欢用标准差(std),它是方差的平方根,单位跟原始信号一致。

4.3 峰峰值(Peak-to-Peak)—— 信号的“最大摆幅”

峰峰值,就是最大值减最小值。它告诉你信号在时间窗口内“折腾”了多大范围。

在储能故障预测中,峰峰值对突发性异常特别敏感。比如电池突然发生热失控前,电压可能会出现剧烈的瞬时跌落,这时候峰峰值会瞬间变大。我见过一个案例:某电芯在热失控前30秒,电压峰峰值从正常的0.02V跳到了0.35V。虽然均值变化不大,但峰峰值已经报警了。

公式很简单:

P2P = max(x) - min(x)

代码:

p2p_voltage = np.max(voltage) - np.min(voltage)
print(f"电压峰峰值: {p2p_voltage:.3f} V")
# 输出: 电压峰峰值: 0.030 V

避坑指南:我曾经犯过一个错误——直接用原始数据的最大值和最小值算峰峰值。结果发现数据里有一个明显的采样毛刺,导致峰峰值虚高。后来我学乖了,先去掉最高和最低的1%数据,再用剩下的算。这样算出来的峰峰值更稳健。

4.4 三个特征的关系与对比

这三个特征,其实是从不同角度描述信号:

  • 均值:告诉你信号“在哪”
  • 方差:告诉你信号“抖不抖”
  • 峰峰值:告诉你信号“最极端的情况”

它们之间没有绝对的优劣,关键看场景。比如:

故障类型 均值 方差 峰峰值
内阻增大 明显变化 轻微变化 轻微变化
微短路 轻微变化 明显变化 明显变化
连接松动 无变化 明显变化 明显变化
热失控前兆 轻微变化 剧烈变化 剧烈变化

你看,不同故障对这三个特征的敏感度是不一样的。所以实际项目中,我一般会把它们组合起来用,形成一个特征向量。

4.5 知识体系结构图

下面这张图,帮你理清时域特征提取的核心逻辑:

时域特征提取知识体系 原始时域信号 均值 (Mean) 反映静态工作点 方差 (Variance) 反映波动程度 峰峰值 (P2P) 反映最大摆幅 内阻增大检测 微短路 / 连接松动 热失控前兆预警 特征向量 → 模型输入

4.6 实际项目中的组合用法

光讲理论没意思,咱们来点实际的。假设你有一段电压数据,采样频率是10Hz,时间窗口是10秒(也就是100个采样点)。你会怎么提取特征?

我的做法是这样的:

  1. 滑动窗口:以1秒为步长,每次取10秒的数据段。
  2. 对每个窗口,计算均值、方差、峰峰值。
  3. 形成三维特征向量:[mean, variance, p2p]。
  4. 送入模型:比如一个简单的SVM或者随机森林。

代码示例:

import numpy as np

def extract_time_features(signal, window_size=100, step=10):
    """
    滑动窗口提取时域特征
    signal: 一维数组
    window_size: 窗口长度(采样点数)
    step: 滑动步长(采样点数)
    """
    features = []
    for start in range(0, len(signal) - window_size + 1, step):
        window = signal[start:start + window_size]
        mean = np.mean(window)
        var = np.var(window)
        p2p = np.max(window) - np.min(window)
        features.append([mean, var, p2p])
    return np.array(features)

# 模拟一段电压信号
np.random.seed(42)
voltage_signal = 3.5 + 0.02 * np.random.randn(1000)  # 正常波动
# 在第500个点加入一个异常
voltage_signal[500:510] += 0.15  # 模拟电压突降

feat_matrix = extract_time_features(voltage_signal)
print(f"特征矩阵形状: {feat_matrix.shape}")
# 输出: 特征矩阵形状: (91, 3)
print("前3个窗口的特征:")
print(feat_matrix[:3])
# 输出示例:
# [[3.5002, 0.0004, 0.0812],
#  [3.5005, 0.0003, 0.0798],
#  [3.4998, 0.0004, 0.0805]]

我的习惯:提取完特征后,我通常会先做一次可视化。把三个特征画成散点图或者平行坐标图,看看正常数据和异常数据能不能分开。如果分不开,说明特征选得不对,得换思路。这一步能帮你省掉大量调参时间。

好了,时域特征的上半部分就聊到这儿。均值、方差、峰峰值,这三个是基础中的基础。你想想看,它们虽然简单,但组合起来已经能覆盖大部分常见故障场景了。下一节咱们会继续聊更高级的时域特征,比如均方根、峭度、波形因子这些。不过先把今天这三个练熟,比什么都强。


专注资料整理