CVXPy凸优化在工商业光储系统优化中未达最优性能的问询
工商业光储系统CVXPy凸优化方案改进建议
问题概述
我正在优化一套由1MWh电池系统与200kW额定容量光伏组成的工商业光储系统,核心目标是降低建筑电费。工商业电费包含两部分:
- 基于月度总能耗的能源费
- 基于15分钟间隔峰值用电量的需求费
费率采用分时计价(TOU)策略。
优化方向为最小化月度能耗以削减能源费,同时通过电池储电平抑用电尖峰、降低需求费,理想运行逻辑是:光伏出力过剩时给电池充电,负载需求过剩时电池放电补能。目前负载跟随算法已实现接近理想的优化效果,但采用CVXPy凸优化方案时性能极差——甚至比不使用电池的情况更糟,能源消耗增加且需求费上升。已排查代码、目标函数与约束条件,未发现明显问题,推测可能是求解器优先将过剩电力并网导致尖峰出现,特此寻求改进建议。
附:翻译后的代码
凸优化CVXPy代码及输出(中文翻译版)
# 导入CVXPy库 import cvxpy as cp # 基础参数定义 time_step = 0.25 # 时间步长:15分钟(0.25小时) num_steps = 2880 # 月度总时间步数(按30天计算:30*24/0.25) # 优化变量定义 grid_purchase = cp.Variable(num_steps, nonneg=True) # 电网购电功率(kW) pv_output = cp.Parameter(num_steps, nonneg=True) # 光伏出力(kW,已知输入) load_demand = cp.Parameter(num_steps, nonneg=True) # 负载需求(kW,已知输入) battery_charge = cp.Variable(num_steps, nonneg=True) # 电池充电功率(kW) battery_discharge = cp.Variable(num_steps, nonneg=True) # 电池放电功率(kW) soc = cp.Variable(num_steps+1, nonneg=True) # 电池荷电状态(SOC,kWh) peak_demand = cp.Variable(nonneg=True) # 15分钟最大用电峰值(kW) # 费率参数 energy_rates = cp.Parameter(num_steps) # 分时能源费率(元/kWh) demand_rate = cp.Parameter() # 需求费费率(元/kW) # 目标函数:最小化月度总电费(能源费+需求费) objective = cp.Minimize( cp.sum(grid_purchase * time_step * energy_rates) + demand_rate * peak_demand ) # 约束条件 constraints = [] # 功率平衡:电网购电 + 光伏出力 + 电池放电 = 负载需求 + 电池充电 constraints += [ grid_purchase[i] + pv_output[i] + battery_discharge[i] == load_demand[i] + battery_charge[i] for i in range(num_steps) ] # 电池功率限制:充电/放电功率不超过额定值(假设为200kW) constraints += [battery_charge[i] <= 200 for i in range(num_steps)] constraints += [battery_discharge[i] <= 200 for i in range(num_steps)] # SOC约束:初始与结束SOC一致(月度循环),SOC范围0~1000kWh constraints += [soc[0] == soc[-1]] constraints += [soc[i] >= 0 for i in range(num_steps+1)] constraints += [soc[i] <= 1000 for i in range(num_steps+1)] # SOC变化逻辑:SOC(t+1) = SOC(t) + (充电功率-放电功率)*时间步长 constraints += [ soc[i+1] == soc[i] + (battery_charge[i] - battery_discharge[i]) * time_step for i in range(num_steps) ] # 峰值需求约束:每个时间步的电网购电不超过峰值 constraints += [grid_purchase[i] <= peak_demand for i in range(num_steps)] # 求解优化问题 prob = cp.Problem(objective, constraints) prob.solve(solver=cp.GUROBI) # 输出结果 print("月度总电费:", prob.value) print("峰值需求:", peak_demand.value)
负载跟随算法代码(中文翻译版)
# 基础参数初始化 time_step = 0.25 # 时间步长:15分钟 battery_capacity = 1000 # 电池额定容量:1MWh max_charge_power = 200 # 电池最大充电功率:200kW max_discharge_power = 200 # 电池最大放电功率:200kW initial_soc = 500 # 初始SOC:500kWh soc = initial_soc total_grid_energy = 0 # 月度电网购电总量(kWh) peak_demand = 0 # 15分钟用电峰值(kW) # 遍历每个时间步执行负载跟随逻辑 for i in range(len(pv_output_data)): pv = pv_output_data[i] load = load_demand_data[i] net_load = load - pv # 净负载:需求-光伏出力 charge = 0 discharge = 0 if net_load < 0: # 光伏过剩,优先给电池充电 available_charge = -net_load max_possible_charge = min(max_charge_power, (battery_capacity - soc)/time_step) charge = min(available_charge, max_possible_charge) soc += charge * time_step # 剩余过剩电力并网(若允许) grid_export = available_charge - charge else: # 负载过剩,优先电池放电补能 needed_discharge = net_load max_possible_discharge = min(max_discharge_power, soc/time_step) discharge = min(needed_discharge, max_possible_discharge) soc -= discharge * time_step # 不足部分从电网购电 grid_import = needed_discharge - discharge total_grid_energy += grid_import * time_step # 更新峰值需求 if grid_import > peak_demand: peak_demand = grid_import # 计算月度总电费 total_cost = total_grid_energy * average_energy_rate + peak_demand * demand_rate print("月度总电费:", total_cost) print("峰值需求:", peak_demand)
改进建议
1. 修正目标函数的优先级与逻辑
当前目标函数可能因权重分配不合理,导致求解器优先选择并网(若有收益)而非储电削峰。建议:
- 若并网收益远低于需求费支出,直接在目标函数中移除并网收益项,或添加惩罚项抑制并网行为;
- 采用分层优化逻辑:先添加约束锁定峰值需求上限,再最小化能源费,避免求解器为小额收益牺牲峰值控制。
2. 添加约束限制过剩电力并网
针对“求解器优先并网导致尖峰”的推测,可通过约束强制优先储电:
- 若不需要并网,直接添加
grid_export = 0(或在功率平衡中移除并网变量),强制过剩光伏全部用于电池充电(在电池容量/功率限制内); - 若允许并网,设置并网功率上限(如
grid_export[i] <= 50),降低求解器选择并网的优先级。
3. 明确需求费的计算基准
需求费的计算基准(电网购电峰值/建筑总用电峰值)直接影响约束逻辑,需确认后修正:
- 若需求费基于电网购电峰值,约束
grid_purchase[i] <= peak_demand是正确的; - 若基于建筑总用电峰值,需将约束改为
load_demand[i] <= peak_demand + pv_output[i] + battery_discharge[i],避免求解器通过电网购电补能推高峰值。
4. 优化求解器设置与验证
- 更换求解器:尝试使用GUROBI、CPLEX等商业求解器(默认ECOS可能在复杂问题上表现不佳),不同求解器的优化策略差异可能解决当前问题;
- 开启求解器日志:设置
solver=cp.GUROBI, verbose=True,查看求解过程中变量的取值变化,定位是否存在异常并网或电池充放电行为; - 添加正则项:对电池充放电功率的变化率添加约束(如
battery_charge[i+1] - battery_charge[i] <= 50),避免求解器出现极端充放电操作。
5. 验证凸性与约束合理性
确保整个优化问题是严格凸的:
- 将
peak_demand变量替换为cp.max(grid_purchase)(CVXPy支持cp.max作为凸函数),避免手动定义峰值变量可能导致的非凸问题; - 检查所有约束是否为线性或凸约束,排除非凸等式/不等式(如绝对值、平方项的错误使用)。
内容的提问来源于stack exchange,提问作者Luis Enriquez-Contreras
相关产品推荐
相关产品推荐

