From 2177a86c28aae7ebe18f421257a8b983f6557909 Mon Sep 17 00:00:00 2001 From: dmy Date: Fri, 26 Dec 2025 00:28:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9C=A8excel=E4=B8=AD?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=8F=82=E6=95=B0=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- advanced_visualization.py | 31 +++-- excel_reader.py | 232 +++++++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 15 deletions(-) diff --git a/advanced_visualization.py b/advanced_visualization.py index a88aca5..3d2cb15 100644 --- a/advanced_visualization.py +++ b/advanced_visualization.py @@ -109,15 +109,26 @@ def create_comprehensive_plot(solar_output, wind_output, thermal_output, load_de total_curtailed = sum(curtailed_wind) + sum(curtailed_solar) total_grid = sum(result['grid_feed_in']) - # 能量分配 - 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('能量分配') + # 处理上网电量为负的情况(购电) + 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]) @@ -146,7 +157,7 @@ def create_comprehensive_plot(solar_output, wind_output, thermal_output, load_de 弃光率: {result['total_curtailment_solar_ratio']:.1%} 上网电量比例: {result['total_grid_feed_in_ratio']:.1%} - 能量平衡: {'✓' if result['energy_balance_check'] else '✗'} + 能量平衡: {'通过' if result['energy_balance_check'] else '未通过'} 最大储能状态: {max(storage_soc):.1f} MWh 最小储能状态: {min(storage_soc):.1f} MWh diff --git a/excel_reader.py b/excel_reader.py index 574df43..8df9bde 100644 --- a/excel_reader.py +++ b/excel_reader.py @@ -9,8 +9,9 @@ Excel数据读取模块 import pandas as pd import numpy as np -from typing import Dict, List, Optional, Tuple +from typing import Dict, List, Optional, Tuple, Any import os +from storage_optimization import SystemParameters def validate_excel_data(df: pd.DataFrame, data_type: str = "8760") -> bool: @@ -52,13 +53,79 @@ def validate_excel_data(df: pd.DataFrame, data_type: str = "8760") -> bool: return True -def read_excel_data(file_path: str, sheet_name: str = 0) -> Dict[str, List[float]]: +def read_system_parameters(file_path: str) -> SystemParameters: + """ + 从Excel文件读取系统参数 + + Args: + file_path: Excel文件路径 + + Returns: + SystemParameters对象 + + Raises: + FileNotFoundError: 文件不存在 + ValueError: 参数格式错误 + """ + # 检查文件是否存在 + if not os.path.exists(file_path): + raise FileNotFoundError(f"文件不存在:{file_path}") + + try: + # 读取参数工作表 + df_params = pd.read_excel(file_path, sheet_name='参数') + + # 验证参数工作表格式 + required_columns = ['参数名称', '参数值', '参数说明'] + missing_columns = [col for col in required_columns if col not in df_params.columns] + + if missing_columns: + raise ValueError(f"参数工作表缺少必需的列:{missing_columns}") + + # 提取参数值 + params_dict = {} + for _, row in df_params.iterrows(): + param_name = row['参数名称'] + param_value = row['参数值'] + + # 跳过空行 + if pd.isna(param_name) or pd.isna(param_value): + continue + + # 转换参数值 + try: + if isinstance(param_value, str): + # 尝试转换为浮点数 + param_value = float(param_value) + params_dict[param_name] = param_value + except (ValueError, TypeError): + raise ValueError(f"参数 '{param_name}' 的值 '{param_value}' 不是有效的数值") + + # 创建SystemParameters对象 + return SystemParameters( + max_curtailment_wind=params_dict.get('最大弃风率', 0.1), + max_curtailment_solar=params_dict.get('最大弃光率', 0.1), + max_grid_ratio=params_dict.get('最大上网电量比例', 0.2), + storage_efficiency=params_dict.get('储能效率', 0.9), + discharge_rate=params_dict.get('放电倍率', 1.0), + charge_rate=params_dict.get('充电倍率', 1.0), + max_storage_capacity=params_dict.get('最大储能容量', None) + ) + + except Exception as e: + print(f"读取参数工作表失败,使用默认参数:{str(e)}") + # 如果参数工作表不存在或读取失败,返回默认参数 + return SystemParameters() + + +def read_excel_data(file_path: str, sheet_name: str = 0, include_parameters: bool = True) -> Dict[str, List[float]]: """ 从Excel文件读取8760小时数据 Args: file_path: Excel文件路径 sheet_name: 工作表名称或索引,默认为第一个工作表 + include_parameters: 是否同时读取系统参数 Returns: 包含所有数据的字典 @@ -96,7 +163,8 @@ def read_excel_data(file_path: str, sheet_name: str = 0) -> Dict[str, List[float thermal_output = thermal_output * 365 load_demand = load_demand * 365 - return { + # 构建返回结果 + result = { 'solar_output': solar_output, 'wind_output': wind_output, 'thermal_output': thermal_output, @@ -105,6 +173,17 @@ def read_excel_data(file_path: str, sheet_name: str = 0) -> Dict[str, List[float 'original_length': len(df) } + # 如果需要读取参数 + if include_parameters: + try: + result['system_parameters'] = read_system_parameters(file_path) + print("成功读取系统参数") + except Exception as e: + print(f"读取系统参数失败,使用默认参数:{str(e)}") + result['system_parameters'] = SystemParameters() + + return result + except Exception as e: raise ValueError(f"读取Excel文件失败:{str(e)}") @@ -173,15 +252,66 @@ def create_excel_template(file_path: str, data_type: str = "8760"): with pd.ExcelWriter(file_path, engine='openpyxl') as writer: df.to_excel(writer, sheet_name='数据', index=False) + # 添加参数工作表 + parameters_df = pd.DataFrame({ + '参数名称': [ + '最大弃风率', + '最大弃光率', + '最大上网电量比例', + '储能效率', + '放电倍率', + '充电倍率', + '最大储能容量' + ], + '参数值': [ + 0.1, # 最大弃风率 + 0.1, # 最大弃光率 + 0.2, # 最大上网电量比例 + 0.9, # 储能效率 + 1.0, # 放电倍率 + 1.0, # 充电倍率 + '' # 最大储能容量(空表示无限制) + ], + '参数说明': [ + '允许的最大弃风率(0.0-1.0)', + '允许的最大弃光率(0.0-1.0)', + '允许的最大上网电量比例(0.0-∞,只限制上网电量)', + '储能充放电效率(0.0-1.0)', + '储能放电倍率(C-rate,>0)', + '储能充电倍率(C-rate,>0)', + '储能容量上限(MWh,空表示无限制)' + ], + '取值范围': [ + '0.0-1.0', + '0.0-1.0', + '≥0.0', + '0.0-1.0', + '>0', + '>0', + '>0或空' + ], + '默认值': [ + '0.1', + '0.1', + '0.2', + '0.9', + '1.0', + '1.0', + '无限制' + ] + }) + parameters_df.to_excel(writer, sheet_name='参数', index=False) + # 添加说明工作表 description_df = pd.DataFrame({ - '项目': ['数据说明', '数据类型', '时间范围', '单位', '注意事项'], + '项目': ['数据说明', '数据类型', '时间范围', '单位', '注意事项', '参数说明'], '内容': [ description, f'{data_type}小时电力数据', f'1-{hours}小时', 'MW (兆瓦)', - '所有数值必须为非负数' + '所有数值必须为非负数', + '系统参数请在"参数"工作表中修改' ] }) description_df.to_excel(writer, sheet_name='说明', index=False) @@ -228,6 +358,70 @@ def analyze_excel_data(file_path: str) -> Dict[str, float]: return {} +def validate_system_parameters(params: SystemParameters) -> Dict[str, Any]: + """ + 验证系统参数的有效性 + + Args: + params: SystemParameters对象 + + Returns: + 验证结果字典 + """ + validation_result = { + 'valid': True, + 'errors': [], + 'warnings': [] + } + + # 检查弃风率 + if not (0.0 <= params.max_curtailment_wind <= 1.0): + validation_result['valid'] = False + validation_result['errors'].append(f"弃风率必须在0.0-1.0之间,当前值:{params.max_curtailment_wind}") + + # 检查弃光率 + if not (0.0 <= params.max_curtailment_solar <= 1.0): + validation_result['valid'] = False + validation_result['errors'].append(f"弃光率必须在0.0-1.0之间,当前值:{params.max_curtailment_solar}") + + # 检查上网电量比例 + if not (0.0 <= params.max_grid_ratio): + validation_result['valid'] = False + validation_result['errors'].append(f"上网电量比例必须为非负值,当前值:{params.max_grid_ratio}") + + # 检查储能效率 + if not (0.0 < params.storage_efficiency <= 1.0): + validation_result['valid'] = False + validation_result['errors'].append(f"储能效率必须在0.0-1.0之间,当前值:{params.storage_efficiency}") + + # 检查放电倍率 + if params.discharge_rate <= 0: + validation_result['valid'] = False + validation_result['errors'].append(f"放电倍率必须大于0,当前值:{params.discharge_rate}") + + # 检查充电倍率 + if params.charge_rate <= 0: + validation_result['valid'] = False + validation_result['errors'].append(f"充电倍率必须大于0,当前值:{params.charge_rate}") + + # 检查储能容量上限 + if params.max_storage_capacity is not None and params.max_storage_capacity <= 0: + validation_result['valid'] = False + validation_result['errors'].append(f"储能容量上限必须大于0,当前值:{params.max_storage_capacity}") + + # 添加警告信息 + if params.storage_efficiency < 0.8: + validation_result['warnings'].append("储能效率较低,可能影响系统性能") + + if params.max_curtailment_wind > 0.3 or params.max_curtailment_solar > 0.3: + validation_result['warnings'].append("弃风弃光率较高,可能造成能源浪费") + + if params.max_grid_ratio > 0.5: + validation_result['warnings'].append("上网电量比例较高,可能影响电网稳定性") + + return validation_result + + def main(): """主函数,演示Excel数据读取功能""" print("=== Excel数据读取模块演示 ===") @@ -255,11 +449,39 @@ def main(): print(f"光伏出力前10小时:{data['solar_output'][:10]}") print(f"风电出力前10小时:{data['wind_output'][:10]}") print(f"负荷需求前10小时:{data['load_demand'][:10]}") + + # 演示参数读取 + if 'system_parameters' in data: + params = data['system_parameters'] + print(f"\n系统参数:") + print(f" 最大弃风率: {params.max_curtailment_wind}") + print(f" 最大弃光率: {params.max_curtailment_solar}") + print(f" 最大上网电量比例: {params.max_grid_ratio}") + print(f" 储能效率: {params.storage_efficiency}") + print(f" 放电倍率: {params.discharge_rate}") + print(f" 充电倍率: {params.charge_rate}") + print(f" 最大储能容量: {params.max_storage_capacity}") + + # 验证参数 + validation = validate_system_parameters(params) + if validation['valid']: + print("[OK] 参数验证通过") + else: + print("[ERROR] 参数验证失败:") + for error in validation['errors']: + print(f" - {error}") + + if validation['warnings']: + print("[WARNING] 参数警告:") + for warning in validation['warnings']: + print(f" - {warning}") + except Exception as e: print(f"读取失败:{str(e)}") print("\n=== 演示完成 ===") print("模板文件已创建,您可以根据实际数据修改Excel文件。") + print("系统参数可以在Excel的'参数'工作表中直接修改。") if __name__ == "__main__":