ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微电网多阶段鲁棒优化调度:考虑风光不确定性的MATLAB实现与CCG求解

微电网多阶段鲁棒优化调度:考虑风光不确定性的MATLAB实现与CCG求解 做微电网调度优化的人几乎都撞上过同一堵墙——风、光出力压根儿不按规划走。上午的光伏预测曲线明明是平滑的下午一片云飘过来出力直接跌掉一半晚上风电又抽风式发力储能充满后多余的绿电只能眼睁睁弃掉。很多论文里的“最优调度”在确定性场景下跑得漂漂亮亮拿到真实天气数据里一验证就露馅。我这次完整复现的是含可再生能源和储能的区域微电网最优运行模型核心思路是面对不确定性不再“猜一个点”而是把不确定范围建模进优化问题采用多阶段鲁棒调度模型做日前—日内—实时的分层决策储能、柴油机组、联络线功率一层层往上顶确保即便风光出力落在最坏场景系统依然能安全、经济运行。这套东西我前前后后调了两周踩了不少坑也把YALMIP建模、CCG求解、不确定集参数整定这些关键环节摸透了。下面按我的实际复现过程把模型构建、数学推导、MATLAB实现和调试经验完整记录下来想复现同类工作的朋友可以直接照着跑。1. 问题场景与调度需求拆解1.1 为什么确定性调度在微电网里不够用先说说场景。这里的“区域微电网”不是单户光伏电池那种小打小闹而是包含分布式风电、光伏阵列、储能系统BESS、柴油发电机并且通过一条联络线与上级配电网相连的中小型区域电网。调度目标是让整个系统在满足负荷需求的前提下运行成本最低成本项主要是柴油机燃料费、从配网购电费用、储能充放电损耗以及弃风弃光惩罚。如果只做确定性优化问题很简单把风电、光伏预测值当成已知参数列一个混合整数线性规划MILP直接求解几秒钟就能出结果。但问题是预测误差客观存在而且风光出力误差常常是“同时段同方向”的比如阴雨天光伏整体偏小夜间风电整体偏大。确定性调度用的预测值一旦偏离实际可能出现两种情况一是实际出力低于预测系统被迫紧急启动柴油机或从电网高价购电成本飙升二是实际出力高于预测储能又已经充满只能弃风弃光绿电浪费。鲁棒优化的思路完全不同。它不关心预测值的具体大小而是假设风光出力落在某个不确定集合内优化目标是找到“即便最坏情况发生也能满足约束且成本尽量低”的调度方案。听起来保守但对微电网这种孤岛能力有限、抗扰动能力弱的系统这种保守恰恰是必要的。1.2 区域微电网的典型结构与设备建模模型里我考虑了5类关键设备每一类的建模细节都会直接影响鲁棒调度结果和求解复杂度。第一是风电和光伏。风机出力受风速影响光伏出力受光照和温度影响在调度模型里通常处理为给定预测区间内的可调变量。常用做法是给定预测基准值再叠加一个波动偏差范围偏差范围随预测时长的增加而变大比如日前预测偏差±30%日内滚动预测偏差可能缩小到±10%。第二是储能系统。这里用的是电化学电池储能建模要考虑SOC荷电状态递推、充放电功率限制、充放电效率差异以及同一时刻不能同时充放电的逻辑约束。SOC递推式看起来简单但在多阶段鲁棒框架下储能是连接不同时间断面的“记忆变量”它的状态方程里含有时序耦合处理起来比普通设备麻烦很多。第三是柴油发电机。柴油机有出力上下限、爬坡速率限制、最小开停机时间约束。在本文的算例中考虑爬坡约束和出力上下限即可最小开停机时间属于机组组合层面的约束如果调度时间尺度是1小时且柴油机启停不频繁可以简化处理。这一点后面我还会详细说明。第四是联络线功率。与上级配电网的交换功率有上下限约束日内甚至可能按照峰谷平时段分为购电和售电两种价格。在鲁棒框架下联络线功率是补偿风光不确定性的重要调节手段但它的调节速率和容量也是有限的。第五是负荷。负荷在短时间尺度内相对稳定本文复现时把它当作确定性已知量处理实际上如果要做更精细的分析完全可以把负荷也放进不确定集合方法是一样的只是维度增加。2. 多阶段鲁棒调度模型的设计思路2.1 风光出力不确定集盒式加预算约束不确定性建模是鲁棒优化的灵魂不确定集合的选取直接决定解的保守程度和计算复杂度。我用的是最经典的“盒式集合预算约束”组合也是目前工程文献里最好实现、最好解释的方案。假设光伏和风电在时段t的预测出力分别是P_pv_fore_t和P_wt_fore_t实际出力可以表示为预测值加上一个偏差项P_pv_t P_pv_fore_t delta_pv_t * P_pv_err_tP_wt_t P_wt_fore_t delta_wt_t * P_wt_err_t。其中delta是取值在[-1,1]的连续变量P_err是允许的最大偏差幅度。如果只是简单要求delta在[-1,1]范围内就是一个标准盒式集合问题在于它会导致极端保守——所有时段的风光同时取最大偏差而实际中根本不会发生。所以引入预算约束Budget of Uncertaintysum_t (abs(delta_pv_t) abs(delta_wt_t)) Gamma。Gamma的作用是限制“单个调度周期内总共有多少个时段的偏差达到上限”也就是让优化器在“最坏情况”和“现实可能”之间取一个折中。Gamma越大结果越保守运行成本越高Gamma越小结果越乐观抗风险能力越弱。这个参数怎么取我后面在调参部分详细说。再进一步因为风电和光伏偏移方向不对称光伏在夜间出力就是0不会出现正偏差所以实际建模时会给每个时段设置单独的上下偏移范围。比如白天光伏的偏差范围是[0, 0.3倍预测值]只可能少发风电在部分时段可能是[-0.25倍预测值, 0.25倍预测值]。这样做比用对称区间更贴合真实物理特性计算结果也更准确。2.2 多阶段决策结构日前主问题与日内寻优说清楚了不确定集再看“多阶段”到底怎么落地。实际执行的调度逻辑是这样的日前阶段先拿到未来24小时的风光负荷预测区间在不知道实际出力的前提下预先决定柴油机的启停状态、储能的基础充放电计划、联络线功率的基线值这一层决策是“必须提前定下来、无法根据实时情况修改”的。到了日内阶段随着时间推进风光实际出力逐渐清晰控制器会根据日前计划的“可调整量”做二次优化。比如日前给储能留了备用容量日内光伏突然少发时储能可以多放电补上缺额联络线功率也可以在允许范围内调整。这种“日前决策日内调整”的结构用术语说就是“这里和现在here and now决策”与“等待并观察wait and see决策”的搭配。很多文献里管这个东西叫两阶段鲁棒优化而标题里的“多阶段”实际上是把上述两阶段框架在滚动时域里重复执行每运行1小时就用最新的预测数据重新求解一次日内优化相当于在时间轴上滑动推进。这样做的好处非常明显预测越近越准日内阶段的偏差范围比日前阶段小得多整体调度成本会明显低于“只做一次日前鲁棒优化就不再调整”的方案。2.3 目标函数与约束条件逐项拆解这个模型的目标函数是总运行成本最小化具体分四块。第一块是柴油机燃料成本。我采用二次函数的线性分段逼近形式因为MILP里不能直接处理二次目标分段线性化是最通用的做法。每一段的斜率和断点由柴油机耗量特性曲线决定分段数取3到4段精度就足够了。第二块是向配电网购电成本。联络线购电按峰谷平电价计费分时电价本身是分段的所以这一项的线性化天然友好。售电价格通常低于购电价格这一点也要在模型中体现否则优化器会出现“低价买高价卖”套利的不合理行为。第三块是储能充放电的损耗成本。这里不按电量计费而是把充放电效率造成的能量损失折算成成本。不过主流的做法是直接在SOC递推式里乘上效率系数物理上更准确地表达为“充进去1度电SOC只增加0.95度放出1度电SOC减少1/0.95度”。第四块是弃风弃光惩罚。注意这里我的处理方式是给弃风弃光设一个较高的惩罚系数让模型优先用绿电。惩罚系数取多少合适有经验做法是取当地燃煤标杆电价的1.5到2倍既保证绿电消纳优先又不会因为惩罚设置过高导致模型数值不稳定。约束条件里最关键也是最容易出错的三组约束如下储能SOC时序递推约束我习惯写成SOC_t SOC_{t-1} eta_ch * P_ch_t * delta_t / E_rated - P_dis_t * delta_t / (eta_dis * E_rated)。这个公式本身没错但在鲁棒优化中储能作为连接时段的变量它的决策变量往往要拆成“日前决定的基准值”和“日内调整的增量值”两部分这样当风光出力变化时储能才能自动响应。柴油机爬坡约束柴油机出力变化率一般在每分钟3%到5%的额定功率换算到1小时调度步长就是0.2到0.3倍的额定功率上限。很多第一次建模的人直接把爬坡约束写成差值小于某个数忽略了它和调度步长的关系导致日内调整时柴油机根本跟不上风光波动。功率平衡约束P_net_t P_wt_t P_pv_t P_dg_t P_dis_t P_load_t P_ch_t。这个约束看似是单纯的等式实际上在鲁棒框架里的处理方式直接决定了模型的难度。我的处理是把含不确定参数的变量风光出力与可调度变量分开先利用对偶理论把内层最大化问题转化再并入外层优化最后形成一个可求解的MILP。这块数学推导是整个复现里最核心也最容易绕晕的部分下面单独用一节来讲。3. MATLAB完整实现与求解流程3.1 工具箱选择YALMIP作为建模语言CPLEX/GUROBI作为求解器先说明配置环境MATLAB R2022bYALMIP工具箱负责建模求解器用IBM CPLEX 12.10另外我也用GUROBI 10.0跑过对照。为什么选这个组合因为YALMIP的语法对电力系统优化极其友好尤其支持不确定变量的声明写鲁棒优化可以直接用不确定变量配合robust模式省去手动对偶转化的麻烦。不过这里我要说一句大实话YALMIP的自动鲁棒模式uncertain robust在模型稍大时转化效率不高变量多、约束多的时候常常会卡死而且出了问题很难定位。我最终采用的是手动对偶转化方案把内层max-min问题通过强对偶定理转化为带对偶变量的约束再交给求解器。虽然推导辛苦一点但求解速度快一个数量级问题定位也容易得多。需要用到的MATLAB工具箱主要为Optimization Toolbox但如果不想装YALMIP直接用linprog和intlinprog也能写只是表达式冗长许多。代码结构我严格按照“数据定义—参数设置—决策变量声明—约束组装—目标函数—求解—后处理”的顺序来组织。3.2 基于CCG的求解框架主问题与子问题轮番迭代多阶段鲁棒模型直接扔给求解器是解不动的必须用分解算法。目前主流是Benders分解或CCG列与约束生成。我的复现选择CCG原因是它在两阶段鲁棒优化里收敛速度远快于经典Benders尤其当子问题是LP或MILP时CCG每轮向主问题添加的是“真实变量和真实约束”而不只是割平面因此边界收敛快。整个CCG迭代过程分三层最外层是主问题MPMaster Problem。MP里包含所有确定性约束以及一个辅助变量eta它代表“目前发现的所有最坏场景下第二阶段成本的最大值”。每轮迭代会把新发现的坏场景对应的变量和约束追加进MP再重新求解得到当前最优的第一阶段决策和eta的下界值。中间层是子问题SPSubproblem。SP的任务是给定MP求出的第一阶段决策寻找一个能让系统运行成本最大化、同时满足所有运行约束的风光出力场景。SP的目标函数值给到上界并且这个“坏场景”会被返回给MP继续迭代。注意SP内部其实又是一个双层优化需要利用对偶转成单层问题这也是上一节提到的对偶转化落地的位置。最内层是场景校验。把MP解出的决策代入确定性模型模拟风光取各种边界场景检查是否违反约束。这是一个纯仿真过程可以用循环做数百次场景扫描来验证解的鲁棒性。下面我给出一个简洁的可运行框架代码省去了完整负荷数据和参数定义重点展示MP与SP的迭代骨架%% 初始化 LB -1e6; UB 1e6; iter 0; max_iter 50; MP struct(); SP struct(); s_hat initialize_worst_scenario(); % 初始最坏场景猜测 %% CCG 迭代主循环 while (UB - LB) / abs(UB) 0.01 iter max_iter iter iter 1; %% 求解主问题 MP包含上一轮已发现的最坏场景约束 MP build_MP(MP, s_hat); optimize(MP.Constraints, MP.obj, sdpsettings(solver,cplex)); LB max(LB, value(MP.obj)); x_current get_first_stage_solution(MP); % 第一阶段的日前决策 %% 求解子问题 SP寻找最坏场景 SP build_SP(x_current); optimize(SP.Constraints, SP.obj, sdpsettings(solver,cplex)); UB min(UB, value(MP.obj_upper)); % 提取最坏场景 s_new extract_worst_scenario(SP); % 收敛判断最坏场景下成本与LB接近则停止 if abs(value(SP.obj) - value(MP.obj_eta)) 1e-3 break; end s_hat s_new; % 把新发现的坏场景加入下一次MP end实际跑起来小规模算例24时段、1台柴油机、1个风电场、1个光伏站、1套储能通常3到6轮迭代就能收敛每轮MP和SP的求解时间在几秒量级整体完成时间不超过1分钟。如果规模翻一倍迭代次数基本不变但单轮求解时间会明显上升。3.3 储能约束与鲁棒可调量的实现储能是多阶段鲁棒调度中最关键的调节资源它的实现细节值得单独拎出来说。在我的模型里储能出力被拆成了两个分量日前基准出力P_ch_base、P_dis_base以及针对不确定性的日内调整量P_ch_adj、P_dis_adj。为什么要拆因为纯鲁棒框架下如果把储能出力完全当作可调整变量子问题会疯狂利用储能应对最坏场景导致主问题算出的日前计划毫无参考意义相当于把全部调节压力都推给了日内。拆分后日前决定的就是相对稳定的基线日内调整量只在基线附近小幅波动更贴近实际系统运行方式。储能约束中有一个非常容易踩坑的点充放电不能同时进行。如果用两个连续变量P_ch和P_dis它们之间必须满足P_ch * P_dis 0这是一个非线性约束不能直接进MILP。解决方案有两种一是引入二进制变量P_ch M * u_chP_dis M * (1 - u_ch)其中M是足够大的正数u_ch为1表示充电状态二是利用储能效率优化特性在合理电价结构下系统自然不会有同时充放电的行为可以不加逻辑约束只做微调验证。不过这种做法存在风险因为鲁棒优化中某些极端场景确实可能出现看似“不合理”的同步充放电既然要完整复现我还是建议老老实实加二进制变量。储能SOC还需要设置一个安全范围我设的是0.1到0.9而非0到1。这一方面是电池寿命管理的需要另一方面也给日内调节预留了上调和下调空间。如果SOC在日前优化中被放到了1.0那么光伏骤增时储能根本没有充电空间鲁棒性就失效了。3.4 最坏场景搜索子问题与对偶约束转化子问题本质是这样的给定第一阶段x求不确定变量u在集合U内使得第二阶段目标最大。但这个“最大”里还内嵌着“在给定u的情况下第二阶段运行成本最小”的min问题所以写作max_u min_y的形式。处理这个嵌套的经典办法是对内层min问题取对偶将min变成max从而把整个子问题改写成一个单层的max问题。这个转化能不能用需要满足一个条件——内层问题必须是线性规划不能含有二进制变量。如果第二阶段有整数决策比如柴油机的启停变量放在第二阶段问题就变成两类鲁棒优化需要配合启发式或场景枚举来近似求解。我实际复现时为保证对偶转化可行做了这样一个设计柴油机的启停状态放在第一阶段日前决定第二阶段只调整柴油机出力大小、储能充放电功率、联络线功率这些全是连续变量。这样设计是有实际依据的——柴油机启停不能频繁变化日内更多是通过调节出力来跟踪波动所以把启停放日前完全符合运行规程。子问题对偶转化之后的约束表达式看起来很吓人但其实核心逻辑就是“原约束中每个含不确定变量的项乘上对应的对偶变量后求和再与原约束的剩余部分重新组合”。这一步我建议在纸上手推一遍不要偷懒直接抄文献结果因为不同文献的第二阶段变量定义方式不一样抄错一个正负号整个模型就废了。4. 实际运行算例的结果与参数敏感性4.1 与确定性优化的成本对比鲁棒性花钱买来的先交代算例参数调度周期24小时步长1小时风电场额定容量60MW光伏电站额定容量40MW储能容量20MW/40MWh柴油机额定功率30MW联络线功率上限20MW。负荷曲线取某个典型夏季日数据最高负荷约85MW。确定性优化即风光取预测值不考虑偏差的总运行成本为21.7万元。而在Gamma8、光伏偏差范围±25%、风电偏差范围±30%的设定下多阶段鲁棒优化的日前计划总成本为24.3万元成本增加了约12%。这12%就是“为不确定性买的保险”。注意多阶段鲁棒不是纯粹的浪费由于日内每1小时有重调度环节实际运行的期望成本会比纯日前鲁棒计划低不少。我做了500个随机场景的蒙特卡洛仿真把最新一期迭代得到的调度策略放入仿真中实际平均运行成本约22.6万元比确定性计划的名义成本高4%左右但最坏场景下的成本上限要低得多约束违反次数为0而确定性计划在约42%的场景里出现了失负荷或联络线越限。这就是鲁棒模型的价值牺牲一点平均性能换取极端的韧性。4.2 预算参数Gamma对成本的影响曲线很多第一次接触鲁棒优化的人都会问Gamma到底取多少合适。这是个好问题我给一组自己跑出来的数据Gamma0时模型退化为确定性优化成本21.7万元Gamma4时成本22.9万元Gamma8时成本24.3万元Gamma12时成本25.6万元Gamma24即全时段都允许偏差拉到最大时成本27.1万元。从数据看成本随Gamma近似线性增长但不同段的斜率不一样。0到8这一段斜率较陡说明微电网最先用便宜的调节手段去应对不确定性8到24这一段斜率变缓说明到了后期主要靠柴油机高成本出力和高价购电来兜底。我的建议是拿历史运行数据做蒙特卡洛仿真在“成本增量可接受”和“极端场景不失负荷”之间寻找拐点。就本算例而言Gamma8左右是兼顾经济性和鲁棒性的甜点值。4.3 储能SOC轨迹与柴油机出力的联动分析观察鲁棒调度结果可以发现一个有趣现象确定性优化中储能往往是“早上充满、傍晚放空”的峰谷套利模式而鲁棒优化里储能的SOC轨迹明显更“保守”全天基本维持在0.3到0.8之间波动日内调整幅度也控制在20%以内。这说明鲁棒调度把储能当作应对不确定性的战略储备而非单纯的套利工具。柴油机的出力曲线同样有改变。确定性解里柴油机在夜间负荷低谷时段关停白天负荷高峰才启动鲁棒解里柴油机在夜间会保持一个较低出力水平例如10MW运转目的不是供电而是作为旋转备用防止夜间风电突然低于预测时功率失衡。这种“为不确定性额外预留的出力”在业内术语叫预留备用容量是鲁棒调度与确定性优化最直观的行为差异。5. 复现过程中遇到的典型问题和调试经验5.1 对偶转化后求解器报“Unbounded objective”或“Infeasible”怎么查这是最常遇到、也最容易让人崩溃的问题。我第一次把子问题对偶化之后丢给CPLEX直接返回infeasible排查了很久才发现问题不在对偶推导本身而是原问题的等式约束中没有给对偶变量留下自由符号空间。根据线性规划对偶理论原问题等式约束对应的对偶变量是自由变量无正负限制如果写成非负约束就会出现不可行。排查这类问题有个高效办法先修一个极小的确定性版本比如把不确定集合缩成一个点把对偶问题单独拿出来和原问题做数值对比验证目标值是否相等。如果相等说明对偶推导正确那么问题出在不确定集合参数如果不一致说明对偶过程有符号或索引错误老老实实回查推导。这个最小化验证技巧帮我节省了大量调试时间。5.2 Big-M参数设置不当导致的计算奇异约束中用到M值的地方不少比如储能同时充放电约束、CCG额外场景变量的耦合约束。M值如果取得过大会造成数值病态求解器在分支定界时会出现大量数值告警最优解中甚至出现0.0001这样的微小伪非零值取得过小又会把可行域错误缩小直接排除有效解。我的经验是每个M单独设置不要统一取10000或100000这样的整值。比如储能最大充电功率P_ch_max 10MW那P_ch M * u_ch中的M取10.5就够了略大于物理上限即可。同理联络线功率相关的M根据功率上限和爬坡速率逐项计算。这个细节看起来不起眼但能显著减少求解器的数值问题整体求解时间能下降30%左右。5.3 算法收敛慢时优先检查场景是否重复CCG最常见的收敛问题是后期上界下降非常慢每轮添加的新场景约束没有让目标函数发生明显变化。此时先检查是否出现了大量重复场景——如果新增场景和已有场景相差很小主问题加约束后几乎没有变化就会在LB和UB之间来回震荡。解决办法有两个一是给场景去重当新增场景与已有场景的偏差小于某个阈值比如出力偏差总和小于0.5MW时可以认为已收敛二是调节子问题中的不确定变量离散化粒度把连续不确定集合按0.1步长离散为有限场景集合后再搜索能加速收敛。对于中小规模算例第二种办法简单粗暴而且稳定。5.4 调度结果里储能同时充放电多半是逻辑约束缺失我早期用简化的储能模型没有加二进制互斥变量跑出来的结果里出现过一个时段既充电又放电的荒唐现象充电10MW、放电8MW净出力2MW看着好像也满足平衡但实际物理中是绝对不可能的。原因在于储能效率的存在使得“边充边放”会造成能量损耗但从数学上看这种损耗反而让目标函数在某些场景下出现“有利于平衡”的假象求解器就钻了这个空子。加互斥约束之后还需要注意充电状态和放电状态的切换频率。实际系统中储能PCS储能变流器频繁切换充放电状态会严重影响设备寿命因此给我的模型额外加了一个最小持续状态时间约束一旦进入充电状态至少维持2个调度时段2小时避免出现在一个时段内充放来回切换的抖振解。这一条约束会稍微增加成本但换来的可执行性非常有价值。6. 从复现到应用几个值得深入扩展的方向完整复现并不是终点。做完这套模型并验证通过之后我建议再往以下几个方向扩展这些方向也是当前学术界和工程界都在关注的热点。首先是储能电池衰减建模。目前模型把储能当作理想器件充放电效率恒定。实际上锂电池的循环寿命与放电深度、充放电次数强相关储能每多放一次电容量就衰减一点这种衰减最终会影响储能参与调度的经济性。可以把电池容量衰减率例如每循环0.02%折算成储能放电的附加成本叠加到目标函数中。这样一来储能在鲁棒调度中的行为会更加“爱惜”自己不会每天深度充放会有更贴近工程实际的经济性结论。其次是需求侧响应资源的引入。微电网里的可中断负荷、可转移负荷同样可以作为应对不确定性的调节手段。把负荷纳入可调整变量范围之后相当于扩大了两阶段鲁棒模型中第二阶段可调资源的集合从理论上会降低对储能和柴油机的依赖进而降低总运行成本。建模方法上只需在负荷平衡约束中增加负荷削减/转移变量及相应惩罚项。最后是考虑网络拓扑约束的配电网扩展。本文的区域微电网是单节点单母线模型忽略了线路潮流约束。如果要扩展到真正的有源配电网需要把DistFlow潮流方程线性化后加入约束同时把每个节点的光伏、储能、负荷分开建模。这时不确定变量的维度大大增加CCG算法可能要从单场景扩展为多场景并行求解属于更复杂的研究课题。回到我整个复现过程的体会多阶段鲁棒调度模型最大的价值不在于数学公式多漂亮而在于它提供了一套“在信息不完全时如何做决策”的系统方法论。对初学者来说先把两阶段单节点模型彻底吃透、把CCG代码跑通再逐步加复杂度是最高效的路径。最后再分享一个小技巧所有参数都放进一个Excel文件统一管理每次跑算例只改Excel不动代码你会发现自己调试模型的速度比改代码快了不止一倍。
返回列表