3、SCADA数据采集与预处理:打好数据基础
大家好,我是老张。做风电故障诊断这些年,我最大的体会就是——数据质量决定模型上限。你算法再牛,喂进去一堆垃圾数据,出来的结果也是垃圾。今天咱们就聊聊SCADA数据的采集与预处理,这部分我踩过的坑,够写一本小册子了。
核心观点:SCADA数据预处理不是可有可无的步骤,而是整个故障预警系统的地基。地基不稳,楼盖得再高也得塌。
3.1 SCADA系统:风机的"黑匣子"
SCADA,全称是数据采集与监视控制系统。说白了,就是风机的"黑匣子"加"体检报告"。它实时记录着风机各个部件的运行状态——转速、温度、振动、功率、风速等等。
我记得刚入行那会儿,师傅跟我说:"老张,SCADA数据就是风机的脉搏和体温,你得学会看。"当时不太理解,后来做了几个项目才明白——SCADA数据里藏着风机所有的秘密。
一个典型的风场,SCADA系统会采集以下关键参数:
| 参数类别 | 具体参数 | 采集频率 |
|---|---|---|
| 环境参数 | 风速、风向、环境温度、气压 | 1秒-10秒 |
| 电气参数 | 有功功率、无功功率、电网频率、三相电压/电流 | 1秒-10秒 |
| 机械参数 | 主轴转速、发电机转速、桨距角、偏航角度 | 1秒-10秒 |
| 温度参数 | 齿轮箱油温、发电机绕组温度、主轴轴承温度、机舱温度 | 1秒-60秒 |
| 振动参数 | 主轴振动X/Y、齿轮箱振动、发电机振动 | 0.1秒-1秒 |
| 状态参数 | 运行状态、故障代码、累计发电量、累计运行时间 | 事件触发 |
这里有个细节要注意——不同参数的采集频率是不一样的。温度变化慢,可以10秒采一次;振动变化快,得0.1秒采一次。我见过有人把所有参数都按1秒频率采集,结果数据量爆炸,存储成本翻了好几倍。
3.2 数据采集频率与标签:别让数据"失真"
采集频率这事,我吃过亏。有一次做齿轮箱故障预警,用的SCADA数据是10秒一条。结果模型训练出来,准确率只有60%。后来一查,齿轮箱的故障特征频率在10Hz以上,10秒采一次,信息全丢了。
所以,采集频率必须根据信号的物理特性来定。奈奎斯特采样定理告诉我们:采样频率至少是信号最高频率的两倍。但实际工程中,我一般取5-10倍。
举个例子:
- 温度信号:变化慢,1秒-10秒采集一次就够了
- 振动信号:变化快,建议0.1秒-0.01秒采集一次
- 功率信号:介于两者之间,1秒采集一次比较合适
另外,数据标签也很关键。SCADA数据里通常会有"运行状态"这个标签,比如:
- 0:停机
- 1:运行
- 2:故障
- 3:维护
我建议在做预处理时,先把停机、维护的数据剔除掉。因为这些状态下,风机不发电,数据没有分析价值。嗯,这个坑我踩过——有一次忘了剔除停机数据,模型把停机状态误判为"功率异常",闹了个笑话。
3.3 缺失值处理:插值还是删除?
SCADA数据里,缺失值太常见了。传感器故障、通信中断、存储异常,都可能导致数据缺失。处理缺失值,我一般遵循这个原则:
缺失比例 < 5%:插值处理
缺失比例 5%-20%:视情况插值或删除
缺失比例 > 20%:直接删除该特征或时间段
常用的插值方法有:
- 线性插值:简单快速,适合变化平缓的参数(如温度)
- 多项式插值:精度更高,但容易过拟合,适合变化复杂的参数(如功率)
- 前向填充:用上一个有效值填充,适合变化缓慢的参数(如环境温度)
- 后向填充:用下一个有效值填充,适合有延迟响应的参数
代码实现很简单:
import pandas as pd
import numpy as np
# 读取SCADA数据
df = pd.read_csv('scada_data.csv')
# 查看缺失值情况
print(df.isnull().sum())
# 线性插值
df['temp_gearbox'] = df['temp_gearbox'].interpolate(method='linear')
# 前向填充
df['wind_speed'] = df['wind_speed'].fillna(method='ffill')
# 删除缺失比例超过20%的列
threshold = 0.2 * len(df)
df = df.dropna(thresh=threshold, axis=1)
我的经验:对于连续缺失超过10个点的情况,建议用多项式插值。我曾经用线性插值处理一段连续缺失的功率数据,结果插出来的曲线跟实际偏差很大,导致模型训练效果很差。
3.4 异常值检测:3σ法与箱线图
异常值,说白了就是"离谱"的数据。比如风速突然从10m/s跳到100m/s,或者功率变成负数。这些数据必须处理掉,不然模型会被带偏。
我常用的两种方法:
3.4.1 3σ法(拉依达准则)
这个方法假设数据服从正态分布。超出均值±3倍标准差的数据,视为异常值。
def detect_outliers_3sigma(data):
mean = np.mean(data)
std = np.std(data)
lower_bound = mean - 3 * std
upper_bound = mean + 3 * std
outliers = (data < lower_bound) | (data > upper_bound)
return outliers
# 应用
df['outlier_power'] = detect_outliers_3sigma(df['active_power'])
3σ法简单粗暴,但有个前提——数据得服从正态分布。如果数据分布偏斜严重,3σ法会误判很多正常数据为异常。
3.4.2 箱线图法(IQR法)
这个方法不依赖正态分布假设,用四分位数来判定异常。超出Q1-1.5*IQR或Q3+1.5*IQR的数据,视为异常值。
def detect_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
outliers = (data < lower_bound) | (data > upper_bound)
return outliers
# 应用
df['outlier_temp'] = detect_outliers_iqr(df['temp_generator'])
注意:对于风速、功率这类有物理上下限的参数,建议先设置物理阈值,再用统计方法检测。比如风速不可能超过50m/s,功率不可能超过额定功率的1.2倍。先卡物理阈值,再卡统计阈值,这样更稳妥。
我个人习惯是:先用箱线图法做初步筛选,再用3σ法做二次确认。两种方法都标记为异常的,基本可以确定是真正的异常值。
3.5 数据标准化:让所有参数"站在同一起跑线"
标准化,就是把不同量纲的数据映射到同一个尺度。比如温度是0-100℃,功率是0-2000kW,风速是0-30m/s。如果不标准化,模型会天然地"偏爱"数值大的特征。
常用的标准化方法:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | x' = (x - μ) / σ | 数据近似正态分布 |
| Min-Max标准化 | x' = (x - min) / (max - min) | 数据有明确上下界 |
| Robust标准化 | x' = (x - median) / IQR | 数据存在较多异常值 |
代码实现:
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
# Z-score标准化
scaler_z = StandardScaler()
df_scaled_z = scaler_z.fit_transform(df[['active_power', 'wind_speed', 'temp_gearbox']])
# Min-Max标准化
scaler_mm = MinMaxScaler()
df_scaled_mm = scaler_mm.fit_transform(df[['active_power', 'wind_speed', 'temp_gearbox']])
# Robust标准化
scaler_rb = RobustScaler()
df_scaled_rb = scaler_rb.fit_transform(df[['active_power', 'wind_speed', 'temp_gearbox']])
我的建议:对于风电SCADA数据,我推荐用Robust标准化。因为SCADA数据里异常值比较多,Robust标准化用中位数和IQR,对异常值不敏感。Min-Max标准化虽然简单,但一旦出现新的极值,整个标准化结果都会变。
3.6 本章知识体系
说了这么多,咱们用一张图来总结一下SCADA数据采集与预处理的完整流程:
这张图把整个流程串起来了。从数据采集开始,经过缺失值处理、异常值检测、数据标准化,再到特征工程和数据划分,每一步都有讲究。你想想看,如果其中一步没做好,后面的模型再牛也白搭。
好了,SCADA数据采集与预处理就聊到这儿。这部分内容虽然基础,但真的很重要。我见过太多人急着建模型,结果数据预处理没做好,最后模型效果一塌糊涂。记住一句话:数据预处理花的时间,会在模型训练阶段加倍还给你。