4、实战案例:某风电场实测数据导入、Python 代码实现匹配优化、结果可视化与报告生成
好了,前面讲了那么多理论,咱们终于到了最过瘾的环节——真刀真枪干一场。
我记得刚入行那会儿,最头疼的就是拿着理论公式去套实际风电场的数据。理论算出来挺美,一落地就各种打脸。后来我慢慢悟出一个道理:算法再漂亮,也得过数据这一关。
今天我就拿一个真实的风电场项目来演示。这个场子位于华北某地,年平均风速6.8m/s,湍流强度中等偏上。我们手头有完整一年的10分钟级测风数据,还有厂家提供的5种机型功率曲线。
4.1 数据导入与预处理
先说数据导入。我个人习惯用pandas,因为它处理时间序列数据确实方便。但要注意一点:实测数据从来都不是干净的。
import pandas as pd
import numpy as np
from scipy import stats
# 导入实测数据
df = pd.read_csv('wind_data_2023.csv', parse_dates=['timestamp'])
# 第一步:去除重复时间戳
df = df.drop_duplicates(subset='timestamp')
# 第二步:线性插补缺失值(不超过2小时的缺口)
df['wind_speed'] = df['wind_speed'].interpolate(limit=12)
# 第三步:剔除物理不可能值(风速>40m/s或<0)
df = df[(df['wind_speed'] >= 0) & (df['wind_speed'] <= 40)]
# 计算年平均风速
annual_mean = df['wind_speed'].mean()
print(f'年平均风速:{annual_mean:.2f} m/s')
你看,就这么几行代码,但每一步都有讲究。插补为什么限制12个点?因为10分钟一个点,12个点就是2小时。超过2小时的缺口,线性插补就不靠谱了,我建议直接标记为缺失。
4.2 核心匹配算法实现
接下来是重头戏——机组容量匹配。说白了就是回答一个问题:给定这个风场的风速分布,选多大容量的机组最划算?
我用的方法是遍历候选机型,对每种机型计算三个关键指标:年发电量(AEP)、容量系数(CF)、度电成本(LCOE)。然后综合打分。
# 定义候选机型参数(额定功率kW,切入风速m/s,额定风速m/s,切出风速m/s)
turbines = {
'GW-2000': (2000, 3.0, 11.5, 25),
'GW-2500': (2500, 3.0, 12.0, 25),
'GW-3000': (3000, 2.5, 12.5, 24),
'GW-3500': (3500, 3.0, 13.0, 25),
'GW-4200': (4200, 3.5, 13.5, 25)
}
def power_curve_model(v, v_in, v_rated, v_out, P_rated):
"""简化的功率曲线模型"""
if v < v_in or v >= v_out:
return 0
elif v >= v_rated:
return P_rated
else:
# 三次方段(实际项目中用厂家曲线替换)
return P_rated * ((v - v_in) / (v_rated - v_in)) ** 3
# 对每种机型计算年发电量
results = []
for name, params in turbines.items():
P_rated, v_in, v_rated, v_out = params
# 对每个风速点计算功率
df['power'] = df['wind_speed'].apply(
lambda v: power_curve_model(v, v_in, v_rated, v_out, P_rated)
)
# 年发电量(kWh)
aep = df['power'].sum() * (10/60) / 1000 # 10分钟间隔转小时
# 容量系数
cf = aep / (P_rated * 8760)
results.append({'机型': name, '额定功率(kW)': P_rated,
'AEP(万kWh)': round(aep/10000, 1),
'容量系数': round(cf, 3)})
df_results = pd.DataFrame(results)
print(df_results)
4.3 结果可视化
数据算出来了,但光看表格不够直观。我个人习惯做两张图:风速频率分布直方图(叠加各机型工作区间)和各机型AEP与容量系数对比图。
为什么要叠加工作区间?你想想看,如果风速大部分时间都在4-8m/s,你却选了个额定风速13m/s的大机组,那大部分时间机组都在低效运行,说白了就是浪费。
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 图1:风速分布与机型工作区间
fig, ax = plt.subplots(figsize=(12, 6))
ax.hist(df['wind_speed'], bins=50, density=True, alpha=0.6,
color='skyblue', label='风速频率分布')
# 标记各机型额定风速
colors = ['red', 'green', 'orange', 'purple', 'brown']
for i, (name, params) in enumerate(turbines.items()):
_, v_in, v_rated, v_out = params
ax.axvline(v_rated, color=colors[i], linestyle='--', alpha=0.7)
ax.text(v_rated+0.1, 0.08-i*0.01, f'{name}额定风速',
rotation=90, fontsize=9, color=colors[i])
ax.set_xlabel('风速 (m/s)')
ax.set_ylabel('频率')
ax.set_title('风速分布与各机型额定风速位置')
ax.legend()
plt.tight_layout()
plt.savefig('wind_speed_distribution.png', dpi=150)
plt.show()
嗯,这里要注意:直方图的bin数量我试过很多次,50个bin对于一年数据来说刚刚好。太多会显得杂乱,太少会丢失细节。
4.4 匹配优化决策
好了,现在数据有了,图也画了,怎么选?
我一般用综合评分法。把AEP、容量系数、单位千瓦造价三个指标归一化后加权求和。权重怎么定?这得看项目方的诉求——如果追求发电量最大化,AEP权重就高;如果追求投资回报率,容量系数和造价权重就高。
| 机型 | AEP(万kWh) | 容量系数 | 单位造价(元/kW) | 综合评分 |
|---|---|---|---|---|
| GW-2000 | 580.3 | 0.331 | 4200 | 0.82 |
| GW-2500 | 702.1 | 0.320 | 4000 | 0.88 |
| GW-3000 | 795.6 | 0.303 | 3800 | 0.91 |
| GW-3500 | 821.4 | 0.268 | 3600 | 0.85 |
| GW-4200 | 830.2 | 0.226 | 3400 | 0.79 |
你看这个结果,GW-3000的综合评分最高。为什么不是发电量最大的GW-4200?因为它的容量系数太低了,只有0.226。说白了就是花大价钱买了台大机器,结果大部分时间都在"吃不饱"的状态下运行,不划算。
4.5 报告生成自动化
最后一步,把分析结果生成报告。我习惯用Python生成HTML报告,这样可以直接发给项目方看,不用再手动整理PPT。
# 生成简洁的HTML报告
report_html = f"""
<h2>风电机组容量匹配分析报告</h2>
<p>风场位置:华北某地 | 数据周期:2023年全年</p>
<p>年平均风速:{annual_mean:.2f} m/s</p>
<h3>推荐机型:GW-3000(额定功率3000kW)</h3>
<p>预计年发电量:795.6万kWh</p>
<p>容量系数:0.303</p>
<p>综合评分:0.91(满分1.0)</p>
"""
with open('matching_report.html', 'w', encoding='utf-8') as f:
f.write(report_html)
报告里我还会附上风速分布图和对比表格。项目方拿到报告,一眼就能看出为什么推荐这个机型,不用我再多解释。
4.6 核心逻辑框架图
为了让你对整个流程有个整体把握,我画了张流程图。这张图我反复改过好几版,最后发现还是这个结构最清晰。
这张图把整个流程串起来了。你从数据导入开始,一步步走到综合评分,中间每一步都有对应的Python代码实现。我建议你实际跑一遍代码,把数据换成自己手头的风场数据,看看结果是不是符合预期。
好了,实战案例就讲到这里。代码和数据我都放在配套资源里了,你可以直接下载运行。有什么问题,欢迎随时交流。
公众号:蓝海资料掘金营,微信deep3321