excel结果中输出弃电量。
This commit is contained in:
134
docs/CURTAILMENT_LOSS_FEATURES.md
Normal file
134
docs/CURTAILMENT_LOSS_FEATURES.md
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# 弃电损失量功能增强文档
|
||||||
|
|
||||||
|
## 修改概述
|
||||||
|
|
||||||
|
在用户要求下,对 `main.py` 文件的 Excel 输出功能进行了增强,新增了**弃电损失量**相关的统计和输出。
|
||||||
|
|
||||||
|
## 主要修改内容
|
||||||
|
|
||||||
|
### 1. 统计结果工作表增强
|
||||||
|
|
||||||
|
在 `export_results_to_excel` 函数的 `stats_df` 中新增了以下指标:
|
||||||
|
|
||||||
|
| 新增指标 | 说明 | 单位 |
|
||||||
|
|---------|------|------|
|
||||||
|
| 总弃风电量 | 全部时间的弃风量总和 | MWh |
|
||||||
|
| 总弃光电量 | 全部时间的弃光量总和 | MWh |
|
||||||
|
| 总弃电量 | 弃风量 + 弃光量 | MWh |
|
||||||
|
| 弃电损失比例 | 总弃电量 / 总潜在发电量 | % |
|
||||||
|
|
||||||
|
**代码位置**:[`main.py:374-377`](main.py:374-377)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 计算弃电损失量
|
||||||
|
total_curtail_wind = sum(result['curtailed_wind'])
|
||||||
|
total_curtail_solar = sum(result['curtailed_solar'])
|
||||||
|
total_curtail_energy = total_curtail_wind + total_curtail_solar
|
||||||
|
|
||||||
|
# 计算总潜在发电量
|
||||||
|
total_potential_generation = sum(solar_output) + sum(wind_output) + sum(thermal_output)
|
||||||
|
curtailment_loss_ratio = (total_curtail_energy / total_potential_generation * 100) if total_potential_generation > 0 else 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 运行数据工作表增强
|
||||||
|
|
||||||
|
在 `data_df` 中新增了以下列:
|
||||||
|
|
||||||
|
| 新增列名 | 说明 | 计算方式 |
|
||||||
|
|---------|------|----------|
|
||||||
|
| 弃电损失量(MW) | 每小时的弃电损失量 | 弃风量 + 弃光量 |
|
||||||
|
| 累计弃电量(MWh) | 从开始到当前的累计弃电量 | 逐小时累加弃电损失量 |
|
||||||
|
|
||||||
|
**代码位置**:[`main.py:323-348`](main.py:323-348)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 计算弃电损失量(弃风+弃光)
|
||||||
|
curtailment_loss = [result['curtailed_wind'][i] + result['curtailed_solar'][i] for i in range(len(result['curtailed_wind']))]
|
||||||
|
|
||||||
|
# 计算累计弃电损失量
|
||||||
|
cumulative_curtailment = []
|
||||||
|
cumulative = 0
|
||||||
|
for loss in curtailment_loss:
|
||||||
|
cumulative += loss
|
||||||
|
cumulative_curtailment.append(cumulative)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
### 1. 完整的弃电损失分析
|
||||||
|
- **小时级分析**:`弃电损失量(MW)` 提供每小时的弃电情况
|
||||||
|
- **累计分析**:`累计弃电量(MWh)` 提供弃电的累积趋势
|
||||||
|
- **总量统计**:总弃风量、总弃光量、总弃电量的完整统计
|
||||||
|
- **比例分析**:弃电损失比例,评估系统效率
|
||||||
|
|
||||||
|
### 2. 数据一致性保证
|
||||||
|
- 运行数据中的累计弃电量 = 统计结果中的总弃电量
|
||||||
|
- 弃电损失量 = 弃风量 + 弃光量(逐小时匹配)
|
||||||
|
- 所有计算基于原始优化结果,确保数据一致性
|
||||||
|
|
||||||
|
### 3. 用户友好的输出
|
||||||
|
- Excel文件中清晰的工作表分类
|
||||||
|
- 中文列名,便于理解
|
||||||
|
- 合理的单位标注(MW用于功率,MWh用于能量)
|
||||||
|
|
||||||
|
## 输出效果
|
||||||
|
|
||||||
|
### 统计结果工作表示例
|
||||||
|
```
|
||||||
|
指标 | 数值
|
||||||
|
-------------------|------------------
|
||||||
|
总弃风电量 | 12.50 MWh
|
||||||
|
总弃光电量 | 8.30 MWh
|
||||||
|
总弃电量 | 20.80 MWh
|
||||||
|
弃电损失比例 | 2.34%
|
||||||
|
```
|
||||||
|
|
||||||
|
### 运行数据工作表新增列
|
||||||
|
```
|
||||||
|
小时 | 弃风量(MW) | 弃光量(MW) | 弃电损失量(MW) | 累计弃电量(MWh)
|
||||||
|
-----|-----------|-----------|---------------|--------------
|
||||||
|
1 | 0.5 | 0.3 | 0.8 | 0.8
|
||||||
|
2 | 0.2 | 0.4 | 0.6 | 1.4
|
||||||
|
3 | 0.0 | 0.5 | 0.5 | 1.9
|
||||||
|
... | ... | ... | ... | ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
1. **运行程序**:`python main.py --excel data.xlsx`
|
||||||
|
2. **查看结果**:在生成的Excel文件中查看"统计结果"和"运行数据"工作表
|
||||||
|
3. **分析弃电**:
|
||||||
|
- 统计结果:了解总体弃电情况和损失比例
|
||||||
|
- 运行数据:分析逐小时弃电模式和累计趋势
|
||||||
|
|
||||||
|
## 技术细节
|
||||||
|
|
||||||
|
### 计算公式
|
||||||
|
- **弃电损失量** = 弃风量 + 弃光量
|
||||||
|
- **累计弃电量** = Σ(弃电损失量) (逐小时累加)
|
||||||
|
- **弃电损失比例** = (总弃电量 / 总潜在发电量) × 100%
|
||||||
|
- **总潜在发电量** = 光伏总出力 + 风电总出力 + 火电总出力
|
||||||
|
|
||||||
|
### 数据来源
|
||||||
|
- 基于 `storage_optimization.py` 中的 `result` 字典
|
||||||
|
- 使用 `curtailed_wind` 和 `curtailed_solar` 数据
|
||||||
|
- 确保与优化算法结果完全一致
|
||||||
|
|
||||||
|
## 兼容性
|
||||||
|
|
||||||
|
- ✅ 向后兼容:不影响原有功能
|
||||||
|
- ✅ Excel格式:保持原有文件结构
|
||||||
|
- ✅ 时间尺度:支持24小时和8760小时数据
|
||||||
|
- ✅ 数据精度:保持原有计算精度
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
创建了测试文件 `test_main_modifications.py` 用于验证功能正确性:
|
||||||
|
- 验证Excel文件导出成功
|
||||||
|
- 检查新增列是否正确添加
|
||||||
|
- 验证数据计算的一致性
|
||||||
|
- 确认统计结果的准确性
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
此次修改成功地在Excel输出中增加了完整的弃电损失量分析功能,为用户提供了更详细和直观的弃电情况分析工具,有助于优化储能系统配置和运行策略。
|
||||||
121
docs/GRID_FEED_IN_RATIO_CALCULATION.md
Normal file
121
docs/GRID_FEED_IN_RATIO_CALCULATION.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# 上网电量比例计算方法说明
|
||||||
|
|
||||||
|
## 计算公式
|
||||||
|
|
||||||
|
**上网电量比例** = 总上网电量 / 总发电量
|
||||||
|
|
||||||
|
其中:
|
||||||
|
- **总上网电量** = sum(grid_feed_in) - 只计算正值(上网电量)
|
||||||
|
- **总发电量** = 火电发电量 + 实际风电发电量 + 实际光伏发电量
|
||||||
|
|
||||||
|
## 详细计算过程
|
||||||
|
|
||||||
|
### 1. 基础数据获取
|
||||||
|
|
||||||
|
在 [`check_constraints()`](src/storage_optimization.py:350) 函数中:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 计算总量
|
||||||
|
total_wind_potential = sum(wind_output) # 风电总潜力
|
||||||
|
total_solar_potential = sum(solar_output) # 光伏总潜力
|
||||||
|
total_thermal = sum(thermal_output) # 火电总量
|
||||||
|
|
||||||
|
total_curtailed_wind = sum(balance_result['curtailed_wind']) # 弃风总量
|
||||||
|
total_curtailed_solar = sum(balance_result['curtailed_solar']) # 弃光总量
|
||||||
|
total_grid_feed_in = sum(balance_result['grid_feed_in']) # 电网交互总量
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 计算实际发电量
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 实际发电量(考虑弃风弃光)
|
||||||
|
actual_wind_generation = total_wind_potential - total_curtailed_wind
|
||||||
|
actual_solar_generation = total_solar_potential - total_curtailed_solar
|
||||||
|
total_generation = total_thermal + actual_wind_generation + actual_solar_generation
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 计算上网电量比例
|
||||||
|
|
||||||
|
```python
|
||||||
|
actual_grid_feed_in_ratio = total_grid_feed_in / total_generation if total_generation > 0 else 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据来源说明
|
||||||
|
|
||||||
|
### grid_feed_in 数据含义
|
||||||
|
在 [`calculate_energy_balance()`](src/storage_optimization.py:107) 函数中:
|
||||||
|
|
||||||
|
- **正值** = 向电网输送的电量(上网)
|
||||||
|
- **负值** = 从电网购买的电量(购电)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 上网情况
|
||||||
|
grid_feed_in[hour] = grid_feed_allowed # 正值
|
||||||
|
|
||||||
|
# 购电情况
|
||||||
|
grid_feed_in[hour] = -remaining_deficit # 负值
|
||||||
|
```
|
||||||
|
|
||||||
|
### 分母说明
|
||||||
|
**总发电量**包括:
|
||||||
|
1. **火电发电量** - 全部计入(不考虑弃火电)
|
||||||
|
2. **实际风电发电量** = 风电总潜力 - 弃风量
|
||||||
|
3. **实际光伏发电量** = 光伏总潜力 - 弃光量
|
||||||
|
|
||||||
|
## 计算示例
|
||||||
|
|
||||||
|
假设有如下数据:
|
||||||
|
- 火电总量:120 MWh (24小时 × 5MW)
|
||||||
|
- 风电总量:72 MWh (24小时 × 平均3MW)
|
||||||
|
- 光伏总量:48 MWh (24小时 × 平均2MW)
|
||||||
|
- 弃风量:7.2 MWh
|
||||||
|
- 弃光量:4.8 MWh
|
||||||
|
- 上网电量:10 MWh
|
||||||
|
|
||||||
|
计算过程:
|
||||||
|
```python
|
||||||
|
# 1. 实际发电量
|
||||||
|
actual_wind = 72 - 7.2 = 64.8 MWh
|
||||||
|
actual_solar = 48 - 4.8 = 43.2 MWh
|
||||||
|
total_generation = 120 + 64.8 + 43.2 = 228 MWh
|
||||||
|
|
||||||
|
# 2. 上网电量比例
|
||||||
|
grid_feed_in_ratio = 10 / 228 = 0.0438 ≈ 4.38%
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 1. 购电情况的处理
|
||||||
|
- 如果系统净购电(total_grid_feed_in < 0),上网电量比例仍按公式计算
|
||||||
|
- 负的上网电量会降低比例值
|
||||||
|
|
||||||
|
### 2. 零分母处理
|
||||||
|
- 如果总发电量为0,比例设为0,避免除零错误
|
||||||
|
|
||||||
|
### 3. 约束检查
|
||||||
|
在优化算法中,上网电量比例用于约束检查:
|
||||||
|
```python
|
||||||
|
grid_constraint_satisfied = constraint_results['total_grid_feed_in_ratio'] <= params.max_grid_ratio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 输出位置
|
||||||
|
|
||||||
|
上网电量比例在以下位置输出:
|
||||||
|
1. **控制台输出**:[`main.py:749`](main.py:749)
|
||||||
|
```python
|
||||||
|
print(f"实际上网电量比例: {result['total_grid_feed_in_ratio']:.3f}")
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Excel统计结果**:[`main.py:393`](main.py:393)
|
||||||
|
```python
|
||||||
|
f"{result['total_grid_feed_in_ratio']:.3f}",
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **可视化显示**:[`src/advanced_visualization.py:158`](src/advanced_visualization.py:158)
|
||||||
|
```python
|
||||||
|
上网电量比例: {result['total_grid_feed_in_ratio']:.1%}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
上网电量比例反映的是系统向电网输送电量占总发电量的比例,是评估系统电网交互特性的重要指标。该比例越低,说明系统越倾向于本地消纳新能源;比例越高,说明系统向电网输出的电量越多。
|
||||||
840
excel_reader.py
840
excel_reader.py
@@ -1,840 +0,0 @@
|
|||||||
"""
|
|
||||||
Excel数据读取模块
|
|
||||||
|
|
||||||
该模块提供从Excel文件中读取8760小时负荷和发电曲线数据的功能。
|
|
||||||
|
|
||||||
作者: iFlow CLI
|
|
||||||
创建日期: 2025-12-25
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
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:
|
|
||||||
"""
|
|
||||||
验证Excel数据格式是否正确
|
|
||||||
|
|
||||||
Args:
|
|
||||||
df: pandas DataFrame对象
|
|
||||||
data_type: 数据类型,"24"或"8760"
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 验证是否通过
|
|
||||||
"""
|
|
||||||
expected_length = 8760 if data_type == "8760" else 24
|
|
||||||
|
|
||||||
# 检查行数
|
|
||||||
if len(df) != expected_length:
|
|
||||||
print(f"错误:数据行数应为{expected_length},实际为{len(df)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查必需的列
|
|
||||||
required_columns = ['光伏出力(MW)', '风电出力(MW)', '火电出力(MW)', '负荷需求(MW)']
|
|
||||||
missing_columns = [col for col in required_columns if col not in df.columns]
|
|
||||||
|
|
||||||
if missing_columns:
|
|
||||||
print(f"错误:缺少必需的列:{missing_columns}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查数据类型和非负值
|
|
||||||
for col in required_columns:
|
|
||||||
if not pd.api.types.is_numeric_dtype(df[col]):
|
|
||||||
print(f"错误:列'{col}'必须为数值类型")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if (df[col] < 0).any():
|
|
||||||
print(f"错误:列'{col}'包含负值")
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
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}' 不是有效的数值")
|
|
||||||
|
|
||||||
# 读取各参数值,如果找不到则使用默认值
|
|
||||||
get_param_value = lambda param_name: df_params.loc[df_params['参数名称'] == param_name, '参数值'].iloc[0] if param_name in df_params['参数名称'].values else None
|
|
||||||
|
|
||||||
max_storage_capacity = get_param_value('最大储能容量')
|
|
||||||
# 处理空值或字符串"空"
|
|
||||||
if pd.isna(max_storage_capacity) or max_storage_capacity == '空':
|
|
||||||
max_storage_capacity = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 获取各参数值,区分None、NaN、0和有效值
|
|
||||||
def get_param_with_default(param_name, default_value):
|
|
||||||
value = get_param_value(param_name)
|
|
||||||
if value is None or pd.isna(value):
|
|
||||||
return default_value
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
return SystemParameters(
|
|
||||||
max_curtailment_wind=get_param_with_default('最大弃风率', 0.1),
|
|
||||||
max_curtailment_solar=get_param_with_default('最大弃光率', 0.1),
|
|
||||||
max_grid_ratio=get_param_with_default('最大上网电量比例', 0.2),
|
|
||||||
storage_efficiency=get_param_with_default('储能效率', 0.9),
|
|
||||||
discharge_rate=get_param_with_default('放电倍率', 1.0),
|
|
||||||
charge_rate=get_param_with_default('充电倍率', 1.0),
|
|
||||||
max_storage_capacity=max_storage_capacity,
|
|
||||||
rated_thermal_capacity=get_param_with_default('额定火电装机容量', 100.0),
|
|
||||||
rated_solar_capacity=get_param_with_default('额定光伏装机容量', 100.0),
|
|
||||||
rated_wind_capacity=get_param_with_default('额定风电装机容量', 100.0),
|
|
||||||
available_thermal_energy=get_param_with_default('火电可用发电量', 2400.0),
|
|
||||||
available_solar_energy=get_param_with_default('光伏可用发电量', 600.0),
|
|
||||||
available_wind_energy=get_param_with_default('风电可用发电量', 1200.0)
|
|
||||||
)
|
|
||||||
except (KeyError, IndexError, Exception) as e:
|
|
||||||
print(f"读取参数失败:{str(e)},使用默认参数")
|
|
||||||
return 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
|
|
||||||
)
|
|
||||||
|
|
||||||
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:
|
|
||||||
包含所有数据的字典
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
FileNotFoundError: 文件不存在
|
|
||||||
ValueError: 数据格式错误
|
|
||||||
"""
|
|
||||||
# 检查文件是否存在
|
|
||||||
if not os.path.exists(file_path):
|
|
||||||
raise FileNotFoundError(f"文件不存在:{file_path}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 读取Excel文件
|
|
||||||
df = pd.read_excel(file_path, sheet_name=sheet_name)
|
|
||||||
|
|
||||||
# 自动检测数据类型
|
|
||||||
data_type = "8760" if len(df) >= 8760 else "24"
|
|
||||||
|
|
||||||
# 验证数据格式
|
|
||||||
if not validate_excel_data(df, data_type):
|
|
||||||
raise ValueError("Excel数据格式验证失败")
|
|
||||||
|
|
||||||
# 提取数据并转换为列表
|
|
||||||
solar_output = df['光伏出力(MW)'].tolist()
|
|
||||||
wind_output = df['风电出力(MW)'].tolist()
|
|
||||||
thermal_output = df['火电出力(MW)'].tolist()
|
|
||||||
load_demand = df['负荷需求(MW)'].tolist()
|
|
||||||
|
|
||||||
# 如果是24小时数据,扩展到8760小时(重复365天)
|
|
||||||
if data_type == "24" and len(df) == 24:
|
|
||||||
print("检测到24小时数据,自动扩展到8760小时(重复365天)")
|
|
||||||
solar_output = solar_output * 365
|
|
||||||
wind_output = wind_output * 365
|
|
||||||
thermal_output = thermal_output * 365
|
|
||||||
load_demand = load_demand * 365
|
|
||||||
|
|
||||||
# 构建返回结果
|
|
||||||
result = {
|
|
||||||
'solar_output': solar_output,
|
|
||||||
'wind_output': wind_output,
|
|
||||||
'thermal_output': thermal_output,
|
|
||||||
'load_demand': load_demand,
|
|
||||||
'data_type': data_type,
|
|
||||||
'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()
|
|
||||||
|
|
||||||
try:
|
|
||||||
result['economic_parameters'] = read_economic_parameters(file_path)
|
|
||||||
print("成功读取经济参数")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"读取经济参数失败,使用默认参数:{str(e)}")
|
|
||||||
from economic_optimization import EconomicParameters
|
|
||||||
result['economic_parameters'] = EconomicParameters()
|
|
||||||
|
|
||||||
try:
|
|
||||||
result['optimization_settings'] = get_optimization_settings(file_path)
|
|
||||||
print("成功读取优化设置")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"读取优化设置失败,使用默认设置:{str(e)}")
|
|
||||||
result['optimization_settings'] = {
|
|
||||||
'storage_capacity_range': (0, 1000),
|
|
||||||
'rate_range': (0.1, 2.0),
|
|
||||||
'max_iterations': 100,
|
|
||||||
'tolerance': 0.01
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
raise ValueError(f"读取Excel文件失败:{str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
def create_excel_template(file_path: str, data_type: str = "8760"):
|
|
||||||
"""
|
|
||||||
创建Excel数据模板文件
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: 保存路径
|
|
||||||
data_type: 数据类型,"24"或"8760"
|
|
||||||
"""
|
|
||||||
# 生成示例数据
|
|
||||||
if data_type == "24":
|
|
||||||
hours = 24
|
|
||||||
# 24小时典型日数据
|
|
||||||
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
|
|
||||||
wind = [2.0, 3.0, 4.0, 3.0, 2.0, 1.0] * 4
|
|
||||||
thermal = [5.0] * 24
|
|
||||||
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]
|
|
||||||
description = "24小时典型日数据模板"
|
|
||||||
else:
|
|
||||||
hours = 8760
|
|
||||||
# 生成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]
|
|
||||||
|
|
||||||
solar = []
|
|
||||||
wind = []
|
|
||||||
thermal = []
|
|
||||||
load = []
|
|
||||||
|
|
||||||
np.random.seed(42) # 确保可重复性
|
|
||||||
|
|
||||||
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 * (np.random.random() - 0.5)
|
|
||||||
wind_variation = 1.0 + 0.3 * (np.random.random() - 0.5)
|
|
||||||
load_variation = 1.0 + 0.1 * (np.random.random() - 0.5)
|
|
||||||
|
|
||||||
solar.append(daily_solar[hour] * season_factor * solar_variation)
|
|
||||||
wind.append(daily_wind[hour] * wind_variation)
|
|
||||||
thermal.append(daily_thermal[hour])
|
|
||||||
load.append(daily_load[hour] * (2.0 - season_factor) * load_variation)
|
|
||||||
|
|
||||||
description = "8760小时全年数据模板"
|
|
||||||
|
|
||||||
# 创建DataFrame
|
|
||||||
df = pd.DataFrame({
|
|
||||||
'小时': range(1, hours + 1),
|
|
||||||
'光伏出力(MW)': solar,
|
|
||||||
'风电出力(MW)': wind,
|
|
||||||
'火电出力(MW)': thermal,
|
|
||||||
'负荷需求(MW)': load
|
|
||||||
})
|
|
||||||
|
|
||||||
# 保存到Excel
|
|
||||||
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, # 额定火电装机容量(可以为0)
|
|
||||||
100.0, # 额定光伏装机容量
|
|
||||||
100.0, # 额定风电装机容量
|
|
||||||
2400.0, # 火电可用发电量
|
|
||||||
600.0, # 光伏可用发电量
|
|
||||||
1200.0 # 风电可用发电量
|
|
||||||
],
|
|
||||||
'参数说明': [
|
|
||||||
'允许的最大弃风率(0.0-1.0)',
|
|
||||||
'允许的最大弃光率(0.0-1.0)',
|
|
||||||
'允许的最大上网电量比例(0.0-∞,只限制上网电量)',
|
|
||||||
'储能充放电效率(0.0-1.0)',
|
|
||||||
'储能放电倍率(C-rate,>0)',
|
|
||||||
'储能充电倍率(C-rate,>0)',
|
|
||||||
'储能容量上限(MWh,空表示无限制)',
|
|
||||||
'额定火电装机容量(MW,可以为0)',
|
|
||||||
'额定光伏装机容量(MW)',
|
|
||||||
'额定风电装机容量(MW)',
|
|
||||||
'火电可用发电量(MWh)',
|
|
||||||
'光伏可用发电量(MWh)',
|
|
||||||
'风电可用发电量(MWh)'
|
|
||||||
],
|
|
||||||
'取值范围': [
|
|
||||||
'0.0-1.0',
|
|
||||||
'0.0-1.0',
|
|
||||||
'≥0.0',
|
|
||||||
'0.0-1.0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0或空',
|
|
||||||
'≥0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'≥0',
|
|
||||||
'≥0',
|
|
||||||
'≥0'
|
|
||||||
],
|
|
||||||
'默认值': [
|
|
||||||
'0.1',
|
|
||||||
'0.1',
|
|
||||||
'0.2',
|
|
||||||
'0.9',
|
|
||||||
'1.0',
|
|
||||||
'1.0',
|
|
||||||
'无限制',
|
|
||||||
'0.0',
|
|
||||||
'100.0',
|
|
||||||
'100.0',
|
|
||||||
'2400.0',
|
|
||||||
'600.0',
|
|
||||||
'1200.0'
|
|
||||||
]
|
|
||||||
})
|
|
||||||
parameters_df.to_excel(writer, sheet_name='参数', index=False)
|
|
||||||
|
|
||||||
# 添加经济参数工作表
|
|
||||||
economic_params_df = pd.DataFrame({
|
|
||||||
'参数名称': [
|
|
||||||
'光伏建设成本',
|
|
||||||
'风电建设成本',
|
|
||||||
'储能建设成本',
|
|
||||||
'购电价格',
|
|
||||||
'上网电价',
|
|
||||||
'光伏运维成本',
|
|
||||||
'风电运维成本',
|
|
||||||
'储能运维成本',
|
|
||||||
'项目寿命',
|
|
||||||
'折现率',
|
|
||||||
'储能容量搜索范围-最小值',
|
|
||||||
'储能容量搜索范围-最大值',
|
|
||||||
'充放电倍率搜索范围-最小值',
|
|
||||||
'充放电倍率搜索范围-最大值',
|
|
||||||
'最大迭代次数',
|
|
||||||
'收敛容差'
|
|
||||||
],
|
|
||||||
'参数值': [
|
|
||||||
3000000, # 光伏建设成本 (元/MW)
|
|
||||||
2500000, # 风电建设成本 (元/MW)
|
|
||||||
800000, # 储能建设成本 (元/MWh)
|
|
||||||
600, # 购电价格 (元/MWh)
|
|
||||||
400, # 上网电价 (元/MWh)
|
|
||||||
50000, # 光伏运维成本 (元/MW/年)
|
|
||||||
45000, # 风电运维成本 (元/MW/年)
|
|
||||||
3000, # 储能运维成本 (元/MW/年)
|
|
||||||
25, # 项目寿命 (年)
|
|
||||||
0.08, # 折现率
|
|
||||||
0, # 储能容量搜索范围-最小值 (MWh)
|
|
||||||
1000, # 储能容量搜索范围-最大值 (MWh)
|
|
||||||
0.1, # 充放电倍率搜索范围-最小值
|
|
||||||
2.0, # 充放电倍率搜索范围-最大值
|
|
||||||
100, # 最大迭代次数
|
|
||||||
0.01 # 收敛容差
|
|
||||||
],
|
|
||||||
'参数说明': [
|
|
||||||
'光伏发电系统建设成本 (元/MW)',
|
|
||||||
'风力发电系统建设成本 (元/MW)',
|
|
||||||
'储能系统建设成本 (元/MWh)',
|
|
||||||
'从电网购电价格 (元/MWh)',
|
|
||||||
'向电网售电价格 (元/MWh)',
|
|
||||||
'光伏系统年度运维成本 (元/MW/年)',
|
|
||||||
'风电系统年度运维成本 (元/MW/年)',
|
|
||||||
'储能系统年度运维成本 (元/MW/年)',
|
|
||||||
'项目运营寿命 (年)',
|
|
||||||
'项目折现率 (用于NPV计算)',
|
|
||||||
'储能容量优化搜索范围下限 (MWh)',
|
|
||||||
'储能容量优化搜索范围上限 (MWh)',
|
|
||||||
'充放电倍率优化搜索范围下限',
|
|
||||||
'充放电倍率优化搜索范围上限',
|
|
||||||
'优化算法最大迭代次数',
|
|
||||||
'优化算法收敛容差'
|
|
||||||
],
|
|
||||||
'取值范围': [
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'≥0',
|
|
||||||
'≥0',
|
|
||||||
'≥0',
|
|
||||||
'≥0',
|
|
||||||
'>0',
|
|
||||||
'0-1',
|
|
||||||
'≥0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0',
|
|
||||||
'>0'
|
|
||||||
],
|
|
||||||
'默认值': [
|
|
||||||
'3,000,000',
|
|
||||||
'2,500,000',
|
|
||||||
'800,000',
|
|
||||||
'600',
|
|
||||||
'400',
|
|
||||||
'50,000',
|
|
||||||
'45,000',
|
|
||||||
'3,000',
|
|
||||||
'25',
|
|
||||||
'0.08',
|
|
||||||
'0',
|
|
||||||
'1000',
|
|
||||||
'0.1',
|
|
||||||
'2.0',
|
|
||||||
'100',
|
|
||||||
'0.01'
|
|
||||||
]
|
|
||||||
})
|
|
||||||
economic_params_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)
|
|
||||||
|
|
||||||
print(f"Excel模板已创建:{file_path}")
|
|
||||||
|
|
||||||
|
|
||||||
def analyze_excel_data(file_path: str) -> Dict[str, float]:
|
|
||||||
"""
|
|
||||||
分析Excel数据的基本统计信息
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Excel文件路径
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
包含统计信息的字典
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
data = read_excel_data(file_path)
|
|
||||||
|
|
||||||
solar = data['solar_output']
|
|
||||||
wind = data['wind_output']
|
|
||||||
thermal = data['thermal_output']
|
|
||||||
load = data['load_demand']
|
|
||||||
|
|
||||||
return {
|
|
||||||
'data_length': len(solar),
|
|
||||||
'total_solar': sum(solar),
|
|
||||||
'total_wind': sum(wind),
|
|
||||||
'total_thermal': sum(thermal),
|
|
||||||
'total_generation': sum(solar) + sum(wind) + sum(thermal),
|
|
||||||
'total_load': sum(load),
|
|
||||||
'max_solar': max(solar),
|
|
||||||
'max_wind': max(wind),
|
|
||||||
'max_thermal': max(thermal),
|
|
||||||
'max_load': max(load),
|
|
||||||
'avg_solar': np.mean(solar),
|
|
||||||
'avg_wind': np.mean(wind),
|
|
||||||
'avg_thermal': np.mean(thermal),
|
|
||||||
'avg_load': np.mean(load)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
print(f"分析数据失败:{str(e)}")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def read_economic_parameters(file_path: str):
|
|
||||||
"""
|
|
||||||
从Excel文件读取经济参数
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Excel文件路径
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
EconomicParameters对象
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
FileNotFoundError: 文件不存在
|
|
||||||
ValueError: 参数格式错误
|
|
||||||
"""
|
|
||||||
from economic_optimization import EconomicParameters
|
|
||||||
|
|
||||||
# 检查文件是否存在
|
|
||||||
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}' 不是有效的数值")
|
|
||||||
|
|
||||||
# 读取各参数值,如果找不到则使用默认值
|
|
||||||
get_param_value = lambda param_name: df_params.loc[df_params['参数名称'] == param_name, '参数值'].iloc[0] if param_name in df_params['参数名称'].values else None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 获取各参数值,区分None、NaN、0和有效值
|
|
||||||
def get_param_with_default(param_name, default_value):
|
|
||||||
value = get_param_value(param_name)
|
|
||||||
if value is None or pd.isna(value):
|
|
||||||
return default_value
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
return EconomicParameters(
|
|
||||||
solar_capex=get_param_with_default('光伏建设成本', 3000000),
|
|
||||||
wind_capex=get_param_with_default('风电建设成本', 2500000),
|
|
||||||
storage_capex=get_param_with_default('储能建设成本', 800000),
|
|
||||||
electricity_price=get_param_with_default('购电价格', 600),
|
|
||||||
feed_in_price=get_param_with_default('上网电价', 400),
|
|
||||||
solar_om=get_param_with_default('光伏运维成本', 50000),
|
|
||||||
wind_om=get_param_with_default('风电运维成本', 45000),
|
|
||||||
storage_om=get_param_with_default('储能运维成本', 3000),
|
|
||||||
project_lifetime=int(get_param_with_default('项目寿命', 25)),
|
|
||||||
discount_rate=get_param_with_default('折现率', 0.08)
|
|
||||||
)
|
|
||||||
except (KeyError, IndexError, Exception) as e:
|
|
||||||
print(f"读取经济参数失败:{str(e)},使用默认参数")
|
|
||||||
return EconomicParameters(
|
|
||||||
solar_capex=3000000,
|
|
||||||
wind_capex=2500000,
|
|
||||||
storage_capex=800000,
|
|
||||||
electricity_price=600,
|
|
||||||
feed_in_price=400,
|
|
||||||
solar_om=50000,
|
|
||||||
wind_om=45000,
|
|
||||||
storage_om=3000,
|
|
||||||
project_lifetime=25,
|
|
||||||
discount_rate=0.08
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"读取经济参数工作表失败,使用默认参数:{str(e)}")
|
|
||||||
# 如果经济参数工作表不存在或读取失败,返回默认参数
|
|
||||||
return EconomicParameters()
|
|
||||||
|
|
||||||
|
|
||||||
def get_optimization_settings(file_path: str) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
从Excel文件读取优化设置参数
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Excel文件路径
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
优化设置字典
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 读取经济参数工作表
|
|
||||||
df_params = pd.read_excel(file_path, sheet_name='经济参数')
|
|
||||||
|
|
||||||
# 提取优化设置参数
|
|
||||||
get_param_value = lambda param_name: df_params.loc[df_params['参数名称'] == param_name, '参数值'].iloc[0] if param_name in df_params['参数名称'].values else None
|
|
||||||
|
|
||||||
def get_param_with_default(param_name, default_value):
|
|
||||||
value = get_param_value(param_name)
|
|
||||||
if value is None or pd.isna(value):
|
|
||||||
return default_value
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
return {
|
|
||||||
'storage_capacity_range': (
|
|
||||||
get_param_with_default('储能容量搜索范围-最小值', 0),
|
|
||||||
get_param_with_default('储能容量搜索范围-最大值', 1000)
|
|
||||||
),
|
|
||||||
'rate_range': (
|
|
||||||
get_param_with_default('充放电倍率搜索范围-最小值', 0.1),
|
|
||||||
get_param_with_default('充放电倍率搜索范围-最大值', 2.0)
|
|
||||||
),
|
|
||||||
'max_iterations': int(get_param_with_default('最大迭代次数', 100)),
|
|
||||||
'tolerance': get_param_with_default('收敛容差', 0.01)
|
|
||||||
}
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"读取优化设置失败,使用默认设置:{str(e)}")
|
|
||||||
return {
|
|
||||||
'storage_capacity_range': (0, 1000),
|
|
||||||
'rate_range': (0.1, 2.0),
|
|
||||||
'max_iterations': 100,
|
|
||||||
'tolerance': 0.01
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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数据读取功能"""
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# 检查命令行参数
|
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == '--economic':
|
|
||||||
print("=== 创建经济优化Excel模板 ===")
|
|
||||||
|
|
||||||
# 创建经济优化模板文件
|
|
||||||
economic_template_8760 = "economic_data_template_8760.xlsx"
|
|
||||||
economic_template_24 = "economic_data_template_24.xlsx"
|
|
||||||
|
|
||||||
print("\n1. 创建经济优化Excel模板文件...")
|
|
||||||
create_excel_template(economic_template_8760, "8760")
|
|
||||||
create_excel_template(economic_template_24, "24")
|
|
||||||
|
|
||||||
print(f"\n[OK] 经济优化Excel模板创建完成!")
|
|
||||||
print(f"[FILE] 8760小时模板: {economic_template_8760}")
|
|
||||||
print(f"[FILE] 24小时模板: {economic_template_24}")
|
|
||||||
print(f"\n[INFO] 模板包含以下工作表:")
|
|
||||||
print(f" 1. 数据 - 8760小时电力数据")
|
|
||||||
print(f" 2. 参数 - 系统运行参数")
|
|
||||||
print(f" 3. 经济参数 - 经济优化参数")
|
|
||||||
print(f" 4. 说明 - 使用说明")
|
|
||||||
print(f"\n[USAGE] 使用方法:")
|
|
||||||
print(f" uv run python economic_optimization.py --excel {economic_template_8760}")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("=== Excel数据读取模块演示 ===")
|
|
||||||
|
|
||||||
# 创建模板文件
|
|
||||||
template_8760 = "data_template_8760.xlsx"
|
|
||||||
template_24 = "data_template_24.xlsx"
|
|
||||||
|
|
||||||
print("\n1. 创建Excel模板文件...")
|
|
||||||
create_excel_template(template_8760, "8760")
|
|
||||||
create_excel_template(template_24, "24")
|
|
||||||
|
|
||||||
# 分析模板数据
|
|
||||||
print(f"\n2. 分析{template_8760}数据...")
|
|
||||||
stats = analyze_excel_data(template_8760)
|
|
||||||
if stats:
|
|
||||||
print("数据统计信息:")
|
|
||||||
for key, value in stats.items():
|
|
||||||
print(f" {key}: {value:.2f}")
|
|
||||||
|
|
||||||
print(f"\n3. 演示读取{template_24}数据...")
|
|
||||||
try:
|
|
||||||
data = read_excel_data(template_24)
|
|
||||||
print(f"成功读取数据,类型:{data['data_type']}")
|
|
||||||
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__":
|
|
||||||
main()
|
|
||||||
28
main.py
28
main.py
@@ -320,6 +320,15 @@ def export_results_to_excel(solar_output, wind_output, thermal_output, load_dema
|
|||||||
grid_feed_out.append(power) # 上网电量
|
grid_feed_out.append(power) # 上网电量
|
||||||
|
|
||||||
# 创建主要数据DataFrame
|
# 创建主要数据DataFrame
|
||||||
|
# 计算弃电损失量(弃风+弃光)
|
||||||
|
curtailment_loss = [result['curtailed_wind'][i] + result['curtailed_solar'][i] for i in range(len(result['curtailed_wind']))]
|
||||||
|
# 计算累计弃电损失量
|
||||||
|
cumulative_curtailment = []
|
||||||
|
cumulative = 0
|
||||||
|
for loss in curtailment_loss:
|
||||||
|
cumulative += loss
|
||||||
|
cumulative_curtailment.append(cumulative)
|
||||||
|
|
||||||
data_df = pd.DataFrame({
|
data_df = pd.DataFrame({
|
||||||
'小时': hours,
|
'小时': hours,
|
||||||
'光伏出力(MW)': solar_output,
|
'光伏出力(MW)': solar_output,
|
||||||
@@ -332,6 +341,8 @@ def export_results_to_excel(solar_output, wind_output, thermal_output, load_dema
|
|||||||
'储能状态(MWh)': result['storage_profile'],
|
'储能状态(MWh)': result['storage_profile'],
|
||||||
'弃风量(MW)': result['curtailed_wind'],
|
'弃风量(MW)': result['curtailed_wind'],
|
||||||
'弃光量(MW)': result['curtailed_solar'],
|
'弃光量(MW)': result['curtailed_solar'],
|
||||||
|
'弃电损失量(MW)': curtailment_loss,
|
||||||
|
'累计弃电量(MWh)': cumulative_curtailment,
|
||||||
'购电量(MW)': grid_purchase,
|
'购电量(MW)': grid_purchase,
|
||||||
'上网电量(MW)': grid_feed_out
|
'上网电量(MW)': grid_feed_out
|
||||||
})
|
})
|
||||||
@@ -340,6 +351,15 @@ def export_results_to_excel(solar_output, wind_output, thermal_output, load_dema
|
|||||||
total_grid_feed_in = sum(result['grid_feed_in'])
|
total_grid_feed_in = sum(result['grid_feed_in'])
|
||||||
total_grid_purchase = sum(-x for x in result['grid_feed_in'] if x < 0) # 购电量
|
total_grid_purchase = sum(-x for x in result['grid_feed_in'] if x < 0) # 购电量
|
||||||
total_grid_feed_out = sum(x for x in result['grid_feed_in'] if x > 0) # 上网电量
|
total_grid_feed_out = sum(x for x in result['grid_feed_in'] if x > 0) # 上网电量
|
||||||
|
|
||||||
|
# 计算弃电损失量
|
||||||
|
total_curtail_wind = sum(result['curtailed_wind'])
|
||||||
|
total_curtail_solar = sum(result['curtailed_solar'])
|
||||||
|
total_curtail_energy = total_curtail_wind + total_curtail_solar
|
||||||
|
|
||||||
|
# 计算总潜在发电量
|
||||||
|
total_potential_generation = sum(solar_output) + sum(wind_output) + sum(thermal_output)
|
||||||
|
curtailment_loss_ratio = (total_curtail_energy / total_potential_generation * 100) if total_potential_generation > 0 else 0
|
||||||
|
|
||||||
stats_df = pd.DataFrame({
|
stats_df = pd.DataFrame({
|
||||||
'指标': [
|
'指标': [
|
||||||
@@ -351,6 +371,10 @@ def export_results_to_excel(solar_output, wind_output, thermal_output, load_dema
|
|||||||
'弃风率',
|
'弃风率',
|
||||||
'弃光率',
|
'弃光率',
|
||||||
'上网电量比例',
|
'上网电量比例',
|
||||||
|
'总弃风电量',
|
||||||
|
'总弃光电量',
|
||||||
|
'总弃电量',
|
||||||
|
'弃电损失比例',
|
||||||
'能量平衡校验',
|
'能量平衡校验',
|
||||||
'净购电量/净上网电量',
|
'净购电量/净上网电量',
|
||||||
'总购电量',
|
'总购电量',
|
||||||
@@ -366,6 +390,10 @@ def export_results_to_excel(solar_output, wind_output, thermal_output, load_dema
|
|||||||
f"{result['total_curtailment_wind_ratio']:.3f}",
|
f"{result['total_curtailment_wind_ratio']:.3f}",
|
||||||
f"{result['total_curtailment_solar_ratio']:.3f}",
|
f"{result['total_curtailment_solar_ratio']:.3f}",
|
||||||
f"{result['total_grid_feed_in_ratio']:.3f}",
|
f"{result['total_grid_feed_in_ratio']:.3f}",
|
||||||
|
f"{total_curtail_wind:.2f} MWh",
|
||||||
|
f"{total_curtail_solar:.2f} MWh",
|
||||||
|
f"{total_curtail_energy:.2f} MWh",
|
||||||
|
f"{curtailment_loss_ratio:.2f}%",
|
||||||
"通过" if result['energy_balance_check'] else "未通过",
|
"通过" if result['energy_balance_check'] else "未通过",
|
||||||
f"{-total_grid_feed_in:.2f} MWh" if total_grid_feed_in < 0 else f"{total_grid_feed_in:.2f} MWh",
|
f"{-total_grid_feed_in:.2f} MWh" if total_grid_feed_in < 0 else f"{total_grid_feed_in:.2f} MWh",
|
||||||
f"{total_grid_purchase:.2f} MWh",
|
f"{total_grid_purchase:.2f} MWh",
|
||||||
|
|||||||
Reference in New Issue
Block a user