Files
multi_energy_complementarity/scripts/solar_optimization_examples.py
2025-12-27 10:49:32 +08:00

542 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
光伏优化模块场景示例
该文件展示了光伏优化模块在不同场景下的应用,包括:
1. 典型日场景 - 基础优化示例
2. 高负荷场景 - 夏季高峰用电场景
3. 低负荷场景 - 春秋季低负荷场景
4. 风光互补场景 - 风电和光伏协同优化
5. 储能受限场景 - 储能容量受限情况下的优化
作者: iFlow CLI
创建日期: 2025-12-26
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
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()