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分析会直接崩掉。

我的清洗流程一般分三步:

  1. 去重:同一时间戳的多条记录,只保留第一条。
  2. 去异常值:用3σ原则或IQR方法剔除离群点。
  3. 插值填充:对缺失值用线性插值或前向填充。
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 知识体系总览

下面这张图,是我自己梳理的本章知识结构。你可以把它当作一个“地图”,随时回来对照。

数据存储与建模知识体系 时序数据库选型 • InfluxDB:高吞吐、专用时序 • TimescaleDB:SQL兼容、混合负载 • 选型依据:写入量、查询复杂度 • 我的建议:看团队技术栈 数据清洗与归一化 • 去重:同一时间戳保留一条 • 去异常:3σ / IQR方法 • 插值:线性插值 / 前向填充 • 归一化:仅用于模型输入 特征工程 • 统计特征:均值、方差、极值 • 频域特征:FFT频谱分析 • 窗口长度:1024点经验值 • 应用:齿轮箱故障诊断 分区与保留策略 • 按时间分区:每天一个分区 • 按机组分区:独立标签/表 • 热/温/冷数据分层存储 • 冷数据至少保留3年 四个模块环环相扣,从存储到建模形成完整链路

好了,这一章的内容就到这里。数据存储和建模是风电智能运维的基石,基础打牢了,后面的模型训练、故障诊断才能站得住脚。

如果你在实际部署中遇到问题,欢迎随时交流。咱们下章见。


公众号:蓝海资料掘金营,微信deep3321