362 lines
14 KiB
Python
362 lines
14 KiB
Python
|
|
# 多能互补系统储能容量优化计算程序测试用例
|
|||
|
|
|
|||
|
|
# 该文件包含单元测试和验证测试,确保程序在各种场景下的正确性。
|
|||
|
|
|
|||
|
|
# 作者: iFlow CLI
|
|||
|
|
# 创建日期: 2025-12-25
|
|||
|
|
|
|||
|
|
import unittest
|
|||
|
|
import numpy as np
|
|||
|
|
from storage_optimization import (
|
|||
|
|
optimize_storage_capacity,
|
|||
|
|
validate_inputs,
|
|||
|
|
calculate_energy_balance,
|
|||
|
|
check_constraints,
|
|||
|
|
SystemParameters
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestStorageOptimization(unittest.TestCase):
|
|||
|
|
"""储能优化程序测试类"""
|
|||
|
|
|
|||
|
|
def setUp(self):
|
|||
|
|
"""测试前的准备工作"""
|
|||
|
|
# 基础测试数据
|
|||
|
|
self.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
|
|||
|
|
self.wind_output = [2.0, 3.0, 4.0, 3.0, 2.0, 1.0] * 4
|
|||
|
|
self.thermal_output = [5.0] * 24
|
|||
|
|
self.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]
|
|||
|
|
self.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
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def test_validate_inputs_valid_data(self):
|
|||
|
|
"""测试有效输入数据的验证"""
|
|||
|
|
# 应该不抛出异常
|
|||
|
|
validate_inputs(self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params)
|
|||
|
|
|
|||
|
|
def test_validate_inputs_invalid_length(self):
|
|||
|
|
"""测试无效长度的输入数据"""
|
|||
|
|
with self.assertRaises(ValueError):
|
|||
|
|
validate_inputs([1.0] * 23, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params)
|
|||
|
|
|
|||
|
|
def test_validate_inputs_negative_values(self):
|
|||
|
|
"""测试包含负值的输入数据"""
|
|||
|
|
with self.assertRaises(ValueError):
|
|||
|
|
validate_inputs([-1.0] + self.solar_output[1:], self.wind_output,
|
|||
|
|
self.thermal_output, self.load_demand, self.params)
|
|||
|
|
|
|||
|
|
def test_validate_inputs_invalid_parameters(self):
|
|||
|
|
"""测试无效的参数设置"""
|
|||
|
|
invalid_params = SystemParameters(max_curtailment_wind=1.5) # 超出范围
|
|||
|
|
with self.assertRaises(ValueError):
|
|||
|
|
validate_inputs(self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, invalid_params)
|
|||
|
|
|
|||
|
|
def test_calculate_energy_balance_basic(self):
|
|||
|
|
"""测试基本电能平衡计算"""
|
|||
|
|
result = calculate_energy_balance(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params, 10.0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查返回结果包含所有必要的键
|
|||
|
|
expected_keys = ['storage_profile', 'charge_profile', 'discharge_profile',
|
|||
|
|
'curtailed_wind', 'curtailed_solar', 'grid_feed_in']
|
|||
|
|
for key in expected_keys:
|
|||
|
|
self.assertIn(key, result)
|
|||
|
|
self.assertEqual(len(result[key]), 24)
|
|||
|
|
|
|||
|
|
# 检查储能状态不为负
|
|||
|
|
self.assertTrue(all(soc >= 0 for soc in result['storage_profile']))
|
|||
|
|
|
|||
|
|
def test_check_constraints(self):
|
|||
|
|
"""测试约束条件检查"""
|
|||
|
|
# 先计算平衡结果
|
|||
|
|
balance_result = calculate_energy_balance(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params, 10.0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查约束
|
|||
|
|
constraint_results = check_constraints(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output, balance_result, self.params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查返回结果
|
|||
|
|
expected_keys = ['total_curtailment_wind_ratio', 'total_curtailment_solar_ratio',
|
|||
|
|
'total_grid_feed_in_ratio']
|
|||
|
|
for key in expected_keys:
|
|||
|
|
self.assertIn(key, constraint_results)
|
|||
|
|
self.assertGreaterEqual(constraint_results[key], 0)
|
|||
|
|
self.assertLessEqual(constraint_results[key], 1.0)
|
|||
|
|
|
|||
|
|
def test_optimize_storage_capacity_basic(self):
|
|||
|
|
"""测试基本储能容量优化"""
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查返回结果结构
|
|||
|
|
expected_keys = [
|
|||
|
|
'required_storage_capacity', 'storage_profile', 'charge_profile',
|
|||
|
|
'discharge_profile', 'curtailed_wind', 'curtailed_solar',
|
|||
|
|
'grid_feed_in', 'total_curtailment_wind_ratio',
|
|||
|
|
'total_curtailment_solar_ratio', 'total_grid_feed_in_ratio',
|
|||
|
|
'energy_balance_check'
|
|||
|
|
]
|
|||
|
|
for key in expected_keys:
|
|||
|
|
self.assertIn(key, result)
|
|||
|
|
|
|||
|
|
# 检查数值合理性
|
|||
|
|
self.assertGreaterEqual(result['required_storage_capacity'], 0)
|
|||
|
|
self.assertTrue(result['energy_balance_check'])
|
|||
|
|
|
|||
|
|
def test_zero_curtailment_scenario(self):
|
|||
|
|
"""测试零弃风弃光场景"""
|
|||
|
|
zero_curtail_params = SystemParameters(
|
|||
|
|
max_curtailment_wind=0.0,
|
|||
|
|
max_curtailment_solar=0.0,
|
|||
|
|
max_grid_ratio=0.2,
|
|||
|
|
storage_efficiency=0.9
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, zero_curtail_params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查弃风弃光率是否为0
|
|||
|
|
self.assertEqual(result['total_curtailment_wind_ratio'], 0.0)
|
|||
|
|
self.assertEqual(result['total_curtailment_solar_ratio'], 0.0)
|
|||
|
|
|
|||
|
|
def test_high_grid_ratio_scenario(self):
|
|||
|
|
"""测试高上网电量比例场景"""
|
|||
|
|
high_grid_params = SystemParameters(
|
|||
|
|
max_curtailment_wind=0.1,
|
|||
|
|
max_curtailment_solar=0.1,
|
|||
|
|
max_grid_ratio=0.5, # 高上网电量比例
|
|||
|
|
storage_efficiency=0.9
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, high_grid_params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查上网电量比例是否在约束范围内
|
|||
|
|
self.assertLessEqual(result['total_grid_feed_in_ratio'], 0.5)
|
|||
|
|
|
|||
|
|
def test_energy_balance_verification(self):
|
|||
|
|
"""测试能量平衡验证"""
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
self.load_demand, self.params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 手动验证能量平衡(使用新的计算方法)
|
|||
|
|
total_generation = sum(self.thermal_output) + sum(self.wind_output) + sum(self.solar_output)
|
|||
|
|
total_consumption = sum(self.load_demand)
|
|||
|
|
total_curtailed = sum(result['curtailed_wind']) + sum(result['curtailed_solar'])
|
|||
|
|
total_grid = sum(result['grid_feed_in'])
|
|||
|
|
total_charge = sum(result['charge_profile'])
|
|||
|
|
total_discharge = sum(result['discharge_profile'])
|
|||
|
|
|
|||
|
|
# 新的能量平衡计算:考虑储能效率
|
|||
|
|
energy_from_storage = total_discharge / self.params.storage_efficiency
|
|||
|
|
energy_to_storage = total_charge * self.params.storage_efficiency
|
|||
|
|
energy_balance = total_generation + energy_from_storage - total_consumption - energy_to_storage - total_curtailed - total_grid
|
|||
|
|
|
|||
|
|
# 能量平衡误差应该在合理范围内(考虑储能效率损失)
|
|||
|
|
tolerance = max(10.0, total_generation * 0.15)
|
|||
|
|
self.assertLessEqual(abs(energy_balance), tolerance)
|
|||
|
|
|
|||
|
|
def test_extreme_high_load_scenario(self):
|
|||
|
|
"""测试极高负荷场景"""
|
|||
|
|
high_load = [50.0] * 24 # 极高负荷
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
high_load, self.params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 应该返回一个结果,即使系统可能不平衡
|
|||
|
|
self.assertIsNotNone(result)
|
|||
|
|
self.assertGreater(result['required_storage_capacity'], 0)
|
|||
|
|
|
|||
|
|
def test_extreme_low_load_scenario(self):
|
|||
|
|
"""测试极低负荷场景"""
|
|||
|
|
low_load = [0.1] * 24 # 极低负荷
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.solar_output, self.wind_output, self.thermal_output,
|
|||
|
|
low_load, self.params
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 应该返回一个结果,可能有大量弃风弃光
|
|||
|
|
self.assertIsNotNone(result)
|
|||
|
|
self.assertGreaterEqual(result['total_curtailment_wind_ratio'], 0)
|
|||
|
|
self.assertGreaterEqual(result['total_curtailment_solar_ratio'], 0)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestKnownScenarios(unittest.TestCase):
|
|||
|
|
"""已知场景测试类"""
|
|||
|
|
|
|||
|
|
def test_perfect_balance_scenario(self):
|
|||
|
|
"""测试完美平衡场景"""
|
|||
|
|
# 设计一个完美平衡的场景
|
|||
|
|
solar = [2.0] * 6 + [4.0] * 6 + [2.0] * 6 + [0.0] * 6 # 48 MW
|
|||
|
|
wind = [3.0] * 12 + [1.0] * 12 # 48 MW
|
|||
|
|
thermal = [6.0] * 24 # 144 MW (增加了1 MW每小时)
|
|||
|
|
load = [10.0] * 24 # 恒定负荷 240 MW
|
|||
|
|
# 总发电量: 48 + 48 + 144 = 240 MW,与负荷平衡
|
|||
|
|
|
|||
|
|
params = SystemParameters(
|
|||
|
|
max_curtailment_wind=0.1,
|
|||
|
|
max_curtailment_solar=0.1,
|
|||
|
|
max_grid_ratio=0.2,
|
|||
|
|
storage_efficiency=0.9
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(solar, wind, thermal, load, params)
|
|||
|
|
|
|||
|
|
# 验证结果
|
|||
|
|
self.assertTrue(result['energy_balance_check'])
|
|||
|
|
self.assertLessEqual(result['total_curtailment_wind_ratio'], params.max_curtailment_wind)
|
|||
|
|
self.assertLessEqual(result['total_curtailment_solar_ratio'], params.max_curtailment_solar)
|
|||
|
|
self.assertLessEqual(result['total_grid_feed_in_ratio'], params.max_grid_ratio)
|
|||
|
|
|
|||
|
|
def test_no_renewable_scenario(self):
|
|||
|
|
"""测试无可再生能源场景"""
|
|||
|
|
solar = [0.0] * 24
|
|||
|
|
wind = [0.0] * 24
|
|||
|
|
thermal = [10.0] * 24
|
|||
|
|
load = [8.0] * 24
|
|||
|
|
|
|||
|
|
params = SystemParameters(
|
|||
|
|
max_curtailment_wind=0.1,
|
|||
|
|
max_curtailment_solar=0.1,
|
|||
|
|
max_grid_ratio=0.2,
|
|||
|
|
storage_efficiency=0.9
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(solar, wind, thermal, load, params)
|
|||
|
|
|
|||
|
|
# 验证结果
|
|||
|
|
self.assertTrue(result['energy_balance_check'])
|
|||
|
|
self.assertEqual(result['total_curtailment_wind_ratio'], 0.0)
|
|||
|
|
self.assertEqual(result['total_curtailment_solar_ratio'], 0.0)
|
|||
|
|
self.assertGreaterEqual(result['total_grid_feed_in_ratio'], 0)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def run_performance_test():
|
|||
|
|
"""运行性能测试"""
|
|||
|
|
print("\n=== 性能测试 ===")
|
|||
|
|
|
|||
|
|
# 生成随机测试数据
|
|||
|
|
np.random.seed(42)
|
|||
|
|
solar = np.random.exponential(3, 24).tolist()
|
|||
|
|
wind = np.random.exponential(2, 24).tolist()
|
|||
|
|
thermal = np.random.uniform(3, 8, 24).tolist()
|
|||
|
|
load = np.random.uniform(5, 15, 24).tolist()
|
|||
|
|
|
|||
|
|
params = SystemParameters()
|
|||
|
|
|
|||
|
|
import time
|
|||
|
|
start_time = time.time()
|
|||
|
|
|
|||
|
|
result = optimize_storage_capacity(solar, wind, thermal, load, params)
|
|||
|
|
|
|||
|
|
end_time = time.time()
|
|||
|
|
execution_time = end_time - start_time
|
|||
|
|
|
|||
|
|
print(f"执行时间: {execution_time:.4f} 秒")
|
|||
|
|
print(f"所需储能容量: {result['required_storage_capacity']:.2f} MWh")
|
|||
|
|
print(f"能量平衡校验: {'通过' if result['energy_balance_check'] else '未通过'}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestYearlyData(unittest.TestCase):
|
|||
|
|
"""8760小时数据测试类"""
|
|||
|
|
|
|||
|
|
def setUp(self):
|
|||
|
|
"""测试前的准备工作"""
|
|||
|
|
# 生成简化的8760小时测试数据(每小时的重复模式)
|
|||
|
|
daily_pattern = [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]
|
|||
|
|
self.yearly_load = daily_pattern * 365 # 24 * 365 = 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
|
|||
|
|
|
|||
|
|
self.yearly_solar = daily_solar * 365
|
|||
|
|
self.yearly_wind = daily_wind * 365
|
|||
|
|
self.yearly_thermal = daily_thermal * 365
|
|||
|
|
|
|||
|
|
self.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
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def test_yearly_data_validation(self):
|
|||
|
|
"""测试8760小时数据验证"""
|
|||
|
|
# 验证数据长度
|
|||
|
|
self.assertEqual(len(self.yearly_solar), 8760)
|
|||
|
|
self.assertEqual(len(self.yearly_wind), 8760)
|
|||
|
|
self.assertEqual(len(self.yearly_thermal), 8760)
|
|||
|
|
self.assertEqual(len(self.yearly_load), 8760)
|
|||
|
|
|
|||
|
|
# 验证不会抛出异常
|
|||
|
|
validate_inputs(self.yearly_solar, self.yearly_wind, self.yearly_thermal,
|
|||
|
|
self.yearly_load, self.params)
|
|||
|
|
|
|||
|
|
def test_yearly_basic_optimization(self):
|
|||
|
|
"""测试8760小时基本优化"""
|
|||
|
|
# 使用较小的迭代次数以加快测试
|
|||
|
|
result = optimize_storage_capacity(
|
|||
|
|
self.yearly_solar, self.yearly_wind, self.yearly_thermal,
|
|||
|
|
self.yearly_load, self.params, max_iterations=50
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 检查返回结果结构
|
|||
|
|
expected_keys = [
|
|||
|
|
'required_storage_capacity', 'storage_profile', 'charge_profile',
|
|||
|
|
'discharge_profile', 'curtailed_wind', 'curtailed_solar',
|
|||
|
|
'grid_feed_in', 'total_curtailment_wind_ratio',
|
|||
|
|
'total_curtailment_solar_ratio', 'total_grid_feed_in_ratio',
|
|||
|
|
'energy_balance_check'
|
|||
|
|
]
|
|||
|
|
for key in expected_keys:
|
|||
|
|
self.assertIn(key, result)
|
|||
|
|
|
|||
|
|
# 检查数据长度
|
|||
|
|
self.assertEqual(len(result['storage_profile']), 8760)
|
|||
|
|
self.assertEqual(len(result['charge_profile']), 8760)
|
|||
|
|
self.assertEqual(len(result['discharge_profile']), 8760)
|
|||
|
|
|
|||
|
|
# 检查数值合理性
|
|||
|
|
self.assertGreaterEqual(result['required_storage_capacity'], 0)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
print("运行多能互补系统储能容量优化程序测试...")
|
|||
|
|
|
|||
|
|
# 运行单元测试
|
|||
|
|
unittest.main(argv=[''], exit=False, verbosity=2)
|
|||
|
|
|
|||
|
|
# 运行性能测试
|
|||
|
|
run_performance_test()
|