""" 高级可视化程序 - 多能互补系统储能容量优化 该程序提供更丰富的可视化功能,包括多种图表类型和交互式选项。 作者: iFlow CLI 创建日期: 2025-12-25 """ import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np from datetime import datetime, timedelta 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 create_comprehensive_plot(solar_output, wind_output, thermal_output, load_demand, result, params): """ 创建综合可视化图表 Args: solar_output: 24小时光伏出力曲线 (MW) wind_output: 24小时风电出力曲线 (MW) thermal_output: 24小时火电出力曲线 (MW) load_demand: 24小时负荷曲线 (MW) result: 优化结果字典 params: 系统参数 """ hours = np.arange(24) # 创建大型图形 fig = plt.figure(figsize=(16, 12)) fig.suptitle('多能互补系统储能容量优化分析', fontsize=18, fontweight='bold') # 创建网格布局 gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3) # === 主要图表:发电和负荷 === ax1 = fig.add_subplot(gs[0, :]) # 绘制各发电类型 ax1.fill_between(hours, 0, thermal_output, alpha=0.7, color='blue', label='火电') ax1.fill_between(hours, thermal_output, [thermal_output[i] + wind_output[i] for i in range(24)], alpha=0.7, color='green', label='风电') ax1.fill_between(hours, [thermal_output[i] + wind_output[i] for i in range(24)], [thermal_output[i] + wind_output[i] + solar_output[i] for i in range(24)], alpha=0.7, color='orange', label='光伏') # 绘制负荷曲线 ax1.plot(hours, load_demand, 'r-', linewidth=3, label='负荷需求') ax1.set_xlabel('时间 (小时)') ax1.set_ylabel('功率 (MW)') ax1.set_title('24小时发电与负荷平衡') ax1.legend(loc='upper right') ax1.grid(True, alpha=0.3) ax1.set_xlim(0, 23) # === 储能充放电功率 === ax2 = fig.add_subplot(gs[1, 0]) charge_power = result['charge_profile'] discharge_power = [-x for x in result['discharge_profile']] ax2.bar(hours, charge_power, color='green', alpha=0.7, label='充电') ax2.bar(hours, discharge_power, color='red', alpha=0.7, label='放电') ax2.set_xlabel('时间 (小时)') ax2.set_ylabel('功率 (MW)') ax2.set_title('储能充放电功率') ax2.legend() ax2.grid(True, alpha=0.3) ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5) # === 储能状态 === ax3 = fig.add_subplot(gs[1, 1]) storage_soc = result['storage_profile'] ax3.plot(hours, storage_soc, 'b-', linewidth=2, marker='o') ax3.fill_between(hours, 0, storage_soc, alpha=0.3, color='blue') ax3.set_xlabel('时间 (小时)') ax3.set_ylabel('储能容量 (MWh)') ax3.set_title(f'储能状态 (容量: {result["required_storage_capacity"]:.1f} MWh)') ax3.grid(True, alpha=0.3) ax3.set_ylim(bottom=0) # === 弃风弃光 === ax4 = fig.add_subplot(gs[1, 2]) curtailed_wind = result['curtailed_wind'] curtailed_solar = result['curtailed_solar'] ax4.bar(hours, curtailed_wind, color='lightblue', alpha=0.7, label='弃风') ax4.bar(hours, curtailed_solar, color='yellow', alpha=0.7, label='弃光') ax4.set_xlabel('时间 (小时)') ax4.set_ylabel('功率 (MW)') ax4.set_title('弃风弃光功率') ax4.legend() ax4.grid(True, alpha=0.3) # === 能量饼图 === ax5 = fig.add_subplot(gs[2, 0]) # 计算总能量 total_gen = sum(thermal_output) + sum(wind_output) + sum(solar_output) total_load = sum(load_demand) total_curtailed = sum(curtailed_wind) + sum(curtailed_solar) total_grid = sum(result['grid_feed_in']) # 处理上网电量为负的情况(购电) if total_grid >= 0: # 有上网电量 energy_data = [total_load, total_curtailed, total_grid] energy_labels = [f'负荷\n({total_load:.1f} MWh)', f'弃风弃光\n({total_curtailed:.1f} MWh)', f'上网电量\n({total_grid:.1f} MWh)'] colors = ['red', 'orange', 'green'] ax5.pie(energy_data, labels=energy_labels, colors=colors, autopct='%1.1f%%', startangle=90) ax5.set_title('能量分配') else: # 从电网购电 grid_purchase = -total_grid # 转为正值 energy_data = [total_load, total_curtailed, grid_purchase] energy_labels = [f'负荷\n({total_load:.1f} MWh)', f'弃风弃光\n({total_curtailed:.1f} MWh)', f'购电量\n({grid_purchase:.1f} MWh)'] colors = ['red', 'orange', 'blue'] # 购电用蓝色 ax5.pie(energy_data, labels=energy_labels, colors=colors, autopct='%1.1f%%', startangle=90) ax5.set_title('能量分配(含购电)') # === 发电构成饼图 === ax6 = fig.add_subplot(gs[2, 1]) gen_data = [sum(thermal_output), sum(wind_output), sum(solar_output)] gen_labels = [f'火电\n({gen_data[0]:.1f} MWh)', f'风电\n({gen_data[1]:.1f} MWh)', f'光伏\n({gen_data[2]:.1f} MWh)'] gen_colors = ['blue', 'green', 'orange'] ax6.pie(gen_data, labels=gen_labels, colors=gen_colors, autopct='%1.1f%%', startangle=90) ax6.set_title('发电构成') # === 关键指标文本 === ax7 = fig.add_subplot(gs[2, 2]) ax7.axis('off') # 显示关键指标 metrics_text = f""" 关键指标 ───────────── 所需储能容量: {result['required_storage_capacity']:.1f} MWh 储能效率: {params.storage_efficiency:.1%} 弃风率: {result['total_curtailment_wind_ratio']:.1%} 弃光率: {result['total_curtailment_solar_ratio']:.1%} 上网电量比例: {result['total_grid_feed_in_ratio']:.1%} 能量平衡: {'通过' if result['energy_balance_check'] else '未通过'} 最大储能状态: {max(storage_soc):.1f} MWh 最小储能状态: {min(storage_soc):.1f} MWh """ ax7.text(0.1, 0.5, metrics_text, fontsize=11, verticalalignment='center', fontfamily='SimHei', bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8)) # 保存图片 plt.savefig('comprehensive_analysis.png', dpi=300, bbox_inches='tight') plt.close() print("综合分析图表已保存为 'comprehensive_analysis.png'") def create_time_series_plot(solar_output, wind_output, thermal_output, load_demand, result): """ 创建时间序列图表,模拟真实的时间轴 """ # 创建时间轴 base_time = datetime(2025, 1, 1, 0, 0, 0) times = [base_time + timedelta(hours=i) for i in range(24)] fig, ax = plt.subplots(figsize=(14, 8)) # 绘制发电和负荷 ax.plot(times, load_demand, 'r-', linewidth=3, label='负荷需求') ax.plot(times, thermal_output, 'b-', linewidth=2, label='火电出力') ax.plot(times, wind_output, 'g-', linewidth=2, label='风电出力') ax.plot(times, solar_output, 'orange', linewidth=2, label='光伏出力') # 计算总发电量 total_generation = [thermal_output[i] + wind_output[i] + solar_output[i] for i in range(24)] ax.plot(times, total_generation, 'k--', linewidth=1.5, alpha=0.7, label='总发电量') # 设置时间轴格式 ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) ax.xaxis.set_major_locator(mdates.HourLocator(interval=2)) ax.set_xlabel('时间') ax.set_ylabel('功率 (MW)') ax.set_title('多能互补系统24小时发电曲线 (时间序列)') ax.legend(loc='upper right') ax.grid(True, alpha=0.3) # 旋转时间标签 plt.setp(ax.xaxis.get_majorticklabels(), rotation=45) plt.tight_layout() plt.savefig('time_series_curves.png', dpi=300, bbox_inches='tight') plt.close() print("时间序列图表已保存为 'time_series_curves.png'") def main(): """主函数""" # 示例数据 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("\n=== 优化结果 ===") print(f"所需储能总容量: {result['required_storage_capacity']:.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}") print(f"能量平衡校验: {'通过' if result['energy_balance_check'] else '未通过'}") # 创建各种图表 print("\n正在生成可视化图表...") # 1. 基础曲线图(已在main.py中实现) print("1. 基础系统运行曲线图") # 2. 综合分析图 print("2. 综合分析图表") create_comprehensive_plot(solar_output, wind_output, thermal_output, load_demand, result, params) # 3. 时间序列图 print("3. 时间序列图表") create_time_series_plot(solar_output, wind_output, thermal_output, load_demand, result) print("\n=== 所有图表生成完成 ===") print("生成的文件:") print("- system_curves.png: 基础系统运行曲线") print("- comprehensive_analysis.png: 综合分析图表") print("- time_series_curves.png: 时间序列图表") if __name__ == "__main__": main()