4. 数据存储与建模:时序数据库选型与特征工程
大家好,我是老张。今天咱们聊聊风电运维里最核心的一环——数据怎么存、怎么洗、怎么用。
说实话,我见过太多项目栽在数据存储上。有的团队上来就用MySQL硬扛千万级时序数据,结果查询慢得像蜗牛。有的选了InfluxDB,但分区策略没搞好,磁盘直接爆了。嗯,这些坑我都踩过。
这一章,我把自己的实战经验掰开揉碎讲给你听。从数据库选型到特征工程,咱们一步步来。
核心要点:时序数据存储不是简单的“存进去、查出来”。你要考虑写入速度、查询效率、存储成本,还要为后续的机器学习模型打好基础。
4.1 时序数据库选型:InfluxDB vs TimescaleDB
选哪个?这问题我当年纠结了整整两周。后来两个都试了一遍,才摸清门道。
InfluxDB 是专门为时序数据设计的。它的数据模型就是“时间戳 + 标签 + 字段”,写入速度极快。我曾在单节点上压测过,每秒能写20万点。但它的SQL支持很弱,得用自家的Flux查询语言。
TimescaleDB 则是在PostgreSQL上加了时序插件。说白了,它就是个“增强版PG”。你如果团队里有人熟悉SQL,上手会很快。而且它能无缝对接现有的BI工具。
| 对比维度 | InfluxDB | TimescaleDB |
|---|---|---|
| 写入性能 | 极高(单节点20万点/秒) | 高(约10万点/秒) |
| 查询语言 | Flux(学习成本高) | 标准SQL(上手快) |
| 数据压缩 | 内置压缩,存储效率高 | 依赖PG压缩,略逊一筹 |
| 集群支持 | 企业版才支持 | 原生支持(基于PG流复制) |
| 适用场景 | 纯时序、高吞吐 | 混合负载、需要复杂关联查询 |
我的建议:如果你们团队主要做风电振动监测、SCADA高频采集,选InfluxDB。如果还要做设备台账管理、工单关联查询,选TimescaleDB更省心。
4.2 数据清洗与归一化
数据清洗,说白了就是“去脏”。风电数据有多脏?我举个例子:
有一次,某风场一台机组的转速数据突然跳变到9999转/分。这明显是传感器故障。如果不处理,后续的FFT分析会直接崩掉。
我的清洗流程一般分三步:
- 去重:同一时间戳的多条记录,只保留第一条。
- 去异常值:用3σ原则或IQR方法剔除离群点。
- 插值填充:对缺失值用线性插值或前向填充。
import pandas as pd
import numpy as np
def clean_wind_data(df, column='power', method='3sigma'):
# 去重
df = df.drop_duplicates(subset=['timestamp'])
# 3σ去异常
if method == '3sigma':
mean = df[column].mean()
std = df[column].std()
df = df[(df[column] >= mean - 3*std) & (df[column] <= mean + 3*std)]
# 线性插值
df = df.set_index('timestamp').resample('1s').asfreq()
df[column] = df[column].interpolate(method='linear')
return df.reset_index()
注意:归一化不是万能的。对于风速、功率这类物理量,我建议保留原始单位。归一化只用在模型输入前,别把原始数据改了。
4.3 特征工程:均值、方差与FFT
特征工程,就是把原始数据变成模型能听懂的语言。风电数据里,我最常用的三类特征:
4.3.1 统计特征(均值、方差)
均值反映趋势,方差反映波动。比如,某台机组过去10分钟的功率均值突然下降,可能是叶片结冰了。
def extract_stat_features(df, window=600):
df['power_mean'] = df['power'].rolling(window).mean()
df['power_std'] = df['power'].rolling(window).std()
df['power_max'] = df['power'].rolling(window).max()
df['power_min'] = df['power'].rolling(window).min()
return df
4.3.2 频域特征(FFT)
FFT能把时域信号转成频域。我在做齿轮箱故障诊断时,经常用FFT看频谱。正常齿轮箱的频谱集中在啮合频率附近,如果出现边频带,说明可能有磨损。
import numpy as np
from scipy.fft import fft
def extract_fft_features(signal, fs=10):
n = len(signal)
freqs = np.fft.fftfreq(n, 1/fs)
fft_vals = np.abs(fft(signal))
# 只取正频率部分
pos_mask = freqs > 0
return freqs[pos_mask], fft_vals[pos_mask]
实战经验:FFT的窗口长度很关键。我一般取1024点,这样频率分辨率够用,计算量也不大。如果数据采样率是10Hz,1024点就是102.4秒,刚好覆盖一个完整的风周期。
4.4 数据分区与保留策略
数据分区,说白了就是“分桶存储”。不分区的后果?我见过一个案例:某风场一年积累了50TB数据,查询一周的数据要扫全表,耗时20分钟。
我的分区策略:
- 按时间分区:每天一个分区。查询时只扫对应分区,速度提升百倍。
- 按机组分区:每台机组独立表或标签。避免多机组数据混在一起。
保留策略也很重要。风电数据有明确的“热温冷”分层:
| 数据层级 | 保留时间 | 存储介质 | 用途 |
|---|---|---|---|
| 热数据 | 最近7天 | SSD | 实时监控、告警 |
| 温数据 | 7天~6个月 | HDD | 日常分析、报表 |
| 冷数据 | 6个月以上 | 对象存储(S3) | 历史回溯、模型训练 |
避坑指南:我曾经把保留策略设得太激进,7天前的数据直接删了。结果后来要做年度故障分析,发现历史数据全没了。从那以后,我坚持“冷数据至少保留3年”。
4.5 知识体系总览
下面这张图,是我自己梳理的本章知识结构。你可以把它当作一个“地图”,随时回来对照。
好了,这一章的内容就到这里。数据存储和建模是风电智能运维的基石,基础打牢了,后面的模型训练、故障诊断才能站得住脚。
如果你在实际部署中遇到问题,欢迎随时交流。咱们下章见。
公众号:蓝海资料掘金营,微信deep3321