第一章:风电数据基础——SCADA系统与数据预处理
各位同学好,我是老张。在风电行业摸爬滚打了十几年,今天咱们来聊聊风电智能决策系统的地基——数据。
你想想看,一台风机上百个传感器,每秒都在产生数据。这些数据怎么来的?怎么保证质量?怎么处理脏数据?说白了,这就是本章要解决的问题。
核心观点:数据质量决定了模型的天花板。再牛的算法,喂进去垃圾数据,吐出来的也是垃圾。
1.1 SCADA系统——风机的“黑匣子”
SCADA,全称是数据采集与监视控制系统。我习惯叫它风机的“黑匣子”。
它干三件事:
- 采集数据——风速、转速、温度、振动、功率……
- 监视状态——风机是运行、停机还是故障?
- 控制指令——远程启停、变桨、偏航……
我在项目里见过最老的SCADA系统,还是2005年的。那会儿数据采样频率只有1Hz,存储用的是磁带机。现在?10Hz、50Hz都是常态,数据量大了两个数量级。
小提示:SCADA数据通常以10分钟平均值为单位存储。但做故障诊断时,我建议用原始高频数据。平均值会抹掉很多细节。
1.2 数据采集原理——传感器都在哪?
一台2MW的风机,大概有80-120个传感器。我列几个关键的:
| 传感器类型 | 安装位置 | 采集参数 |
|---|---|---|
| 风速仪 | 机舱顶部 | 风速、风向 |
| 编码器 | 主轴、齿轮箱 | 转速 |
| 加速度计 | 轴承座、塔筒 | 振动 |
| 热电偶 | 齿轮箱、发电机 | 温度 |
| 功率变送器 | 并网柜 | 有功、无功功率 |
嗯,这里要注意:风速仪装在机舱后面,测的是“经过风轮扰动后的风速”。所以SCADA里的风速,比真实来流风速低15%-20%。这个误差,做功率曲线分析时必须修正。
1.3 数据清洗——脏数据怎么处理?
我接手过一个项目,SCADA数据里风速显示80m/s。你想想看,12级台风也就32.7m/s。这明显是传感器坏了。
常见的脏数据有这几类:
- 超出物理范围——风速>50m/s、温度>150°C
- 恒定值——连续100个点数值不变(传感器卡死)
- 跳变值——0.1秒内从5m/s跳到50m/s
- 缺失值——NaN或空值
避坑指南:我曾经直接删掉所有异常值,结果模型训练出来一塌糊涂。后来发现,有些“异常值”其实是风机在特殊工况下的真实数据。比如切出风速附近,功率波动本来就大。所以清洗前,一定要先看数据分布。
下面是我常用的清洗流程:
import pandas as pd
import numpy as np
def clean_scada_data(df):
# 1. 删除超出物理范围的数据
df = df[(df['wind_speed'] >= 0) & (df['wind_speed'] <= 50)]
df = df[(df['power'] >= 0) & (df['power'] <= 2500)] # 单位kW
# 2. 删除恒定值(连续10个点不变)
for col in ['wind_speed', 'power', 'rotor_speed']:
diff = df[col].diff()
constant_mask = (diff == 0).rolling(window=10).sum() >= 10
df = df[~constant_mask]
# 3. 删除跳变值(变化率超过阈值)
df['power_diff'] = df['power'].diff().abs()
df = df[df['power_diff'] < 500] # 功率变化不超过500kW/10min
return df
1.4 缺失值处理——填还是不填?
这是个经典问题。我的原则是:能补则补,不能补就删。
缺失值产生的原因:
- 传感器故障(比如振动传感器断线)
- 通讯中断(光纤被挖断,我遇到过两次)
- 停机维护(人为断电)
- 数据存储异常(磁盘满了)
处理策略分三种:
| 缺失比例 | 处理方法 | 适用场景 |
|---|---|---|
| < 5% | 线性插值 | 风速、温度等连续变化量 |
| 5% - 20% | 前向填充 + 滚动平均 | 功率、转速等有规律的数据 |
| > 20% | 直接删除该段数据 | 任何场景(补了也不可信) |
个人经验:做功率曲线分析时,我一般用线性插值。但做故障预测时,我倾向于用前向填充。为什么?因为故障前的数据往往有趋势性变化,插值会平滑掉这些特征。
代码实现:
# 线性插值
df['wind_speed'] = df['wind_speed'].interpolate(method='linear')
# 前向填充 + 滚动平均
df['power'] = df['power'].fillna(method='ffill')
df['power'] = df['power'].rolling(window=3, min_periods=1).mean()
# 删除缺失超过20%的连续段
missing_ratio = df.isnull().sum() / len(df)
if missing_ratio > 0.2:
df = df.dropna()
1.5 知识体系总览
下面这张图,是我自己总结的数据处理全流程。你把它打印出来贴在工位上,做项目时对照着来。
这张图里,我特意把“保留原始数据副本”写在最下面。为什么?因为清洗逻辑错了,你还能回滚重来。我见过太多人直接覆盖原始数据,结果想改都改不了。
最后说一句:数据预处理没有银弹。每个风场、每台风机都有自己的“脾气”。多看图、多分析、多问为什么。数据搞明白了,后面的模型就是水到渠成的事。