数据采集与清洗:SCADA系统数据、振动监测数据、气象数据、数据清洗实战

各位同行,咱们直接进入正题。数据采集与清洗,说白了就是给风场做体检前的抽血化验。血样不准,后面所有分析都是白搭。我见过太多团队花大价钱上分析平台,结果数据质量一塌糊涂,最后得出的结论连自己都不信。

SCADA系统数据:风场的"心电图"

SCADA系统,也就是数据采集与监视控制系统。它每时每刻都在记录风机的运行状态。我个人习惯把SCADA数据比作风机的心电图——电压、电流、功率、转速、温度,这些参数一个都不能少。

SCADA数据的特点是什么?

  • 采样频率低:通常10分钟一条记录。别嫌少,对于长期趋势分析完全够用。
  • 数据量大:一台风机一年产生约5万条记录,一个风场几十台风机,数据量相当可观。
  • 字段丰富:少则几十个,多则上百个参数。

核心字段清单(我建议至少保留这些)

类别字段说明
时间timestamp精确到秒
运行状态status运行/停机/故障/限功率
发电量active_power单位kW
风速wind_speed机舱风速计测得
转速rotor_speed风轮转速,单位rpm
温度gear_temp, gen_temp齿轮箱、发电机温度
振动vibration_x, vibration_y机舱振动值

嗯,这里要注意:SCADA数据里经常藏着"假数据"。比如风机明明停机了,功率却显示为0,但风速还在跳。这种数据如果不处理,后面算发电量损失时会出大问题。

振动监测数据:听诊器下的秘密

振动监测,说白了就是给风机戴听诊器。SCADA数据告诉你"风机病了",振动数据告诉你"病在哪"。

振动数据的特点和SCADA完全不同:

  • 采样频率极高:通常每秒几千到几万次采样。你想想看,一分钟的数据量就顶SCADA跑一年。
  • 数据量爆炸:一台风机一天产生几个GB的振动数据很正常。
  • 需要专业处理:原始振动数据没法直接用,得做FFT变换、包络分析等处理。

我在项目中遇到过一件事:某风场连续报齿轮箱故障,SCADA数据显示温度正常,但振动监测发现高频段有异常峰值。后来拆开一看,轴承保持架已经裂了。要是只靠SCADA数据,这台风机会一直带病运行到彻底报废。

我的经验:振动数据不要全量存储。建议只保存:

  1. 原始数据的统计特征(均值、峰值、峭度等)
  2. 频谱图中的关键频段能量值
  3. 报警触发前后的原始数据片段

这样既能保留关键信息,又不会把存储撑爆。

气象数据:风从哪里来

气象数据,尤其是测风塔数据,是风场分析的基准。SCADA上的风速是机舱风速计测的,受叶片旋转影响,数据有偏差。测风塔数据才是"真值"。

气象数据采集要注意什么?

  • 高度分层:测风塔通常在10m、50m、70m、90m等高度都有传感器。不同高度的风速差异很大。
  • 风向扇区:风场周围有障碍物(其他风机、山体、建筑物)会影响风向。需要做扇区管理。
  • 数据完整性:气象站容易出问题,结冰、雷击、传感器老化,数据缺失是常态。

我曾经处理过一个案例:某风场发电量一直低于设计值,SCADA数据显示风速正常。后来一查测风塔数据,发现机舱风速计比测风塔风速低了15%。原来是叶片污染导致风速计测量不准。你看,没有气象数据做对比,这个问题根本发现不了。

数据清洗实战:脏数据无处遁形

好了,数据采集完了,接下来就是重头戏——数据清洗。我常说一句话:数据清洗花的时间,至少占整个数据分析项目的60%。别嫌多,这是常态。

常见的脏数据类型:

  • 缺失值:传感器故障、通信中断导致数据为空
  • 异常值:传感器漂移、干扰导致数据超出物理范围
  • 重复值:通信协议问题导致同一条数据被记录多次
  • 逻辑错误:风速为0但功率不为0,或者功率为负值

下面是我常用的清洗流程,用Python实现:

import pandas as pd
import numpy as np

# 读取SCADA数据
df = pd.read_csv('scada_data.csv', parse_dates=['timestamp'])

# 1. 删除完全重复的行
df = df.drop_duplicates()

# 2. 处理缺失值
# 对于连续型参数,用前后均值填充
df['wind_speed'] = df['wind_speed'].interpolate(method='linear')
# 对于状态类参数,用前向填充
df['status'] = df['status'].fillna(method='ffill')

# 3. 剔除物理范围外的异常值
df = df[(df['wind_speed'] >= 0) & (df['wind_speed'] <= 35)]
df = df[(df['active_power'] >= 0) & (df['active_power'] <= 2500)]

# 4. 剔除逻辑错误
# 风速大于切入风速但功率为0,可能是停机状态
mask = (df['wind_speed'] > 3) & (df['active_power'] == 0) & (df['status'] != '停机')
df.loc[mask, 'active_power'] = np.nan

# 5. 标记限功率运行状态
# 风速在额定风速以上但功率低于额定功率的95%
mask = (df['wind_speed'] > 12) & (df['active_power'] < 0.95 * 2500)
df.loc[mask, 'status'] = '限功率'

print(f"清洗前数据量: {len(df_raw)}")
print(f"清洗后数据量: {len(df)}")
print(f"剔除比例: {(1 - len(df)/len(df_raw))*100:.1f}%")

注意:数据清洗不是越狠越好。我曾经见过有人把限功率运行的数据全删了,理由是"功率没达到额定值"。结果分析发电量损失时,数据全没了,白干。清洗前一定要搞清楚业务逻辑。

知识体系总览

说了这么多,咱们用一张图把数据采集与清洗的核心逻辑串起来:

数据采集与清洗知识体系 SCADA系统数据 10分钟/条,百个字段 振动监测数据 kHz级采样,GB级/天 气象数据 测风塔,多高度层 数据清洗核心步骤 去重 缺失值处理 异常值剔除 逻辑校验 高质量可用数据集 三个数据源经过清洗后,统一时间戳,合并为分析用数据集

这张图把咱们刚才讲的内容串起来了。三个数据源各有特点,但最终都要汇入数据清洗这个"大熔炉"。清洗干净了,后面的分析才有意义。

实战建议:刚开始做数据清洗时,别想着一步到位。我的做法是:

  1. 先跑一遍基础清洗(去重、范围校验)
  2. 可视化看看数据分布,找找明显异常
  3. 跟现场运维人员确认业务逻辑
  4. 再跑第二轮精细清洗

这样反复迭代两三次,数据质量基本就靠谱了。

好了,数据采集与清洗这块就聊到这儿。记住一句话:数据清洗不是技术活,是良心活。你花多少心思在清洗上,后面的分析就能给你多少回报。

专注资料整理