Python与可再生能源技术结合实现发电预测与优化调度插图

Python与可再生能源技术结合实现发电预测与优化调度:一个风电场的实战案例

大家好,作为一名长期混迹在能源与数据交叉领域的开发者,我深刻感受到,可再生能源的波动性既是挑战,也是机遇。单纯依赖传统经验进行发电调度,在“看天吃饭”的风电和光伏领域已经行不通了。今天,我想和大家分享一个我亲身参与的项目:如何用Python为一座中型风电场搭建一套从发电预测到优化调度的简易原型系统。这个过程充满了数据清洗的烦恼、模型调参的纠结,当然,还有代码跑通那一刻的成就感。希望我的经验能给你带来一些启发。

第一步:理解业务与数据准备——一切从“脏数据”开始

我们的目标是:利用历史功率数据、气象预报数据(风速、风向等),预测未来24小时风电场的出力,并基于预测结果和电网调度指令,给出各风机群的优化运行建议。

首先,数据是基石。我们通常从SCADA(数据采集与监控系统)和气象服务API获取数据。原始数据往往惨不忍睹:存在缺失值、异常值(如风速正常但功率为零的停机记录)、时间戳不规整等问题。

我的实战踩坑提示:千万不要跳过数据质量分析! 我曾因忽略一段传感器故障期的数据,导致训练出的模型在“好天气”下预测精准,一遇到特定风况就“崩盘”。

这里,Pandas是我们的主力。以下是一段典型的数据清洗与特征工程代码:

import pandas as pd
import numpy as np
from datetime import timedelta

# 加载数据
df_power = pd.read_csv('wind_power_history.csv', parse_dates=['timestamp'])
df_weather = pd.read_csv('weather_forecast.csv', parse_dates=['timestamp'])

# 1. 对齐时间戳(15分钟间隔)
df_power.set_index('timestamp', inplace=True)
df_power = df_power.resample('15min').mean() # 聚合

# 2. 处理缺失值 - 对于功率,前后插值;对于风速,用历史同期均值
df_power['power'].interpolate(method='time', inplace=True)
# 假设我们已有历史风速的同期均值字典 `wind_speed_avg`
# df_weather['wind_speed'].fillna(...)

# 3. 处理异常值:识别并剔除明显不合理的记录(如功率大于额定容量)
rated_capacity = 2.5 # 兆瓦
invalid_mask = (df_power['power']  rated_capacity * 1.05)
df_power.loc[invalid_mask, 'power'] = np.nan
df_power['power'].interpolate(method='time', inplace=True)

# 4. 特征工程:创造对模型有用的特征
df_power['hour'] = df_power.index.hour
df_power['day_of_week'] = df_power.index.dayofweek
df_power['month'] = df_power.index.month
# 计算滚动平均风速,作为短期趋势特征
df_weather['wind_speed_rolling_3h'] = df_weather['wind_speed'].rolling(window=12).mean() # 12个15分钟点=3小时

# 5. 合并数据集
df = pd.merge(df_power, df_weather, on='timestamp', how='inner')
print(df.head())

第二步:构建发电预测模型——从简单回归到LSTM的探索

预测是优化的前提。我们尝试了从线性回归、随机森林到LSTM(长短期记忆网络)等多种模型。对于初学者,我强烈建议从树模型(如随机森林)开始,它对特征工程的要求相对友好,且能给出特征重要性,帮你理解数据。

踩坑提示:直接上LSTM可能很酷,但你需要大量的数据、仔细的序列构建和更长的训练时间。对于许多场站,特征丰富的树模型表现可能并不逊色。

以下是使用Scikit-learn构建随机森林预测模型的示例:

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error

# 准备特征和目标变量
# 假设特征包括历史功率、风速、风向、温度、时间特征等
feature_columns = ['wind_speed', 'wind_direction', 'temperature', 'hour', 'day_of_week', 'power_lag_1h'] # power_lag_1h 需要提前创建
target_column = 'power'

X = df[feature_columns].dropna()
y = df.loc[X.index, target_column]

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # 时间序列不随机打乱

# 创建并训练模型
rf_model = RandomForestRegressor(n_estimators=100, random_state=42, n_jobs=-1)
rf_model.fit(X_train, y_train)

# 预测与评估
y_pred = rf_model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"随机森林预测效果: MAE: {mae:.2f} MW, RMSE: {rmse:.2f} MW")

# 查看特征重要性
importances = pd.DataFrame({'feature': feature_columns, 'importance': rf_model.feature_importances_})
print(importances.sort_values('importance', ascending=False))

第三步:优化调度模型——将预测转化为决策

有了预测的发电功率曲线,下一步就是优化调度。核心问题通常是:在满足电网调度指令(总出力计划)和风机自身约束(启停、爬坡率)的前提下,如何分配各风机或风机群的出力,使得损耗最小、收益最大或疲劳载荷最低?

这通常是一个约束优化问题,我们可以使用PuLP或CVXPY这样的优化库来求解。

踩坑提示:模型的约束务必贴合实际物理限制。我曾设定了理想化的爬坡率,结果优化出的调度方案被现场工程师直接否决——风机根本做不到那种“急转弯”。

下面是一个极度简化的示例,假设我们要分配未来4个时段(1小时一个时段)的出力给3台风机,以满足总计划,并考虑每台风机的最小出力和最大出力限制:

import pulp

# 假设数据
num_periods = 4
num_turbines = 3
# 预测的每台风机最大可用功率 (MW)
P_max = np.array([[2.0, 2.1, 1.9], [2.2, 2.0, 2.0], [1.8, 2.2, 2.1], [2.1, 1.9, 2.0]])
# 电网调度总计划 (MW)
P_total_demand = np.array([4.5, 5.0, 5.2, 4.8])
# 风机最小出力 (MW)
P_min = 0.2

# 定义问题
prob = pulp.LpProblem('Wind_Farm_Dispatch', pulp.LpMinimize)

# 定义决策变量:每台风机在每个时段的实际出力
P = pulp.LpVariable.dicts("P", ((i, j) for i in range(num_periods) for j in range(num_turbines)), lowBound=P_min)

# 目标函数:假设我们想最小化总发电成本(这里简化为总出力,实际可能包含磨损成本等)
prob += pulp.lpSum([P[(i, j)] for i in range(num_periods) for j in range(num_turbines)])

# 约束条件
# 1. 每个时段总出力等于调度计划
for i in range(num_periods):
    prob += pulp.lpSum([P[(i, j)] for j in range(num_turbines)]) == P_total_demand[i]

# 2. 每台风机出力不超过其预测最大可用功率
for i in range(num_periods):
    for j in range(num_turbines):
        prob += P[(i, j)] <= P_max[i, j]

# 3. (可选)爬坡率约束,此处省略...

# 求解
prob.solve(pulp.PULP_CBC_CMD(msg=False))
print("优化状态:", pulp.LpStatus[prob.status])

# 输出结果
if prob.status == pulp.LpStatusOptimal:
    schedule = np.zeros((num_periods, num_turbines))
    for i in range(num_periods):
        for j in range(num_turbines):
            schedule[i, j] = P[(i, j)].varValue
    print("优化后的出力调度方案 (MW):")
    print(schedule)
else:
    print("未找到最优解,请检查约束条件是否冲突。")

第四步:系统集成与展望——让模型“活”起来

将预测和优化模块串联,并设定定时任务(如使用Apache Airflow或简单的cron job),就能形成一个自动化的决策支持系统。我们可以用Flask或FastAPI包装成API,供前端监控界面或SCADA系统调用。

回顾这个项目,最大的收获不是某个模型的超高精度,而是建立了“数据-预测-优化-反馈”的完整思维闭环。Python生态提供的强大工具链,让我们能够快速原型化并验证想法。

未来的方向可以更深入:引入更精细的物理模型(如考虑尾流效应)、结合市场价格信号进行经济性优化、甚至利用强化学习让系统自适应学习调度策略。可再生能源的智能化之路漫长,但用Python敲下每一行代码,都让我们离高效、绿色的未来电网更近一步。希望这篇实战笔记能成为你探索之路的一块垫脚石。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。