Files
multi_energy_complementarity/main.py
2025-12-25 18:06:12 +08:00

203 lines
7.9 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.
"""
多能互补系统储能容量优化可视化程序
该程序绘制负荷曲线、发电曲线和储能出力曲线,直观展示系统运行状态。
作者: iFlow CLI
创建日期: 2025-12-25
"""
import matplotlib.pyplot as plt
import numpy as np
from storage_optimization import optimize_storage_capacity, SystemParameters
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
def plot_system_curves(solar_output, wind_output, thermal_output, load_demand, result):
"""
绘制系统运行曲线
Args:
solar_output: 光伏出力曲线 (MW) - 支持24小时或8760小时
wind_output: 风电出力曲线 (MW) - 支持24小时或8760小时
thermal_output: 火电出力曲线 (MW) - 支持24小时或8760小时
load_demand: 负荷曲线 (MW) - 支持24小时或8760小时
result: 优化结果字典
"""
hours = np.arange(len(solar_output))
data_length = len(solar_output)
# 确定图表标题和采样率
if data_length == 8760:
title_suffix = " (全年8760小时)"
# 对于全年数据我们采样显示每6小时显示一个点
sample_rate = 6
sampled_hours = hours[::sample_rate]
sampled_solar = solar_output[::sample_rate]
sampled_wind = wind_output[::sample_rate]
sampled_thermal = thermal_output[::sample_rate]
sampled_load = load_demand[::sample_rate]
sampled_storage = result['storage_profile'][::sample_rate]
sampled_charge = result['charge_profile'][::sample_rate]
sampled_discharge = result['discharge_profile'][::sample_rate]
else:
title_suffix = " (24小时)"
sampled_hours = hours
sampled_solar = solar_output
sampled_wind = wind_output
sampled_thermal = thermal_output
sampled_load = load_demand
sampled_storage = result['storage_profile']
sampled_charge = result['charge_profile']
sampled_discharge = result['discharge_profile']
# 创建图形
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(14, 12))
fig.suptitle('多能互补系统24小时运行曲线', fontsize=16, fontweight='bold')
# === 第一个子图:发电和负荷曲线 ===
ax1.plot(sampled_hours, sampled_load, 'r-', linewidth=2, label='负荷需求')
ax1.plot(sampled_hours, sampled_thermal, 'b-', linewidth=2, label='火电出力')
ax1.plot(sampled_hours, sampled_wind, 'g-', linewidth=2, label='风电出力')
ax1.plot(sampled_hours, sampled_solar, 'orange', linewidth=2, label='光伏出力')
# 计算总发电量
total_generation = [sampled_thermal[i] + sampled_wind[i] + sampled_solar[i] for i in range(len(sampled_thermal))]
ax1.plot(sampled_hours, total_generation, 'k--', linewidth=1.5, alpha=0.7, label='总发电量')
ax1.set_xlabel('时间 (小时)')
ax1.set_ylabel('功率 (MW)')
ax1.set_title(f'发电与负荷曲线{title_suffix}')
ax1.legend(loc='upper right')
ax1.grid(True, alpha=0.3)
ax1.set_xlim(0, max(sampled_hours))
# === 第二个子图:储能充放电曲线 ===
discharge_power = [-x for x in sampled_discharge] # 放电显示为负值
ax2.bar(sampled_hours, sampled_charge, color='green', alpha=0.7, label='充电功率')
ax2.bar(sampled_hours, discharge_power, color='red', alpha=0.7, label='放电功率')
ax2.set_xlabel('时间 (小时)')
ax2.set_ylabel('功率 (MW)')
ax2.set_title(f'储能充放电功率{title_suffix}')
ax2.legend(loc='upper right')
ax2.grid(True, alpha=0.3)
ax2.set_xlim(0, max(sampled_hours))
ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
# === 第三个子图:储能状态曲线 ===
ax3.plot(sampled_hours, sampled_storage, 'b-', linewidth=1, marker='o', markersize=2)
ax3.fill_between(sampled_hours, 0, sampled_storage, alpha=0.3, color='blue')
ax3.set_xlabel('时间 (小时)')
ax3.set_ylabel('储能容量 (MWh)')
ax3.set_title(f'储能状态 (总容量: {result["required_storage_capacity"]:.2f} MWh){title_suffix}')
ax3.grid(True, alpha=0.3)
ax3.set_xlim(0, max(sampled_hours))
ax3.set_ylim(bottom=0)
# 调整布局
plt.tight_layout()
# 保存图片
plt.savefig('system_curves.png', dpi=300, bbox_inches='tight')
plt.close() # 关闭图形,不显示窗口
# 打印统计信息
print("\n=== 系统运行统计 ===")
print(f"所需储能总容量: {result['required_storage_capacity']:.2f} MWh")
print(f"最大储能状态: {max(result['storage_profile']):.2f} MWh")
print(f"最小储能状态: {min(result['storage_profile']):.2f} MWh")
print(f"总充电量: {sum(result['charge_profile']):.2f} MWh")
print(f"总放电量: {sum(result['discharge_profile']):.2f} MWh")
print(f"弃风率: {result['total_curtailment_wind_ratio']:.3f}")
print(f"弃光率: {result['total_curtailment_solar_ratio']:.3f}")
print(f"上网电量比例: {result['total_grid_feed_in_ratio']:.3f}")
def generate_yearly_data():
"""生成8760小时的示例数据"""
# 基础日模式
daily_solar = [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
daily_wind = [2.0, 3.0, 4.0, 3.0, 2.0, 1.0] * 4
daily_thermal = [5.0] * 24
daily_load = [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]
# 添加季节性变化
import random
random.seed(42)
yearly_solar = []
yearly_wind = []
yearly_thermal = []
yearly_load = []
for day in range(365):
# 季节性因子(夏季光伏更强,冬季负荷更高)
season_factor = 1.0 + 0.3 * np.sin(2 * np.pi * day / 365)
for hour in range(24):
# 添加随机变化
solar_variation = 1.0 + 0.2 * (random.random() - 0.5)
wind_variation = 1.0 + 0.3 * (random.random() - 0.5)
load_variation = 1.0 + 0.1 * (random.random() - 0.5)
yearly_solar.append(daily_solar[hour] * season_factor * solar_variation)
yearly_wind.append(daily_wind[hour] * wind_variation)
yearly_thermal.append(daily_thermal[hour])
yearly_load.append(daily_load[hour] * (2.0 - season_factor) * load_variation)
return yearly_solar, yearly_wind, yearly_thermal, yearly_load
def main():
"""主函数"""
import sys
# 检查命令行参数
use_yearly_data = len(sys.argv) > 1 and sys.argv[1] == '--yearly'
if use_yearly_data:
print("生成8760小时全年数据...")
solar_output, wind_output, thermal_output, load_demand = generate_yearly_data()
print(f"数据长度: {len(solar_output)} 小时")
else:
print("使用24小时示例数据...")
# 示例数据
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
)
# 计算最优储能容量
print("正在计算最优储能容量...")
result = optimize_storage_capacity(
solar_output, wind_output, thermal_output, load_demand, params
)
# 绘制曲线
print("正在绘制系统运行曲线...")
plot_system_curves(solar_output, wind_output, thermal_output, load_demand, result)
print("\n曲线图已保存为 'system_curves.png'")
if __name__ == "__main__":
main()