数据分箱与标准化:风速分箱、功率归一化、空气密度修正
好,咱们接着聊。前面我们拿到了原始的风速和功率数据,但说实话,这些数据就像刚从矿里挖出来的矿石——杂质多、分布乱、没法直接用。今天我要讲的这三个步骤,就是给数据「洗个澡、分个类、再校准一下」。
我个人习惯把这一章叫做「数据预处理三件套」。你想想看,风功率曲线建模,本质上就是在找风速和功率之间的映射关系。但如果风速数据本身就有偏差,功率值又受环境影响,那模型再漂亮也是白搭。
风速分箱:把连续数据装进「抽屉」里
风速是连续变化的,从0 m/s到25 m/s,中间有无数个可能的值。但实际采集到的数据点,往往在某些风速区间特别密集,某些区间又特别稀疏。直接拿这些不均匀的数据去拟合曲线,结果会偏向数据密集的区域。
怎么办?分箱。
说白了,就是把风速范围切成一个个小段,每个段就是一个「箱子」。比如0.5 m/s一个箱,0~0.5 m/s算第一箱,0.5~1.0 m/s算第二箱,以此类推。然后每个箱子里的功率值取平均,得到一个代表点。
我在项目中遇到过这样的情况:某风场的数据采集频率是1 Hz,一年下来几百万条记录。我一开始用了0.1 m/s的箱宽,结果发现高风速区每个箱子里只有两三个点,平均值的波动特别大。后来改成0.5 m/s,曲线就平滑多了。
分箱的代码其实很简单,用pandas的cut函数就能搞定:
import pandas as pd
import numpy as np
# 假设df包含'wind_speed'和'power'两列
bins = np.arange(0, 30, 0.5) # 从0到30,步长0.5
labels = bins[:-1] + 0.25 # 用箱中心值作为标签
df['bin'] = pd.cut(df['wind_speed'], bins=bins, labels=labels)
binned = df.groupby('bin')['power'].mean().reset_index()
binned.columns = ['wind_speed', 'power_mean']
功率归一化:让不同机组的数据能「对话」
不同型号的风机,额定功率不一样。有的2 MW,有的3 MW,甚至还有1.5 MW的老机组。如果你把它们的功率值直接放在一起比较,那肯定乱套。
归一化,就是把功率值映射到0到1之间。最常用的方法是除以额定功率:
P_norm = P / P_rated
这样,不管原始功率是多少,归一化后都在0~1之间。0代表停机,1代表满发。
嗯,这里要注意:归一化不是简单的数学变换,它背后有一个假设——不同机组的功率曲线形状是相似的。实际上这个假设基本成立,因为风机的气动设计原理是相通的。但如果你遇到的是不同技术代际的机组(比如定速定桨和变速变桨),那就要小心了,它们的曲线形状差异可能很大。
我曾经帮一个客户做风场级评估,他们场里有三种不同品牌的风机。我一开始把所有数据归一化后混在一起建模,结果模型在中间风速段偏差很大。后来发现,其中一种机型的控制策略比较激进,在额定风速附近有功率过冲现象。最后我只能按机型分别建模。
归一化的代码:
# 假设已知额定功率P_rated
df['power_norm'] = df['power'] / P_rated
# 如果不知道额定功率,可以用99.5%分位数近似
P_rated_approx = df['power'].quantile(0.995)
df['power_norm'] = df['power'] / P_rated_approx
空气密度修正:别让天气「骗」了你
风功率公式里有一个关键参数——空气密度ρ。风功率与空气密度成正比:
P = 0.5 * ρ * A * Cp * v³
但空气密度不是常数。它随海拔、温度、气压变化。海平面标准条件下ρ≈1.225 kg/m³,但在青藏高原,ρ可能只有0.8 kg/m³左右。同一台风机,在高原和在海边,相同风速下发出的功率能差30%以上。
所以,我们需要把实际功率修正到标准空气密度下的等效功率。修正公式很简单:
P_corrected = P_actual * (ρ_standard / ρ_actual)
其中ρ_actual可以根据现场的温度和气压计算:
ρ = P / (R * T)
P是大气压(Pa),R是气体常数(287 J/(kg·K)),T是绝对温度(K)。
你可能会问:如果现场没有测气压怎么办?我一般用海拔高度估算:
| 海拔 (m) | 标准气压 (kPa) | 空气密度 (kg/m³) |
|---|---|---|
| 0 | 101.3 | 1.225 |
| 500 | 95.5 | 1.167 |
| 1000 | 89.9 | 1.112 |
| 1500 | 84.6 | 1.058 |
| 2000 | 79.5 | 1.007 |
修正代码:
def air_density_correction(power, temp_c, pressure_pa):
"""
空气密度修正
temp_c: 温度,摄氏度
pressure_pa: 大气压,帕斯卡
"""
R = 287.058 # 气体常数
temp_k = temp_c + 273.15
rho_actual = pressure_pa / (R * temp_k)
rho_standard = 1.225
return power * (rho_standard / rho_actual)
# 应用修正
df['power_corrected'] = air_density_correction(
df['power'],
df['temperature'],
df['pressure']
)
本章知识体系
下面这张图,是我自己梳理的本章核心逻辑。你可以把它当作一个检查清单:
好了,这三个步骤做完,你的数据就「干净」了。风速被规整到统一的箱子里,功率值被归一化到可比较的尺度,空气密度的影响也被消除了。接下来,我们就可以用这些处理好的数据去拟合风功率曲线了。
我个人觉得,数据预处理花的时间,至少应该占到整个建模项目的一半。因为数据质量决定了模型的上限,而模型算法只是在逼近这个上限。你想想看,如果输入的数据都是错的,再牛的算法也救不了。