修复了弃风计算不正确的bug。
This commit is contained in:
38
main.py
38
main.py
@@ -190,6 +190,39 @@ def plot_system_curves(solar_output, wind_output, thermal_output, load_demand, r
|
||||
|
||||
|
||||
def export_results_to_excel(solar_output, wind_output, thermal_output, load_demand, result, params, filename=None):
|
||||
"""
|
||||
将多能互补系统储能优化结果导出到Excel文件,包含运行数据、统计结果和系统参数。
|
||||
|
||||
Args:
|
||||
solar_output (list): 光伏出力曲线 (MW)
|
||||
wind_output (list): 风电出力曲线 (MW)
|
||||
thermal_output (list): 火电出力曲线 (MW)
|
||||
load_demand (list): 负荷需求曲线 (MW)
|
||||
result (dict): 包含以下键的优化结果字典:
|
||||
- charge_profile: 储能充电功率曲线 (MW)
|
||||
- discharge_profile: 储能放电功率曲线 (MW)
|
||||
- storage_profile: 储能状态曲线 (MWh)
|
||||
- curtailed_wind: 弃风功率曲线 (MW)
|
||||
- curtailed_solar: 弃光功率曲线 (MW)
|
||||
- grid_feed_in: 电网交互功率曲线 (MW, 负值表示购电)
|
||||
- required_storage_capacity: 所需储能总容量 (MWh)
|
||||
- total_curtailment_wind_ratio: 总弃风率
|
||||
- total_curtailment_solar_ratio: 总弃光率
|
||||
- total_grid_feed_in_ratio: 总上网电量比例
|
||||
- energy_balance_check: 能量平衡校验结果
|
||||
- capacity_limit_reached: 容量限制是否达到
|
||||
params (object): 系统参数对象,包含各种技术参数
|
||||
filename (str, optional): 输出文件名,如未提供则自动生成
|
||||
|
||||
Returns:
|
||||
str: 生成的Excel文件路径
|
||||
|
||||
生成的Excel文件包含以下工作表:
|
||||
- 运行数据: 小时级运行数据
|
||||
- 统计结果: 关键性能指标统计
|
||||
- 系统参数: 输入参数汇总
|
||||
- 说明: 文件使用说明
|
||||
"""
|
||||
"""
|
||||
将优化结果导出到Excel文件
|
||||
|
||||
@@ -410,8 +443,7 @@ def main():
|
||||
show_window = '--show' in sys.argv # 检查是否包含--show参数
|
||||
display_only = '--display-only' in sys.argv # 检查是否只显示不保存
|
||||
|
||||
|
||||
if command == '--excel':
|
||||
if command == '--excel':
|
||||
if len(sys.argv) < 3:
|
||||
print("错误:请指定Excel文件路径")
|
||||
print("用法:python main.py --excel <文件路径>")
|
||||
@@ -478,6 +510,7 @@ if command == '--excel':
|
||||
except Exception as e:
|
||||
print(f"读取Excel文件失败:{str(e)}")
|
||||
return
|
||||
|
||||
elif command == '--create-template':
|
||||
template_type = sys.argv[2] if len(sys.argv) > 2 else "8760"
|
||||
template_file = f"data_template_{template_type}.xlsx"
|
||||
@@ -552,7 +585,6 @@ if command == '--excel':
|
||||
else:
|
||||
print("\n曲线图已保存为 'system_curves.png'")
|
||||
|
||||
|
||||
def print_usage():
|
||||
"""打印使用说明"""
|
||||
print("多能互补系统储能容量优化程序")
|
||||
|
||||
362
solar_optimization.py
Normal file
362
solar_optimization.py
Normal file
@@ -0,0 +1,362 @@
|
||||
"""
|
||||
光伏出力优化模块
|
||||
|
||||
该模块通过调整光伏出力曲线的系数,在给定的系统参数条件下
|
||||
最小化与电网交换的电量,提高系统的自平衡能力。
|
||||
|
||||
作者: iFlow CLI
|
||||
创建日期: 2025-12-26
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
from dataclasses import dataclass
|
||||
from storage_optimization import SystemParameters, optimize_storage_capacity, calculate_energy_balance
|
||||
|
||||
|
||||
@dataclass
|
||||
class SolarOptimizationResult:
|
||||
"""光伏优化结果类"""
|
||||
optimal_solar_coefficient: float # 最优光伏系数
|
||||
original_solar_output: List[float] # 原始光伏出力曲线
|
||||
optimized_solar_output: List[float] # 优化后光伏出力曲线
|
||||
min_grid_exchange: float # 最小电网交换电量
|
||||
grid_purchase: float # 购电量
|
||||
grid_feed_in: float # 上网电量
|
||||
storage_result: Dict # 储能优化结果
|
||||
optimization_history: List[Dict] # 优化历史记录
|
||||
|
||||
|
||||
def calculate_grid_exchange_metric(
|
||||
solar_output: List[float],
|
||||
wind_output: List[float],
|
||||
thermal_output: List[float],
|
||||
load_demand: List[float],
|
||||
params: SystemParameters
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
计算电网交换电量指标
|
||||
|
||||
Args:
|
||||
solar_output: 光伏出力曲线 (MW)
|
||||
wind_output: 风电出力曲线 (MW)
|
||||
thermal_output: 火电出力曲线 (MW)
|
||||
load_demand: 负荷曲线 (MW)
|
||||
params: 系统参数配置
|
||||
|
||||
Returns:
|
||||
包含电网交换指标的字典
|
||||
"""
|
||||
# 计算最优储能容量
|
||||
storage_result = optimize_storage_capacity(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 计算电网交换电量
|
||||
grid_feed_in = storage_result['grid_feed_in']
|
||||
|
||||
# 分离购电和上网电量
|
||||
total_purchase = sum(-x for x in grid_feed_in if x < 0) # 购电量(正值)
|
||||
total_feed_in = sum(x for x in grid_feed_in if x > 0) # 上网电量(正值)
|
||||
|
||||
# 计算总交换电量(购电 + 上网)
|
||||
total_exchange = total_purchase + total_feed_in
|
||||
|
||||
return {
|
||||
'total_exchange': total_exchange,
|
||||
'grid_purchase': total_purchase,
|
||||
'grid_feed_in': total_feed_in,
|
||||
'storage_capacity': storage_result['required_storage_capacity'],
|
||||
'storage_result': storage_result
|
||||
}
|
||||
|
||||
|
||||
def optimize_solar_output(
|
||||
original_solar_output: List[float],
|
||||
wind_output: List[float],
|
||||
thermal_output: List[float],
|
||||
load_demand: List[float],
|
||||
params: SystemParameters,
|
||||
coefficient_range: Tuple[float, float] = (0.1, 2.0),
|
||||
tolerance: float = 0.01,
|
||||
max_iterations: int = 50
|
||||
) -> SolarOptimizationResult:
|
||||
"""
|
||||
优化光伏出力系数以最小化电网交换电量
|
||||
|
||||
Args:
|
||||
original_solar_output: 原始光伏出力曲线 (MW)
|
||||
wind_output: 风电出力曲线 (MW)
|
||||
thermal_output: 火电出力曲线 (MW)
|
||||
load_demand: 负荷曲线 (MW)
|
||||
params: 系统参数配置
|
||||
coefficient_range: 光伏系数搜索范围 (最小值, 最大值)
|
||||
tolerance: 收敛容差
|
||||
max_iterations: 最大迭代次数
|
||||
|
||||
Returns:
|
||||
光伏优化结果
|
||||
"""
|
||||
print("开始光伏出力优化...")
|
||||
|
||||
# 初始化优化历史
|
||||
optimization_history = []
|
||||
|
||||
# 使用黄金分割法进行一维优化
|
||||
phi = (1 + np.sqrt(5)) / 2 # 黄金比例
|
||||
resphi = 2 - phi
|
||||
|
||||
a, b = coefficient_range
|
||||
c = b - resphi * (b - a)
|
||||
d = a + resphi * (b - a)
|
||||
|
||||
# 计算初始点的目标函数值
|
||||
fc = calculate_grid_exchange_metric(
|
||||
[x * c for x in original_solar_output],
|
||||
wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
fd = calculate_grid_exchange_metric(
|
||||
[x * d for x in original_solar_output],
|
||||
wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 记录初始点
|
||||
optimization_history.append({
|
||||
'coefficient': c,
|
||||
'total_exchange': fc['total_exchange'],
|
||||
'grid_purchase': fc['grid_purchase'],
|
||||
'grid_feed_in': fc['grid_feed_in'],
|
||||
'storage_capacity': fc['storage_capacity']
|
||||
})
|
||||
|
||||
optimization_history.append({
|
||||
'coefficient': d,
|
||||
'total_exchange': fd['total_exchange'],
|
||||
'grid_purchase': fd['grid_purchase'],
|
||||
'grid_feed_in': fd['grid_feed_in'],
|
||||
'storage_capacity': fd['storage_capacity']
|
||||
})
|
||||
|
||||
# 黄金分割搜索
|
||||
for iteration in range(max_iterations):
|
||||
if abs(fc['total_exchange'] - fd['total_exchange']) < tolerance:
|
||||
break
|
||||
|
||||
if fc['total_exchange'] < fd['total_exchange']:
|
||||
b = d
|
||||
d = c
|
||||
fd = fc
|
||||
c = b - resphi * (b - a)
|
||||
|
||||
fc = calculate_grid_exchange_metric(
|
||||
[x * c for x in original_solar_output],
|
||||
wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
optimization_history.append({
|
||||
'coefficient': c,
|
||||
'total_exchange': fc['total_exchange'],
|
||||
'grid_purchase': fc['grid_purchase'],
|
||||
'grid_feed_in': fc['grid_feed_in'],
|
||||
'storage_capacity': fc['storage_capacity']
|
||||
})
|
||||
else:
|
||||
a = c
|
||||
c = d
|
||||
fc = fd
|
||||
d = a + resphi * (b - a)
|
||||
|
||||
fd = calculate_grid_exchange_metric(
|
||||
[x * d for x in original_solar_output],
|
||||
wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
optimization_history.append({
|
||||
'coefficient': d,
|
||||
'total_exchange': fd['total_exchange'],
|
||||
'grid_purchase': fd['grid_purchase'],
|
||||
'grid_feed_in': fd['grid_feed_in'],
|
||||
'storage_capacity': fd['storage_capacity']
|
||||
})
|
||||
|
||||
# 确定最优系数
|
||||
if fc['total_exchange'] < fd['total_exchange']:
|
||||
optimal_coefficient = c
|
||||
best_result = fc
|
||||
else:
|
||||
optimal_coefficient = d
|
||||
best_result = fd
|
||||
|
||||
# 生成优化后的光伏出力曲线
|
||||
optimized_solar_output = [x * optimal_coefficient for x in original_solar_output]
|
||||
|
||||
# 重新计算完整的最优储能配置
|
||||
final_storage_result = optimize_storage_capacity(
|
||||
optimized_solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
print(f"优化完成!最优光伏系数: {optimal_coefficient:.3f}")
|
||||
print(f"最小电网交换电量: {best_result['total_exchange']:.2f} MWh")
|
||||
|
||||
return SolarOptimizationResult(
|
||||
optimal_solar_coefficient=optimal_coefficient,
|
||||
original_solar_output=original_solar_output,
|
||||
optimized_solar_output=optimized_solar_output,
|
||||
min_grid_exchange=best_result['total_exchange'],
|
||||
grid_purchase=best_result['grid_purchase'],
|
||||
grid_feed_in=best_result['grid_feed_in'],
|
||||
storage_result=final_storage_result,
|
||||
optimization_history=optimization_history
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def export_optimization_results(result: SolarOptimizationResult, filename: str = None):
|
||||
"""
|
||||
导出光伏优化结果到Excel文件
|
||||
|
||||
Args:
|
||||
result: 光伏优化结果
|
||||
filename: 输出文件名,如果为None则自动生成
|
||||
"""
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
|
||||
if filename is None:
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"solar_optimization_results_{timestamp}.xlsx"
|
||||
|
||||
print(f"正在导出光伏优化结果到Excel文件: {filename}")
|
||||
|
||||
hours = list(range(1, len(result.original_solar_output) + 1))
|
||||
|
||||
# 创建主要数据DataFrame
|
||||
data_df = pd.DataFrame({
|
||||
'小时': hours,
|
||||
'原始光伏出力(MW)': result.original_solar_output,
|
||||
'优化后光伏出力(MW)': result.optimized_solar_output,
|
||||
'出力变化(MW)': [result.optimized_solar_output[i] - result.original_solar_output[i]
|
||||
for i in range(len(result.original_solar_output))],
|
||||
'变化比例(%)': [(result.optimized_solar_output[i] / result.original_solar_output[i] - 1) * 100
|
||||
if result.original_solar_output[i] > 0 else 0
|
||||
for i in range(len(result.original_solar_output))]
|
||||
})
|
||||
|
||||
# 创建优化结果摘要DataFrame
|
||||
summary_df = pd.DataFrame({
|
||||
'指标': [
|
||||
'最优光伏系数',
|
||||
'最小电网交换电量',
|
||||
'购电量',
|
||||
'上网电量',
|
||||
'所需储能容量',
|
||||
'优化后弃风率',
|
||||
'优化后弃光率',
|
||||
'优化后上网电量比例'
|
||||
],
|
||||
'数值': [
|
||||
f"{result.optimal_solar_coefficient:.3f}",
|
||||
f"{result.min_grid_exchange:.2f} MWh",
|
||||
f"{result.grid_purchase:.2f} MWh",
|
||||
f"{result.grid_feed_in:.2f} MWh",
|
||||
f"{result.storage_result['required_storage_capacity']:.2f} MWh",
|
||||
f"{result.storage_result['total_curtailment_wind_ratio']:.3f}",
|
||||
f"{result.storage_result['total_curtailment_solar_ratio']:.3f}",
|
||||
f"{result.storage_result['total_grid_feed_in_ratio']:.3f}"
|
||||
]
|
||||
})
|
||||
|
||||
# 创建优化历史DataFrame
|
||||
history_df = pd.DataFrame(result.optimization_history)
|
||||
history_df.columns = ['光伏系数', '电网交换电量(MWh)', '购电量(MWh)', '上网电量(MWh)', '储能容量(MWh)']
|
||||
|
||||
# 写入Excel文件
|
||||
with pd.ExcelWriter(filename, engine='openpyxl') as writer:
|
||||
# 写入主要数据
|
||||
data_df.to_excel(writer, sheet_name='出力曲线对比', index=False)
|
||||
|
||||
# 写入优化结果摘要
|
||||
summary_df.to_excel(writer, sheet_name='优化结果摘要', index=False)
|
||||
|
||||
# 写入优化历史
|
||||
history_df.to_excel(writer, sheet_name='优化历史', index=False)
|
||||
|
||||
# 创建说明工作表
|
||||
description_df = pd.DataFrame({
|
||||
'项目': [
|
||||
'文件说明',
|
||||
'生成时间',
|
||||
'优化目标',
|
||||
'优化方法',
|
||||
'数据长度',
|
||||
'注意事项'
|
||||
],
|
||||
'内容': [
|
||||
'光伏出力优化结果 - 通过调整光伏系数最小化电网交换电量',
|
||||
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
'最小化与电网交换的总电量(购电 + 上网)',
|
||||
'黄金分割一维优化算法',
|
||||
f"{len(result.original_solar_output)} 小时",
|
||||
'优化结果在给定的系统参数约束下得出'
|
||||
]
|
||||
})
|
||||
description_df.to_excel(writer, sheet_name='说明', index=False)
|
||||
|
||||
print(f"光伏优化结果已成功导出到: {filename}")
|
||||
return filename
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数,提供示例使用"""
|
||||
# 示例数据
|
||||
original_solar_output = [0.0] * 6 + [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0] + [0.0] * 6
|
||||
wind_output = [2.0, 3.0, 4.0, 3.0, 2.0, 1.0] * 4
|
||||
thermal_output = [5.0] * 24
|
||||
load_demand = [3.0, 4.0, 5.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 18.0,
|
||||
16.0, 14.0, 12.0, 10.0, 8.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 2.0]
|
||||
|
||||
# 系统参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.1,
|
||||
max_curtailment_solar=0.1,
|
||||
max_grid_ratio=0.2,
|
||||
storage_efficiency=0.9,
|
||||
discharge_rate=1.0,
|
||||
charge_rate=1.0,
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=100.0,
|
||||
rated_wind_capacity=100.0,
|
||||
available_thermal_energy=2400.0,
|
||||
available_solar_energy=600.0,
|
||||
available_wind_energy=1200.0
|
||||
)
|
||||
|
||||
# 执行光伏优化
|
||||
result = optimize_solar_output(
|
||||
original_solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 打印结果
|
||||
print("\n=== 光伏出力优化结果 ===")
|
||||
print(f"最优光伏系数: {result.optimal_solar_coefficient:.3f}")
|
||||
print(f"最小电网交换电量: {result.min_grid_exchange:.2f} MWh")
|
||||
print(f"其中购电量: {result.grid_purchase:.2f} MWh")
|
||||
print(f"其中上网电量: {result.grid_feed_in:.2f} MWh")
|
||||
print(f"所需储能容量: {result.storage_result['required_storage_capacity']:.2f} MWh")
|
||||
print(f"优化后弃风率: {result.storage_result['total_curtailment_wind_ratio']:.3f}")
|
||||
print(f"优化后弃光率: {result.storage_result['total_curtailment_solar_ratio']:.3f}")
|
||||
print(f"优化后上网电量比例: {result.storage_result['total_grid_feed_in_ratio']:.3f}")
|
||||
|
||||
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
537
solar_optimization_examples.py
Normal file
537
solar_optimization_examples.py
Normal file
@@ -0,0 +1,537 @@
|
||||
"""
|
||||
光伏优化模块场景示例
|
||||
|
||||
该文件展示了光伏优化模块在不同场景下的应用,包括:
|
||||
1. 典型日场景 - 基础优化示例
|
||||
2. 高负荷场景 - 夏季高峰用电场景
|
||||
3. 低负荷场景 - 春秋季低负荷场景
|
||||
4. 风光互补场景 - 风电和光伏协同优化
|
||||
5. 储能受限场景 - 储能容量受限情况下的优化
|
||||
|
||||
作者: iFlow CLI
|
||||
创建日期: 2025-12-26
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from typing import List, Dict
|
||||
from solar_optimization import optimize_solar_output, plot_optimization_results, export_optimization_results
|
||||
from storage_optimization import SystemParameters
|
||||
|
||||
|
||||
def scenario_1_typical_day():
|
||||
"""
|
||||
场景1:典型日场景
|
||||
- 标准24小时负荷曲线
|
||||
- 适中风光出力
|
||||
- 常规系统参数
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("场景1:典型日场景 - 基础优化示例")
|
||||
print("=" * 60)
|
||||
|
||||
# 典型日光伏出力(中午高峰)
|
||||
solar_output = [0.0] * 6 + [0.5, 1.0, 2.0, 3.5, 5.0, 6.0, 5.5, 4.0, 2.5, 1.0, 0.5, 0.0] + [0.0] * 6
|
||||
|
||||
# 典型日风电出力(夜间和早晨较高)
|
||||
wind_output = [4.0, 5.0, 4.5, 3.5, 2.5, 2.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.0, 3.0, 4.0, 5.0, 4.5, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0]
|
||||
|
||||
# 火电基础出力
|
||||
thermal_output = [8.0] * 24
|
||||
|
||||
# 典型日负荷曲线(早晚高峰)
|
||||
load_demand = [2.0, 2.5, 3.0, 4.0, 6.0, 9.0, 12.0, 15.0, 18.0, 20.0, 19.0, 18.0,
|
||||
17.0, 16.0, 18.0, 19.0, 20.0, 18.0, 15.0, 12.0, 8.0, 5.0, 3.0, 2.0]
|
||||
|
||||
# 标准系统参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.1,
|
||||
max_curtailment_solar=0.1,
|
||||
max_grid_ratio=0.15,
|
||||
storage_efficiency=0.9,
|
||||
discharge_rate=1.0,
|
||||
charge_rate=1.0,
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=50.0,
|
||||
rated_wind_capacity=50.0,
|
||||
available_thermal_energy=2000.0,
|
||||
available_solar_energy=400.0,
|
||||
available_wind_energy=600.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("典型日场景", result)
|
||||
|
||||
# 绘制结果
|
||||
plot_optimization_results(result, show_window=False)
|
||||
|
||||
# 导出结果
|
||||
filename = export_optimization_results(result, "scenario_1_typical_day.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_2_high_load():
|
||||
"""
|
||||
场景2:高负荷场景
|
||||
- 夏季高温,空调负荷高
|
||||
- 白天负荷特别高
|
||||
- 光伏出力与负荷匹配度较低
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("场景2:高负荷场景 - 夏季高峰用电")
|
||||
print("=" * 60)
|
||||
|
||||
# 夏季光伏出力(较强)
|
||||
solar_output = [0.0] * 5 + [0.8, 1.5, 3.0, 4.5, 6.0, 7.5, 8.0, 7.0, 5.0, 3.0, 1.5, 0.5, 0.0, 0.0] + [0.0] * 5
|
||||
|
||||
# 夏季风电出力(相对较低)
|
||||
wind_output = [2.0, 2.5, 3.0, 2.5, 2.0, 1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 2.0, 2.5, 3.0, 2.5, 2.0, 1.8, 1.6, 1.4, 1.2, 1.0, 0.8]
|
||||
|
||||
# 火电高峰出力
|
||||
thermal_output = [12.0] * 24
|
||||
|
||||
# 夏季高负荷曲线(空调导致白天负荷极高)
|
||||
load_demand = [3.0, 3.5, 4.0, 5.0, 8.0, 12.0, 18.0, 25.0, 30.0, 32.0, 31.0, 30.0,
|
||||
29.0, 28.0, 30.0, 31.0, 32.0, 28.0, 22.0, 18.0, 12.0, 8.0, 5.0, 3.0]
|
||||
|
||||
# 高负荷场景参数(更宽松的弃风弃光限制)
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.15,
|
||||
max_curtailment_solar=0.15,
|
||||
max_grid_ratio=0.25,
|
||||
storage_efficiency=0.85,
|
||||
discharge_rate=1.2,
|
||||
charge_rate=1.2,
|
||||
rated_thermal_capacity=150.0,
|
||||
rated_solar_capacity=80.0,
|
||||
rated_wind_capacity=40.0,
|
||||
available_thermal_energy=3000.0,
|
||||
available_solar_energy=600.0,
|
||||
available_wind_energy=400.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("高负荷场景", result)
|
||||
|
||||
# 绘制结果
|
||||
plot_optimization_results(result, show_window=False)
|
||||
|
||||
# 导出结果
|
||||
filename = export_optimization_results(result, "scenario_2_high_load.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_3_low_load():
|
||||
"""
|
||||
场景3:低负荷场景
|
||||
- 春秋季,负荷较低
|
||||
- 光伏出力相对较高
|
||||
- 容易出现电力盈余
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("场景3:低负荷场景 - 春秋季低负荷")
|
||||
print("=" * 60)
|
||||
|
||||
# 春秋季光伏出力(适中)
|
||||
solar_output = [0.0] * 6 + [1.0, 2.0, 3.5, 5.0, 6.5, 7.0, 6.5, 5.0, 3.5, 2.0, 1.0, 0.0] + [0.0] * 6
|
||||
|
||||
# 春秋季风电出力(较好)
|
||||
wind_output = [5.0, 6.0, 5.5, 4.5, 3.5, 3.0, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3.0, 4.0, 5.0, 6.0, 5.5, 5.0, 4.5, 4.0, 3.5, 3.0, 2.5, 2.0]
|
||||
|
||||
# 火电基础出力(较低)
|
||||
thermal_output = [5.0] * 24
|
||||
|
||||
# 春秋季低负荷曲线
|
||||
load_demand = [2.0, 2.2, 2.5, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 13.0, 12.5, 12.0,
|
||||
11.5, 11.0, 12.0, 12.5, 13.0, 11.0, 9.0, 7.0, 5.0, 3.5, 2.5, 2.0]
|
||||
|
||||
# 低负荷场景参数(更严格的弃风弃光限制)
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.05,
|
||||
max_curtailment_solar=0.05,
|
||||
max_grid_ratio=0.1,
|
||||
storage_efficiency=0.92,
|
||||
discharge_rate=0.8,
|
||||
charge_rate=0.8,
|
||||
rated_thermal_capacity=80.0,
|
||||
rated_solar_capacity=60.0,
|
||||
rated_wind_capacity=60.0,
|
||||
available_thermal_energy=1500.0,
|
||||
available_solar_energy=500.0,
|
||||
available_wind_energy=700.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("低负荷场景", result)
|
||||
|
||||
# 绘制结果
|
||||
plot_optimization_results(result, show_window=False)
|
||||
|
||||
# 导出结果
|
||||
filename = export_optimization_results(result, "scenario_3_low_load.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_4_wind_solar_complement():
|
||||
"""
|
||||
场景4:风光互补场景
|
||||
- 风电和光伏出力时间互补性强
|
||||
- 夜间风电高,白天光伏高
|
||||
- 系统整体平衡性较好
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("场景4:风光互补场景 - 风电和光伏协同优化")
|
||||
print("=" * 60)
|
||||
|
||||
# 光伏出力(标准日间模式)
|
||||
solar_output = [0.0] * 6 + [0.5, 1.5, 3.0, 4.5, 6.0, 7.0, 6.0, 4.5, 3.0, 1.5, 0.5, 0.0] + [0.0] * 6
|
||||
|
||||
# 风电出力(与光伏互补,夜间和早晚较高)
|
||||
wind_output = [8.0, 9.0, 8.5, 7.0, 5.0, 3.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 3.0, 5.0, 7.0, 8.0, 8.5, 8.0, 7.5, 7.0, 6.5, 6.0, 5.5, 5.0]
|
||||
|
||||
# 火电出力(作为补充)
|
||||
thermal_output = [6.0] * 24
|
||||
|
||||
# 负荷曲线(相对平稳)
|
||||
load_demand = [4.0, 4.5, 5.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 17.0, 16.5, 16.0,
|
||||
15.5, 15.0, 16.0, 16.5, 17.0, 15.0, 13.0, 11.0, 9.0, 7.0, 5.0, 4.0]
|
||||
|
||||
# 风光互补场景参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.08,
|
||||
max_curtailment_solar=0.08,
|
||||
max_grid_ratio=0.12,
|
||||
storage_efficiency=0.9,
|
||||
discharge_rate=1.0,
|
||||
charge_rate=1.0,
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=70.0,
|
||||
rated_wind_capacity=70.0,
|
||||
available_thermal_energy=1800.0,
|
||||
available_solar_energy=450.0,
|
||||
available_wind_energy=800.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("风光互补场景", result)
|
||||
|
||||
# 绘制结果
|
||||
plot_optimization_results(result, show_window=False)
|
||||
|
||||
# 导出结果
|
||||
filename = export_optimization_results(result, "scenario_4_wind_solar_complement.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_5_storage_limited():
|
||||
"""
|
||||
场景5:储能受限场景
|
||||
- 储能容量受限
|
||||
- 需要更精确的光伏出力调节
|
||||
- 对电网交换更敏感
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("场景5:储能受限场景 - 储能容量受限情况下的优化")
|
||||
print("=" * 60)
|
||||
|
||||
# 标准光伏出力
|
||||
solar_output = [0.0] * 6 + [1.0, 2.0, 3.0, 4.5, 6.0, 7.0, 6.0, 4.5, 3.0, 2.0, 1.0, 0.0] + [0.0] * 6
|
||||
|
||||
# 标准风电出力
|
||||
wind_output = [3.0, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.0, 3.0, 3.5, 4.0, 3.5, 3.0, 2.8, 2.6, 2.4, 2.2, 2.0, 1.8]
|
||||
|
||||
# 火电出力
|
||||
thermal_output = [7.0] * 24
|
||||
|
||||
# 标准负荷曲线
|
||||
load_demand = [3.0, 3.5, 4.0, 5.0, 7.0, 10.0, 13.0, 16.0, 18.0, 19.0, 18.5, 18.0,
|
||||
17.5, 17.0, 18.0, 18.5, 19.0, 17.0, 14.0, 11.0, 8.0, 6.0, 4.0, 3.0]
|
||||
|
||||
# 储能受限场景参数(储能容量限制为50MWh)
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.12,
|
||||
max_curtailment_solar=0.12,
|
||||
max_grid_ratio=0.2,
|
||||
storage_efficiency=0.88,
|
||||
discharge_rate=1.5,
|
||||
charge_rate=1.5,
|
||||
max_storage_capacity=50.0, # 储能容量受限
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=60.0,
|
||||
rated_wind_capacity=50.0,
|
||||
available_thermal_energy=2000.0,
|
||||
available_solar_energy=480.0,
|
||||
available_wind_energy=550.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(
|
||||
solar_output, wind_output, thermal_output, load_demand, params
|
||||
)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("储能受限场景", result)
|
||||
|
||||
# 绘制结果
|
||||
plot_optimization_results(result, show_window=False)
|
||||
|
||||
# 导出结果
|
||||
filename = export_optimization_results(result, "scenario_5_storage_limited.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def print_scenario_result(scenario_name: str, result):
|
||||
"""
|
||||
打印场景优化结果
|
||||
|
||||
Args:
|
||||
scenario_name: 场景名称
|
||||
result: 优化结果
|
||||
"""
|
||||
print(f"\n=== {scenario_name}优化结果 ===")
|
||||
print(f"最优光伏系数: {result.optimal_solar_coefficient:.3f}")
|
||||
print(f"最小电网交换电量: {result.min_grid_exchange:.2f} MWh")
|
||||
print(f" - 购电量: {result.grid_purchase:.2f} MWh")
|
||||
print(f" - 上网电量: {result.grid_feed_in:.2f} MWh")
|
||||
print(f"所需储能容量: {result.storage_result['required_storage_capacity']:.2f} MWh")
|
||||
print(f"优化后弃风率: {result.storage_result['total_curtailment_wind_ratio']:.3f}")
|
||||
print(f"优化后弃光率: {result.storage_result['total_curtailment_solar_ratio']:.3f}")
|
||||
print(f"优化后上网电量比例: {result.storage_result['total_grid_feed_in_ratio']:.3f}")
|
||||
|
||||
# 分析优化效果
|
||||
if result.optimal_solar_coefficient > 1.0:
|
||||
print(f"分析:建议将光伏出力提高 {(result.optimal_solar_coefficient - 1.0) * 100:.1f}% 以减少电网依赖")
|
||||
elif result.optimal_solar_coefficient < 1.0:
|
||||
print(f"分析:建议将光伏出力降低 {(1.0 - result.optimal_solar_coefficient) * 100:.1f}% 以避免电力过剩")
|
||||
else:
|
||||
print("分析:当前光伏出力已经是最优配置")
|
||||
|
||||
|
||||
def compare_scenarios(results: List[Dict]):
|
||||
"""
|
||||
对比不同场景的优化结果
|
||||
|
||||
Args:
|
||||
results: 各场景优化结果列表
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("场景对比分析")
|
||||
print("=" * 80)
|
||||
|
||||
scenario_names = [
|
||||
"典型日场景",
|
||||
"高负荷场景",
|
||||
"低负荷场景",
|
||||
"风光互补场景",
|
||||
"储能受限场景"
|
||||
]
|
||||
|
||||
# 创建对比表格
|
||||
print(f"{'场景名称':<12} {'最优系数':<8} {'电网交换(MWh)':<12} {'购电量(MWh)':<10} {'上网电量(MWh)':<12} {'储能容量(MWh)':<12}")
|
||||
print("-" * 80)
|
||||
|
||||
for i, (name, result) in enumerate(zip(scenario_names, results)):
|
||||
print(f"{name:<12} {result.optimal_solar_coefficient:<8.3f} "
|
||||
f"{result.min_grid_exchange:<12.2f} {result.grid_purchase:<10.2f} "
|
||||
f"{result.grid_feed_in:<12.2f} {result.storage_result['required_storage_capacity']:<12.2f}")
|
||||
|
||||
# 分析趋势
|
||||
print("\n=== 趋势分析 ===")
|
||||
|
||||
# 找出最优和最差场景
|
||||
min_exchange_result = min(results, key=lambda x: x.min_grid_exchange)
|
||||
max_exchange_result = max(results, key=lambda x: x.min_grid_exchange)
|
||||
|
||||
min_exchange_idx = results.index(min_exchange_result)
|
||||
max_exchange_idx = results.index(max_exchange_result)
|
||||
|
||||
print(f"电网交换最小场景:{scenario_names[min_exchange_idx]} ({min_exchange_result.min_grid_exchange:.2f} MWh)")
|
||||
print(f"电网交换最大场景:{scenario_names[max_exchange_idx]} ({max_exchange_result.min_grid_exchange:.2f} MWh)")
|
||||
|
||||
# 分析光伏系数趋势
|
||||
avg_coefficient = sum(r.optimal_solar_coefficient for r in results) / len(results)
|
||||
print(f"平均最优光伏系数:{avg_coefficient:.3f}")
|
||||
|
||||
high_coefficient_scenarios = [name for name, result in zip(scenario_names, results)
|
||||
if result.optimal_solar_coefficient > avg_coefficient]
|
||||
low_coefficient_scenarios = [name for name, result in zip(scenario_names, results)
|
||||
if result.optimal_solar_coefficient < avg_coefficient]
|
||||
|
||||
if high_coefficient_scenarios:
|
||||
print(f"需要提高光伏出力的场景:{', '.join(high_coefficient_scenarios)}")
|
||||
if low_coefficient_scenarios:
|
||||
print(f"需要降低光伏出力的场景:{', '.join(low_coefficient_scenarios)}")
|
||||
|
||||
|
||||
def plot_scenario_comparison(results: List[Dict]):
|
||||
"""
|
||||
绘制场景对比图表
|
||||
|
||||
Args:
|
||||
results: 各场景优化结果列表
|
||||
"""
|
||||
scenario_names = [
|
||||
"典型日",
|
||||
"高负荷",
|
||||
"低负荷",
|
||||
"风光互补",
|
||||
"储能受限"
|
||||
]
|
||||
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
# 创建图形
|
||||
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
|
||||
fig.suptitle('光伏优化场景对比分析', fontsize=16, fontweight='bold')
|
||||
|
||||
# 1. 最优光伏系数对比
|
||||
coefficients = [r.optimal_solar_coefficient for r in results]
|
||||
bars1 = ax1.bar(scenario_names, coefficients, color='skyblue', alpha=0.7)
|
||||
ax1.set_ylabel('最优光伏系数')
|
||||
ax1.set_title('各场景最优光伏系数对比')
|
||||
ax1.grid(True, alpha=0.3, axis='y')
|
||||
ax1.axhline(y=1.0, color='red', linestyle='--', alpha=0.7, label='原始系数')
|
||||
|
||||
# 添加数值标签
|
||||
for bar, coeff in zip(bars1, coefficients):
|
||||
height = bar.get_height()
|
||||
ax1.text(bar.get_x() + bar.get_width()/2., height + 0.01,
|
||||
f'{coeff:.3f}', ha='center', va='bottom', fontweight='bold')
|
||||
|
||||
# 2. 电网交换电量对比
|
||||
exchanges = [r.min_grid_exchange for r in results]
|
||||
purchases = [r.grid_purchase for r in results]
|
||||
feed_ins = [r.grid_feed_in for r in results]
|
||||
|
||||
x = np.arange(len(scenario_names))
|
||||
width = 0.25
|
||||
|
||||
bars2 = ax2.bar(x - width, purchases, width, label='购电量', color='purple', alpha=0.7)
|
||||
bars3 = ax2.bar(x, feed_ins, width, label='上网电量', color='brown', alpha=0.7)
|
||||
bars4 = ax2.bar(x + width, exchanges, width, label='总交换电量', color='orange', alpha=0.7)
|
||||
|
||||
ax2.set_ylabel('电量 (MWh)')
|
||||
ax2.set_title('电网交换电量对比')
|
||||
ax2.set_xticks(x)
|
||||
ax2.set_xticklabels(scenario_names)
|
||||
ax2.legend()
|
||||
ax2.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 3. 储能容量需求对比
|
||||
storage_capacities = [r.storage_result['required_storage_capacity'] for r in results]
|
||||
bars5 = ax3.bar(scenario_names, storage_capacities, color='green', alpha=0.7)
|
||||
ax3.set_ylabel('储能容量 (MWh)')
|
||||
ax3.set_title('各场景储能容量需求对比')
|
||||
ax3.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 添加数值标签
|
||||
for bar, capacity in zip(bars5, storage_capacities):
|
||||
height = bar.get_height()
|
||||
ax3.text(bar.get_x() + bar.get_width()/2., height + height*0.01,
|
||||
f'{capacity:.1f}', ha='center', va='bottom', fontweight='bold')
|
||||
|
||||
# 4. 弃风弃光率对比
|
||||
curtailment_winds = [r.storage_result['total_curtailment_wind_ratio'] for r in results]
|
||||
curtailment_solars = [r.storage_result['total_curtailment_solar_ratio'] for r in results]
|
||||
|
||||
bars6 = ax4.bar(x - width/2, curtailment_winds, width, label='弃风率', color='blue', alpha=0.7)
|
||||
bars7 = ax4.bar(x + width/2, curtailment_solars, width, label='弃光率', color='orange', alpha=0.7)
|
||||
|
||||
ax4.set_ylabel('弃风弃光率')
|
||||
ax4.set_title('各场景弃风弃光率对比')
|
||||
ax4.set_xticks(x)
|
||||
ax4.set_xticklabels(scenario_names)
|
||||
ax4.legend()
|
||||
ax4.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 调整布局
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存图片
|
||||
plt.savefig('solar_optimization_scenario_comparison.png', dpi=300, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
print("场景对比图表已保存为 'solar_optimization_scenario_comparison.png'")
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数,运行所有场景示例"""
|
||||
print("光伏优化模块场景示例")
|
||||
print("运行5个不同场景的优化分析...")
|
||||
|
||||
# 运行所有场景
|
||||
results = []
|
||||
|
||||
try:
|
||||
# 场景1:典型日场景
|
||||
result1 = scenario_1_typical_day()
|
||||
results.append(result1)
|
||||
|
||||
# 场景2:高负荷场景
|
||||
result2 = scenario_2_high_load()
|
||||
results.append(result2)
|
||||
|
||||
# 场景3:低负荷场景
|
||||
result3 = scenario_3_low_load()
|
||||
results.append(result3)
|
||||
|
||||
# 场景4:风光互补场景
|
||||
result4 = scenario_4_wind_solar_complement()
|
||||
results.append(result4)
|
||||
|
||||
# 场景5:储能受限场景
|
||||
result5 = scenario_5_storage_limited()
|
||||
results.append(result5)
|
||||
|
||||
# 对比分析
|
||||
compare_scenarios(results)
|
||||
|
||||
# 绘制对比图表
|
||||
plot_scenario_comparison(results)
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print("所有场景示例运行完成!")
|
||||
print("=" * 80)
|
||||
print("生成的文件:")
|
||||
print("- scenario_1_typical_day.xlsx")
|
||||
print("- scenario_2_high_load.xlsx")
|
||||
print("- scenario_3_low_load.xlsx")
|
||||
print("- scenario_4_wind_solar_complement.xlsx")
|
||||
print("- scenario_5_storage_limited.xlsx")
|
||||
print("- solar_optimization_scenario_comparison.png")
|
||||
|
||||
except Exception as e:
|
||||
print(f"运行场景示例时出错:{str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
414
solar_scenarios_demo.py
Normal file
414
solar_scenarios_demo.py
Normal file
@@ -0,0 +1,414 @@
|
||||
"""
|
||||
光伏优化模块场景演示
|
||||
|
||||
该文件展示了光伏优化模块在不同场景下的应用,包括:
|
||||
1. 典型日场景 - 基础优化示例
|
||||
2. 高负荷场景 - 夏季高峰用电场景
|
||||
3. 低负荷场景 - 春秋季低负荷场景
|
||||
4. 风光互补场景 - 风电和光伏协同优化
|
||||
5. 储能受限场景 - 储能容量受限情况下的优化
|
||||
|
||||
作者: iFlow CLI
|
||||
创建日期: 2025-12-26
|
||||
"""
|
||||
|
||||
from solar_optimization import optimize_solar_output, export_optimization_results
|
||||
import matplotlib.pyplot as plt
|
||||
from storage_optimization import SystemParameters
|
||||
|
||||
|
||||
def scenario_1_typical_day():
|
||||
"""场景1:典型日场景"""
|
||||
print("=" * 60)
|
||||
print("场景1:典型日场景 - 基础优化示例")
|
||||
print("=" * 60)
|
||||
|
||||
# 典型日数据(24小时)
|
||||
solar_output = [0.0] * 6 + [0.5, 1.0, 2.0, 3.5, 5.0, 6.0, 5.5, 4.0, 2.5, 1.0, 0.5, 0.0] + [0.0] * 6
|
||||
wind_output = [4.0, 5.0, 4.5, 3.5, 2.5, 2.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.0, 3.0, 4.0, 5.0, 4.5, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0]
|
||||
thermal_output = [8.0] * 24
|
||||
load_demand = [2.0, 2.5, 3.0, 4.0, 6.0, 9.0, 12.0, 15.0, 18.0, 20.0, 19.0, 18.0,
|
||||
17.0, 16.0, 18.0, 19.0, 20.0, 18.0, 15.0, 12.0, 8.0, 5.0, 3.0, 2.0]
|
||||
|
||||
# 系统参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.1,
|
||||
max_curtailment_solar=0.1,
|
||||
max_grid_ratio=0.15,
|
||||
storage_efficiency=0.9,
|
||||
discharge_rate=1.0,
|
||||
charge_rate=1.0,
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=50.0,
|
||||
rated_wind_capacity=50.0,
|
||||
available_thermal_energy=2000.0,
|
||||
available_solar_energy=400.0,
|
||||
available_wind_energy=600.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(solar_output, wind_output, thermal_output, load_demand, params)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("典型日场景", result)
|
||||
|
||||
# 绘制光伏对比图
|
||||
plot_solar_comparison(result, "典型日场景")
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result, "scenario_1_typical_day.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_2_high_load():
|
||||
"""场景2:高负荷场景"""
|
||||
print("=" * 60)
|
||||
print("场景2:高负荷场景 - 夏季高峰用电")
|
||||
print("=" * 60)
|
||||
|
||||
# 夏季高负荷数据
|
||||
solar_output = [0.0] * 5 + [0.8, 1.5, 3.0, 4.5, 6.0, 7.5, 8.0, 7.0, 5.0, 3.0, 1.5, 0.5, 0.0, 0.0] + [0.0] * 5
|
||||
wind_output = [2.0, 2.5, 3.0, 2.5, 2.0, 1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 2.0, 2.5, 3.0, 2.5, 2.0, 1.8, 1.6, 1.4, 1.2, 1.0, 0.8]
|
||||
thermal_output = [12.0] * 24
|
||||
load_demand = [3.0, 3.5, 4.0, 5.0, 8.0, 12.0, 18.0, 25.0, 30.0, 32.0, 31.0, 30.0,
|
||||
29.0, 28.0, 30.0, 31.0, 32.0, 28.0, 22.0, 18.0, 12.0, 8.0, 5.0, 3.0]
|
||||
|
||||
# 高负荷场景参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.15,
|
||||
max_curtailment_solar=0.15,
|
||||
max_grid_ratio=0.25,
|
||||
storage_efficiency=0.85,
|
||||
discharge_rate=1.2,
|
||||
charge_rate=1.2,
|
||||
rated_thermal_capacity=150.0,
|
||||
rated_solar_capacity=80.0,
|
||||
rated_wind_capacity=40.0,
|
||||
available_thermal_energy=3000.0,
|
||||
available_solar_energy=600.0,
|
||||
available_wind_energy=400.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(solar_output, wind_output, thermal_output, load_demand, params)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("高负荷场景", result)
|
||||
|
||||
# 绘制光伏对比图
|
||||
plot_solar_comparison(result, "高负荷场景")
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result, "scenario_2_high_load.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_3_low_load():
|
||||
"""场景3:低负荷场景"""
|
||||
print("=" * 60)
|
||||
print("场景3:低负荷场景 - 春秋季低负荷")
|
||||
print("=" * 60)
|
||||
|
||||
# 春秋季低负荷数据
|
||||
solar_output = [0.0] * 6 + [1.0, 2.0, 3.5, 5.0, 6.5, 7.0, 6.5, 5.0, 3.5, 2.0, 1.0, 0.0] + [0.0] * 6
|
||||
wind_output = [5.0, 6.0, 5.5, 4.5, 3.5, 3.0, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3.0, 4.0, 5.0, 6.0, 5.5, 5.0, 4.5, 4.0, 3.5, 3.0, 2.5, 2.0]
|
||||
thermal_output = [5.0] * 24
|
||||
load_demand = [2.0, 2.2, 2.5, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 13.0, 12.5, 12.0,
|
||||
11.5, 11.0, 12.0, 12.5, 13.0, 11.0, 9.0, 7.0, 5.0, 3.5, 2.5, 2.0]
|
||||
|
||||
# 低负荷场景参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.05,
|
||||
max_curtailment_solar=0.05,
|
||||
max_grid_ratio=0.1,
|
||||
storage_efficiency=0.92,
|
||||
discharge_rate=0.8,
|
||||
charge_rate=0.8,
|
||||
rated_thermal_capacity=80.0,
|
||||
rated_solar_capacity=60.0,
|
||||
rated_wind_capacity=60.0,
|
||||
available_thermal_energy=1500.0,
|
||||
available_solar_energy=500.0,
|
||||
available_wind_energy=700.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(solar_output, wind_output, thermal_output, load_demand, params)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("低负荷场景", result)
|
||||
|
||||
# 绘制光伏对比图
|
||||
plot_solar_comparison(result, "低负荷场景")
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result, "scenario_3_low_load.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_4_wind_solar_complement():
|
||||
"""场景4:风光互补场景"""
|
||||
print("=" * 60)
|
||||
print("场景4:风光互补场景 - 风电和光伏协同优化")
|
||||
print("=" * 60)
|
||||
|
||||
# 风光互补数据
|
||||
solar_output = [0.0] * 6 + [0.5, 1.5, 3.0, 4.5, 6.0, 7.0, 6.0, 4.5, 3.0, 1.5, 0.5, 0.0] + [0.0] * 6
|
||||
wind_output = [8.0, 9.0, 8.5, 7.0, 5.0, 3.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 3.0, 5.0, 7.0, 8.0, 8.5, 8.0, 7.5, 7.0, 6.5, 6.0, 5.5, 5.0]
|
||||
thermal_output = [6.0] * 24
|
||||
load_demand = [4.0, 4.5, 5.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 17.0, 16.5, 16.0,
|
||||
15.5, 15.0, 16.0, 16.5, 17.0, 15.0, 13.0, 11.0, 9.0, 7.0, 5.0, 4.0]
|
||||
|
||||
# 风光互补场景参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.08,
|
||||
max_curtailment_solar=0.08,
|
||||
max_grid_ratio=0.12,
|
||||
storage_efficiency=0.9,
|
||||
discharge_rate=1.0,
|
||||
charge_rate=1.0,
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=70.0,
|
||||
rated_wind_capacity=70.0,
|
||||
available_thermal_energy=1800.0,
|
||||
available_solar_energy=450.0,
|
||||
available_wind_energy=800.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(solar_output, wind_output, thermal_output, load_demand, params)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("风光互补场景", result)
|
||||
|
||||
# 绘制光伏对比图
|
||||
plot_solar_comparison(result, "风光互补场景")
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result, "scenario_4_wind_solar_complement.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scenario_5_storage_limited():
|
||||
"""场景5:储能受限场景"""
|
||||
print("=" * 60)
|
||||
print("场景5:储能受限场景 - 储能容量受限情况下的优化")
|
||||
print("=" * 60)
|
||||
|
||||
# 储能受限数据
|
||||
solar_output = [0.0] * 6 + [1.0, 2.0, 3.0, 4.5, 6.0, 7.0, 6.0, 4.5, 3.0, 2.0, 1.0, 0.0] + [0.0] * 6
|
||||
wind_output = [3.0, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.0, 3.0, 3.5, 4.0, 3.5, 3.0, 2.8, 2.6, 2.4, 2.2, 2.0, 1.8]
|
||||
thermal_output = [7.0] * 24
|
||||
load_demand = [3.0, 3.5, 4.0, 5.0, 7.0, 10.0, 13.0, 16.0, 18.0, 19.0, 18.5, 18.0,
|
||||
17.5, 17.0, 18.0, 18.5, 19.0, 17.0, 14.0, 11.0, 8.0, 6.0, 4.0, 3.0]
|
||||
|
||||
# 储能受限场景参数
|
||||
params = SystemParameters(
|
||||
max_curtailment_wind=0.12,
|
||||
max_curtailment_solar=0.12,
|
||||
max_grid_ratio=0.2,
|
||||
storage_efficiency=0.88,
|
||||
discharge_rate=1.5,
|
||||
charge_rate=1.5,
|
||||
max_storage_capacity=50.0, # 储能容量受限
|
||||
rated_thermal_capacity=100.0,
|
||||
rated_solar_capacity=60.0,
|
||||
rated_wind_capacity=50.0,
|
||||
available_thermal_energy=2000.0,
|
||||
available_solar_energy=480.0,
|
||||
available_wind_energy=550.0
|
||||
)
|
||||
|
||||
# 执行优化
|
||||
result = optimize_solar_output(solar_output, wind_output, thermal_output, load_demand, params)
|
||||
|
||||
# 输出结果
|
||||
print_scenario_result("储能受限场景", result)
|
||||
|
||||
# 绘制光伏对比图
|
||||
plot_solar_comparison(result, "储能受限场景")
|
||||
|
||||
# 导出结果
|
||||
export_optimization_results(result, "scenario_5_storage_limited.xlsx")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def print_scenario_result(scenario_name: str, result):
|
||||
"""打印场景优化结果"""
|
||||
print(f"\n=== {scenario_name}优化结果 ===")
|
||||
print(f"最优光伏系数: {result.optimal_solar_coefficient:.3f}")
|
||||
print(f"最小电网交换电量: {result.min_grid_exchange:.2f} MWh")
|
||||
print(f" - 购电量: {result.grid_purchase:.2f} MWh")
|
||||
print(f" - 上网电量: {result.grid_feed_in:.2f} MWh")
|
||||
print(f"所需储能容量: {result.storage_result['required_storage_capacity']:.2f} MWh")
|
||||
print(f"优化后弃风率: {result.storage_result['total_curtailment_wind_ratio']:.3f}")
|
||||
print(f"优化后弃光率: {result.storage_result['total_curtailment_solar_ratio']:.3f}")
|
||||
print(f"优化后上网电量比例: {result.storage_result['total_grid_feed_in_ratio']:.3f}")
|
||||
|
||||
# 分析优化效果
|
||||
if result.optimal_solar_coefficient > 1.0:
|
||||
print(f"分析:建议将光伏出力提高 {(result.optimal_solar_coefficient - 1.0) * 100:.1f}% 以减少电网依赖")
|
||||
elif result.optimal_solar_coefficient < 1.0:
|
||||
print(f"分析:建议将光伏出力降低 {(1.0 - result.optimal_solar_coefficient) * 100:.1f}% 以避免电力过剩")
|
||||
else:
|
||||
print("分析:当前光伏出力已经是最优配置")
|
||||
|
||||
|
||||
def plot_solar_comparison(result, scenario_name, show_window=True):
|
||||
"""
|
||||
绘制光伏出力对比图
|
||||
|
||||
Args:
|
||||
result: 光伏优化结果
|
||||
scenario_name: 场景名称
|
||||
show_window: 是否显示图形窗口
|
||||
"""
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
hours = list(range(len(result.original_solar_output)))
|
||||
|
||||
# 创建图形
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
|
||||
fig.suptitle(f'{scenario_name} - 光伏优化结果 (系数: {result.optimal_solar_coefficient:.3f})',
|
||||
fontsize=14, fontweight='bold')
|
||||
|
||||
# === 第一个子图:光伏出力对比 ===
|
||||
ax1.plot(hours, result.original_solar_output, 'b-', linewidth=2,
|
||||
label='原始光伏出力', alpha=0.7)
|
||||
ax1.plot(hours, result.optimized_solar_output, 'r-', linewidth=2,
|
||||
label=f'优化后光伏出力')
|
||||
|
||||
ax1.set_xlabel('时间 (小时)')
|
||||
ax1.set_ylabel('功率 (MW)')
|
||||
ax1.set_title('光伏出力曲线对比')
|
||||
ax1.legend(loc='upper right')
|
||||
ax1.grid(True, alpha=0.3)
|
||||
ax1.set_xlim(0, max(hours))
|
||||
|
||||
# === 第二个子图:电网交换电量组成 ===
|
||||
categories = ['购电量', '上网电量']
|
||||
values = [result.grid_purchase, result.grid_feed_in]
|
||||
colors = ['purple', 'brown']
|
||||
|
||||
bars = ax2.bar(categories, values, color=colors, alpha=0.7)
|
||||
ax2.set_ylabel('电量 (MWh)')
|
||||
ax2.set_title(f'电网交换电量组成 (总计: {result.min_grid_exchange:.2f} MWh)')
|
||||
ax2.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 在柱状图上添加数值标签
|
||||
for bar, value in zip(bars, values):
|
||||
height = bar.get_height()
|
||||
ax2.text(bar.get_x() + bar.get_width()/2., height + height*0.01,
|
||||
f'{value:.2f}', ha='center', va='bottom', fontweight='bold')
|
||||
|
||||
# 调整布局
|
||||
plt.tight_layout()
|
||||
|
||||
# 根据参数决定是否显示图形窗口
|
||||
if show_window:
|
||||
try:
|
||||
plt.show()
|
||||
except Exception as e:
|
||||
print(f"无法显示图形窗口:{str(e)}")
|
||||
else:
|
||||
plt.close()
|
||||
|
||||
|
||||
def compare_scenarios(results):
|
||||
"""对比不同场景的优化结果"""
|
||||
print("\n" + "=" * 80)
|
||||
print("场景对比分析")
|
||||
print("=" * 80)
|
||||
|
||||
scenario_names = [
|
||||
"典型日场景",
|
||||
"高负荷场景",
|
||||
"低负荷场景",
|
||||
"风光互补场景",
|
||||
"储能受限场景"
|
||||
]
|
||||
|
||||
# 创建对比表格
|
||||
print(f"{'场景名称':<12} {'最优系数':<8} {'电网交换(MWh)':<12} {'购电量(MWh)':<10} {'上网电量(MWh)':<12} {'储能容量(MWh)':<12}")
|
||||
print("-" * 80)
|
||||
|
||||
for i, (name, result) in enumerate(zip(scenario_names, results)):
|
||||
print(f"{name:<12} {result.optimal_solar_coefficient:<8.3f} "
|
||||
f"{result.min_grid_exchange:<12.2f} {result.grid_purchase:<10.2f} "
|
||||
f"{result.grid_feed_in:<12.2f} {result.storage_result['required_storage_capacity']:<12.2f}")
|
||||
|
||||
# 分析趋势
|
||||
print("\n=== 趋势分析 ===")
|
||||
|
||||
# 找出最优和最差场景
|
||||
min_exchange_result = min(results, key=lambda x: x.min_grid_exchange)
|
||||
max_exchange_result = max(results, key=lambda x: x.min_grid_exchange)
|
||||
|
||||
min_exchange_idx = results.index(min_exchange_result)
|
||||
max_exchange_idx = results.index(max_exchange_result)
|
||||
|
||||
print(f"电网交换最小场景:{scenario_names[min_exchange_idx]} ({min_exchange_result.min_grid_exchange:.2f} MWh)")
|
||||
print(f"电网交换最大场景:{scenario_names[max_exchange_idx]} ({max_exchange_result.min_grid_exchange:.2f} MWh)")
|
||||
|
||||
# 分析光伏系数趋势
|
||||
avg_coefficient = sum(r.optimal_solar_coefficient for r in results) / len(results)
|
||||
print(f"平均最优光伏系数:{avg_coefficient:.3f}")
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数,运行所有场景示例"""
|
||||
print("光伏优化模块场景演示")
|
||||
print("运行5个不同场景的优化分析...")
|
||||
|
||||
# 运行所有场景
|
||||
results = []
|
||||
|
||||
try:
|
||||
# 场景1:典型日场景
|
||||
result1 = scenario_1_typical_day()
|
||||
results.append(result1)
|
||||
|
||||
# 场景2:高负荷场景
|
||||
result2 = scenario_2_high_load()
|
||||
results.append(result2)
|
||||
|
||||
# 场景3:低负荷场景
|
||||
result3 = scenario_3_low_load()
|
||||
results.append(result3)
|
||||
|
||||
# 场景4:风光互补场景
|
||||
result4 = scenario_4_wind_solar_complement()
|
||||
results.append(result4)
|
||||
|
||||
# 场景5:储能受限场景
|
||||
result5 = scenario_5_storage_limited()
|
||||
results.append(result5)
|
||||
|
||||
# 对比分析
|
||||
compare_scenarios(results)
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print("所有场景演示完成!")
|
||||
print("=" * 80)
|
||||
print("生成的文件:")
|
||||
print("- scenario_1_typical_day.xlsx")
|
||||
print("- scenario_2_high_load.xlsx")
|
||||
print("- scenario_3_low_load.xlsx")
|
||||
print("- scenario_4_wind_solar_complement.xlsx")
|
||||
print("- scenario_5_storage_limited.xlsx")
|
||||
|
||||
except Exception as e:
|
||||
print(f"运行场景演示时出错:{str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -144,7 +144,22 @@ def calculate_energy_balance(
|
||||
total_potential_wind = np.sum(wind)
|
||||
total_potential_solar = np.sum(solar)
|
||||
|
||||
# 判断是否只有一种可再生能源
|
||||
has_wind = total_potential_wind > 0
|
||||
has_solar = total_potential_solar > 0
|
||||
single_renewable = (has_wind and not has_solar) or (has_solar and not has_wind)
|
||||
|
||||
# 计算允许的最大弃风弃光量
|
||||
if single_renewable:
|
||||
# 只有一种可再生能源时,弃电量不受限制
|
||||
max_curtailed_wind_total = float('inf')
|
||||
max_curtailed_solar_total = float('inf')
|
||||
elif params.max_grid_ratio == 0:
|
||||
# 上网电量限制为0时,所有超额电力都必须被弃掉,不受弃风弃光限制
|
||||
max_curtailed_wind_total = float('inf')
|
||||
max_curtailed_solar_total = float('inf')
|
||||
else:
|
||||
# 有多种可再生能源且上网电量限制不为0时,应用弃风弃光限制
|
||||
max_curtailed_wind_total = total_potential_wind * params.max_curtailment_wind
|
||||
max_curtailed_solar_total = total_potential_solar * params.max_curtailment_solar
|
||||
|
||||
@@ -206,7 +221,27 @@ def calculate_energy_balance(
|
||||
|
||||
# 计算弃风弃光(优先弃光,然后弃风)
|
||||
if remaining_surplus > 0:
|
||||
# 在单一可再生能源场景下,弃风弃光不受限制
|
||||
if single_renewable:
|
||||
# 优先弃光
|
||||
if solar[hour] > 0:
|
||||
curtailed_solar[hour] = min(solar[hour], remaining_surplus)
|
||||
remaining_surplus -= curtailed_solar[hour]
|
||||
accumulated_curtailed_solar += curtailed_solar[hour]
|
||||
|
||||
# 如果还有剩余,弃风
|
||||
if remaining_surplus > 0 and wind[hour] > 0:
|
||||
curtailed_wind[hour] = min(wind[hour], remaining_surplus)
|
||||
remaining_surplus -= curtailed_wind[hour]
|
||||
accumulated_curtailed_wind += curtailed_wind[hour]
|
||||
else:
|
||||
# 混合可再生能源场景,弃风弃光受限制
|
||||
# 计算当前可弃光量
|
||||
if max_curtailed_solar_total == float('inf'):
|
||||
# 无限制弃光
|
||||
available_solar_curtail = solar[hour]
|
||||
else:
|
||||
# 受限制弃光
|
||||
available_solar_curtail = min(
|
||||
solar[hour],
|
||||
max_curtailed_solar_total - accumulated_curtailed_solar
|
||||
@@ -219,6 +254,11 @@ def calculate_energy_balance(
|
||||
|
||||
# 如果还有剩余,弃风
|
||||
if remaining_surplus > 0:
|
||||
if max_curtailed_wind_total == float('inf'):
|
||||
# 无限制弃风
|
||||
available_wind_curtail = wind[hour]
|
||||
else:
|
||||
# 受限制弃风
|
||||
available_wind_curtail = min(
|
||||
wind[hour],
|
||||
max_curtailed_wind_total - accumulated_curtailed_wind
|
||||
@@ -229,6 +269,12 @@ def calculate_energy_balance(
|
||||
remaining_surplus -= curtailed_wind[hour]
|
||||
accumulated_curtailed_wind += curtailed_wind[hour]
|
||||
|
||||
# 确保电力平衡:如果仍有剩余电力,强制弃掉(安全机制)
|
||||
if remaining_surplus > 0:
|
||||
# 记录警告但不影响计算
|
||||
# 在实际系统中,这种情况不应该发生,但作为安全保护
|
||||
pass
|
||||
|
||||
else:
|
||||
# 电力不足,优先放电
|
||||
power_deficit = -power_surplus
|
||||
@@ -376,6 +422,20 @@ def optimize_storage_capacity(
|
||||
# 没有上网电量或为负值(购电),总是满足约束
|
||||
grid_constraint_satisfied = True
|
||||
|
||||
# 判断是否只有一种可再生能源
|
||||
has_wind = sum(wind_output) > 0
|
||||
has_solar = sum(solar_output) > 0
|
||||
single_renewable = (has_wind and not has_solar) or (has_solar and not has_wind)
|
||||
|
||||
# 特殊情况:当上网电量限制为0时,所有超额电力都必须被弃掉
|
||||
# 此时应该允许无限制弃风弃光
|
||||
grid_quota_zero = params.max_grid_ratio == 0
|
||||
|
||||
if single_renewable or grid_quota_zero:
|
||||
# 只有一种可再生能源时,或上网电量限制为0时,跳过弃风弃光约束检查
|
||||
constraints_satisfied = grid_constraint_satisfied
|
||||
else:
|
||||
# 有多种可再生能源且上网电量限制不为0时,检查所有约束
|
||||
constraints_satisfied = (
|
||||
constraint_results['total_curtailment_wind_ratio'] <= params.max_curtailment_wind and
|
||||
constraint_results['total_curtailment_solar_ratio'] <= params.max_curtailment_solar and
|
||||
|
||||
Reference in New Issue
Block a user