ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

微网动态定价与优化调度:基于CVaR和合作型Stackelberg博弈的建模实战

微网动态定价与优化调度:基于CVaR和合作型Stackelberg博弈的建模实战 1. 先把这个题目拆开微网动态定价与优化调度为什么非要绑在一起做园区微网、台区微网或者社区型微网的朋友应该都有感触光伏装机越来越大储能也上了但真正运营起来最头疼的事情不是设备故障而是“电价怎么定”。定高了用户直接不跟你玩负荷曲线更难伺候定低了运营商自己回收不了成本储能和光伏的投资回报遥遥无期。这就是微网动态定价和优化调度必须放一起建模的根本原因——价格本身就是一种调度手段而调度结果反过来决定价格能不能落地。两者是同一个问题的两个面拆开做一定会失衡。我最早尝试这个方向的时候用的是传统的主从博弈。运营商定电价用户响应负荷储能按固定策略充放。跑出来的结果怎么说呢调度的确能收敛但用户侧的配合度很差因为价格信号带有一点“挤压感”。后来接触到合作型Stackelberg博弈这个概念才觉得这才是微网该有的博弈姿态运营商和用户虽然有主从之分但目标里带合作项不是纯粹的对抗而是一起把“社会福利”“新能源消纳”“成本风险”这几块蛋糕做大。这个视角转换之后整个模型都顺了。再加一层条件风险价值CVaR事情就更完整了。光伏出力不确定用户负荷也不确定电价也不敢拍脑袋定死。传统的期望值优化只会告诉你“平均能赚多少”但现实运营中我们更关心的是“最坏情况下亏多少”。CVaR干的就是这件事在优化目标里显式地惩罚尾部风险让定价和调度方案不必依赖运气。所以这篇博文我就把CVaR、合作型Stackelberg博弈、微网动态定价和优化调度串起来完整讲一遍建模思路、关键公式和实操中容易踩的坑。无论你是刚开始读这个方向的研究生还是已经在微网运营岗位上想引入更合理定价机制的工程师这篇文章应该都能帮你少走不少弯路。2. 模型整体架构设计先分清谁在上层、谁在下层2.1 分层思路微网运营商是领导者用户是跟随者Stackelberg博弈建模的第一步是确定主从关系。在微网场景里最自然的设定是微网聚合商或运营商作为上层领导者负责制定向用户售电的分时价格以及内部调度计划用户作为下层跟随者收到电价信号后调整自己的用电行为。这里的“调整”不是口头上的而是通过一个优化问题来表达——每个用户都有自己的用电偏好、可平移负荷约束、舒适度下限等等。用户优化问题的最优解就是上层定价问题里的反馈变量。实际建模时需要想清楚一个问题用户是“单用户”还是“多用户聚合”。如果只管一个楼宇那直接建一个下层问题就行。但如果是园区微网有工业负荷、商业负荷、居民负荷三类建议把每类负荷分别建模下层、按聚合形式反馈否则算出来的结果缺乏可落地性。我自己常用的是三层结构“运营商—多元负荷聚合商—具体设备”但为了不让模型膨胀第一版可以先做单类负荷聚合。2.2 合作型主从博弈目标函数里的“合作项”怎么加传统主从博弈的目标函数各算各的账——运营商只管自己收益最大化用户只管自己电费最小化。但是微网是一个共同体电价定了之后如果用户因为电费太高削减了太多负荷光伏消纳率就会掉储能的套利空间也会变窄运营商的收益同样受影响。所以合作型Stackelberg博弈在设计目标函数时会在上层目标里加入一个反映用户效用的项或者在约束里加入一个对用户成本的限制。也就是说运营商在定电价时不只考虑收益还要照顾用户侧的电费支出满意度最终达到一种“帕累托改进”的状态。我习惯的建模方式是上层目标 运营商净收益 − 风险惩罚项CVaR同时在下层用户模型中把用户的用电效用考虑进去再用KKT条件将下层问题作为约束并入上层。这个处理方式在学术里叫“MPEC/单层重构”实操中用局部最优和KKT的凸化条件已经足够应付大多数迭代求解。2.3 核心变量表拿起模型之前先列清楚不变量下面这张表是我每次建模都会先列出来的省去后面反复改变量的麻烦。变量类型典型符号含义说明决策变量上层p_t^sell、p_t^buy运营商向用户售电、从电网购电的分时合同价状态变量下层L_t^shift、E_t^SOC可平移负荷的调度量、储能系统SOC随机参数PV_t^(ω)场景ω下的光伏出力预测值目标项C_op、U_user、CVaR运营商收益、用户效用、条件风险价值惩罚约束项SOC_min、SOC_max、Ramp_up储能容量上下限、设备爬坡约束这套变量在具体编程时会展开成矩阵形式但列这种表更主要的价值是统一团队沟通口径。我踩过一个很实在的坑刚写代码时没有统一上下层变量符号结果模型求解器报了很多“Unbounded variable”的错误半天都没查出来最后发现是符号混用了。3. 条件风险价值CVaR为什么要出现在定价与调度模型里3.1 期望值优化会让你忽视最坏情况如果只有光伏和负荷的预测曲线优化模型完全可以不引入CVaR直接用期望值。问题是预测曲线是带误差的现实运营中最怕的恰恰不是误差的平均值而是极端天气下光伏出力断崖下跌、负荷又同时冲高的情况。这种场景出现的概率可能只有5%但一旦出现运营商可能单日亏损就把一周的收益吞掉。条件风险价值正好管这个。简单说CVaR衡量的不是“平均收益”而是“在概率分布最差的α分位之外损失的平均水平”。如果你设置置信水平β0.95那CVaR就是最差5%情景下的平均损失。现在还在用期望值做定价策略的朋友我强烈建议至少跑一版CVaR做对比。很多情况下你会发现期望值最优方案和风险最优方案定价差别很大尤其在峰时段电价上风险厌恶的解会把峰电价抬得更高用价格把高风险时段负荷压下去。3.2 CVaR的数学定义与建模形式CVaR的标准定义为CVaR_β min_{η} { η (1/(1−β)) × Σ_{ω} π_ω × max(0, −f_ω − η) }这里的η本质上是VaR值f_ω是场景ω下的收益π_ω是场景概率。这个公式之所以好用是因为它可以线性化处理只要引入辅助变量z_ω≥0令z_ω ≥ −f_ω − η目标函数中加一项η (1/(1−β))Σπ_ω z_ω即可整个模型还是线性规划结构不会引入非线性求解麻烦。置信水平的选择值得仔细考虑。β取得太低比如0.8模型对风险惩罚不够调度方案几乎退化成期望值优化β取到0.99惩罚又过于严苛成本可能上升20%以上适合那种风险容忍度极低、断电损失极高的工商业微网。我实际项目里一般取0.9到0.95之间既能保证方案稳健又不会把电价抬到用户完全受不了的程度。3.3 场景生成与“困境场景”构造场景集合是CVaR建模的原料。常见做法是用历史光伏出力数据做K-means聚类缩减到20到50个典型场景再配合正态扰动生成预测误差场景。还有一个我自己经常偷懒但很好用的技巧在场景集合里人为加入“困境场景”——比如光伏出力缩减30%、负荷上升20%的组合场景。这相当于直接告诉优化器“这种日子过不过得下去”比单纯加随机扰动更能提升模型的鲁棒性。场景数量也不要一味追求大。YalmipGurobi环境下场景超过100个以后求解时间会成倍增长而CVaR结果改进非常有限。我自己项目里用50个场景和120个场景做过对比两周的典型场景下定价差异不到2%但求解时间从4分钟飙升到25分钟。除了研究需要工程场景里建议控制在50个以内。4. 动态定价模型分时电价骨架与迭代更新策略4.1 分时电价时段划分怎么定动态定价不是说每一小时一个随机价格工程上最稳妥的实现方式是分时电价骨架——把一天分成峰、平、谷三个时段峰时段电价高、谷时段电价低平段居中。时段划分一般参考当地电网报装容量和电网公司的峰谷时段规定。我做过的一个园区项目里峰时段取8:00-11:00和18:00-22:00平时段取11:00-18:00谷时段取22:00-次日8:00储能策略集中在谷充峰放。光有分时骨架还不够鉴别一个“动态定价”模型是否成功要看它能不能在迭代求解时调整各时段的价差。合作型Stackelberg博弈的求解过程本质是初始电价 → 求用户最优负荷 → 把负荷反馈回上层重新定电价 → 再求用户响应 → 反复迭代到电价和负荷都稳定。这里的关键变量是各时段的电价上下限上限不能超过用户从电网直接购电的价格否则用户完全没有留在微网的理由下限不能低于微网向电网售电的上网电价否则运营商亏本倒贴。4.2 定价公式里的关键项与约束上层定价目标函数可以写成max Σ_t [ (p_t^sell − c_t^grid) × L_t − C_op_fixed ] − ρ × CVaR其中c_t^grid是运营商从电网的购电成本。加上用户效用合作项后会在目标里再减一项λ×Σ_t (p_t^sell − p_ref)^2这其实是对电价的“平滑惩罚”——防止迭代中电价在两个极端之间震荡也保证用户的电费不会剧烈波动。λ的值我一般取0.001到0.01之间太大价差被抹平调度灵活性下降太小又起不到平滑作用。电价约束大致是p_min ≤ p_t^sell ≤ p_maxΣ_t (p_t^sell × L_t) ≥ 运营商最低收益目标第一组约束是价格安全边界第二组是让运营商的方案不会亏钱。配合CVaR的线性化约束整体是一个线性目标加线性约束的混合整数线性规划Gurobi十分钟以内就能解出来。4.3 售电价格联动机制售电价格不能刻板地独立于电网市场价。现在很多地区的微网都支持向电网售电富余光伏上网所以微网售电电价和购电电价之间要加一个联动机制如果电网购电成本突然上升微网内部售电价格也要能抬升否则运营商两头受压。我在模型里常用这样一组联动约束p_t^sell ≥ c_t^grid Δ_minp_t^sell ≤ c_t^grid Δ_max这样既保留了运营商定价的自主权又让价格信号跟随外部市场环境。项目实测里这个联动约束直接关系到微网会不会在某个时段出现“卖一度亏一度”的情况。第一版模型漏掉这组约束时仿真结果里一度出现运营商在峰时段亏本售电的荒唐现象检查了半天才发现漏了这层关系。5. 优化调度层储能、可平移负荷与光伏消纳5.1 可平移负荷怎么建模型用户侧的可平移负荷比如洗衣机、工厂的批次生产任务、电动车充电时段是最灵活但也最不好建模的部分。它的核心约束是总用电量不变只是用电时间窗口挪移。数学上可以表达为Σ_t ΔL_t 0L_t^baseline ΔL_t ≥ L_minL_t^baseline ΔL_t ≤ L_max第一行是能量守恒——平移不是消灭负荷只是换个时间用。第二三行是每个时段负荷的上下限防止模型疯子一样把负荷全塞到谷时段。真实的用户侧约束还包括设备运行时长、启动次数、最长等待时间等但最核心的还是这三条。建议第一版建模只做这三条跑通了再加细节。5.2 储能系统的SOC约束与充放电策略储能是微网调度的“压舱石”。SOC模型用标准的能量平衡方程E_{t1}^SOC E_t^SOC η_ch × Δt × P_t^ch − P_t^dis × Δt / η_dis同时要满足SOC_min ≤ E_t^SOC ≤ SOC_max0 ≤ P_t^ch ≤ P_ch_max0 ≤ P_t^dis ≤ P_dis_max这几个约束本身不难但有一个容易出错的细节是充电效率和放电效率的处理方向。有的模型把效率放在充电侧分母有的放在放电侧分母两种写法对最优解的偏移方向完全不同。我自己习惯统一写成上面这种形式充电时能量转换有损失所以有效存入要乘以η_ch约0.95放电时电池要输出更多原始能量才能供应负荷所以耗散SOC时除以η_dis约0.95。这样写的好处是SOC始终严格守恒不会出现能量凭空增加的bug。5.3 光伏预测误差在调度里的体现光伏不确定性除了进CVaR目标函数在调度约束里也要留一手。比如可以加一个旋转备用约束每个时段的可调度能力要大于光伏预测出力上偏差的一定比例。通俗地说就算光伏突然比预测值少发了20%储能加电网购电也能补上缺额。这个备用比例我一般取15%到20%取太高储能容量就被备用占满了失去套利空间取太低又兜不住实际波动。还有一个常规优化里注意不到的点逆变器无功容量。光伏逆变器除了输出有功还承担无功调节功能如果你把逆变器有功走高限设满就没有多余容量做无功支撑了。在调度模型里建议给逆变器加P²Q²≤S²约束把有功和无功的耦合写进去不然调度结果在真实物理系统里会跑不通。6. 双层模型求解KKT条件与强对偶的完整套路6.1 下层优化问题的KKT转换求解合作型Stackelberg博弈的核心是把双层优化转换成单层优化然后扔给求解器。最常用的办法就是对下层用户优化问题写KKT条件。假设下层问题是min U_user(L_t, p_t) s.t. g(L_t) ≤ 0, h(L_t) 0KKT条件包括四条拉格朗日函数对决策变量求导为零Stationarity、原约束可行性Primal feasibility、对偶约束可行性Dual feasibility、互补松弛条件Complementary slackness。把这四组约束写出来就等于把下层问题“固化”成了上层问题的约束。互补松弛条件是非线性的λ·g 0但可以通过大M法线性化0 ≤ λ ≤ M × z0 ≤ −g ≤ M × (1 − z)其中z是0-1变量M取足够大的常数。实际求解中M的取值要谨慎太小会错误排除可行解太大会导致数值病态。我的经验是M取约束量级上限的10到50倍。比如SOC上下限是0到1M取20就够如果是电价差额浮动上百元M取2000。6.2 强对偶条件怎么用双层模型中还有一个双线性项问题上层目标函数里有p_t^sell × L_t这样的乘积而下层KKT条件中的Stationarity也会引入拉格朗日乘子和对偶变量的乘积。处理办法是使用强对偶定理——当下层问题是凸优化且满足Slater条件时下层原问题最优目标值等于其对偶问题最优目标值可以借助这一等式把乘积项替换成对偶变量的表达式从而消除双线性项。这个操作在数学推导里很漂亮但在代码实现时要格外小心必须先验证下层问题是凸的。好在电价固定时用户侧的负荷优化通常都是线性规划或二次规划天然凸。碰到下层是混合整数规划的时候强对偶不能用只能改用启发式迭代嵌套求解。我见过不少同学在MILP下层上硬套强对偶结果求出来一个完全不合逻辑的“最优解”排查的时候才发现根子在这。6.3 求解配置与代码示例我用的是MATLABYalmipGurobi这套组合本质上它是建模语言方便处理符号化的优化问题。放一个缩略的求解框架代码方便你理解整个逻辑% 上层变量 p_sell sdpvar(24, 1); % 24时段售电价格 p_buy sdpvar(24, 1); % 24时段购电价格 % 下层变量KKT转换后并入 L_shift sdpvar(24, 1); % 可平移负荷 soc sdpvar(25, 1); % 储能SOC首尾各多一个状态点 eta sdpvar(1, 1); % VaR值 z_w sdpvar(50, 1); % CVaR辅助变量 % 目标函数运营商收益 - 风险惩罚 obj sum((p_sell - c_grid) .* (L_base L_shift)) ... - rho * (eta 1/(1-beta) * pi * z_w); % 约束集合 Constraints [... p_min p_sell p_max, ... % KKT互补松弛线性化约束组略... % SOC递推约束 ... % CVaR线性化约束z_w -(profit_w) - eta ... ]; % 求解 optimize(Constraints, -obj, sdpsettings(solver, gurobi));这套代码跑通之后你会得到一组电价序列和负荷序列。建议先用一个典型日数据做单日测试再扩展到一周或一个月尺度。单日模型Gurobi秒级就出结果多日尺度因为0-1变量数量增长可能需要几分钟。7. 常见问题与实测排查记录7.1 场景数量太少导致CVaR结果失真最初版本我图省事只用了10个光伏场景跑出来的定价方案“很乐观”——峰谷价差明显、调度也漂亮。但拿去跟真实历史数据回测亏损频率非常高。原因很简单10个场景覆盖不了极端天气组合CVaR的“最差5%”其实只是这10个场景中最差那一个根本不是真正的尾部风险。后来扩到50个场景之后模型自动把峰电价抬高了约0.08元/kWh谷电价下降了0.05元/kWh回测亏损频次降低了一半以上。7.2 初始电价的选择影响迭代收敛合作型Stackelberg博弈如果用迭代法而不是单层转化法求解初始电价的选择非常关键。我一开始把初始电价设为微网向电网售电的上网电价结果第一轮用户几乎不响应调峰迭代震荡了9轮才收敛。后来改成初始电价电网购电电价×0.85作为平时段、乘1.2作为峰时段、乘0.55作为谷时段三到五轮就稳定了。经验是初始电价应该落在最终解的大致区间附近不能直接拿基础电价当起点。7.3 储能SOC初值对调度结果的影响还有一次项目里储能SOC初值我随意设成了0.9。因为电池初始电量高模型在第一个时段就大量放电。配合峰时段电价收益确实提高了但整个调度计划在后半天SOC掉到下限附近根本没有容量应对晚高峰。这个教训让我把SOC初值、末值全部纳入模型约束SOC_0 0.5SOC_T ≥ 0.5这样调度计划只做“日清”模式储能不会寅吃卯粮。7.4 求解器报“Infeasible”时的排查流程这类问题谁都会遇到关键是要有可执行的排查思路。我的习惯顺序是第一步先单独跑下层用户问题如果下层就无解说明用户约束写错看负荷上下界的数值是否矛盾第二步去掉CVaR辅助约束跑上层不加KKT的版本测试定价主循环如果上层无解检查电价上下限是否交叉第三步把KKT和强对偶条件加回来如果还是无解重点检查大M取值和互补松弛条件方向——方向反了是最隐蔽的错误看起来都合理但就是无解。最后才是检查场景场景概率pi是否归一化概率和不等于1导致CVaR约束错乱这种问题最气人但加一句assert(abs(sum(pi) - 1) 1e-6)就能提前堵住。8. 最后的实操补充与个人体会如果前面这些你都能跑通这个项目已经算完整体验了一遍微网动态定价与优化调度的全流程。但我最后还想分享一点额外的经验这个模型在真实微网系统里落地时最关键的转化是“仿真结果如何变成可执行的运行计划”。再漂亮的博弈最优电价如果没法跟微网的实时能量管理系统对接就只是一堆数学结果。我在实际部署中做了一件事把离线优化出的分时电价计划输出成一张“电价策略表”每天由EMS读取当日的实时决策再由EMS在上层电价约束下做滚动优化调整。这相当于让Stackelberg博弈的“上层领导者”在日级尺度运行而“下层跟随者”在15分钟级尺度实时响应两层时间维度不同但通过参数传递串了起来。这种模式目前在我参与的园区项目中运行效果非常稳定比全实时迭代计算稳健得多。另外同型项目在探索可扩展性时可以考虑把碳排放约束、绿电交易凭证、V2G电动车参与需求响应这些维度加进去。在已经有条件风险价值框架打底的情况下加这些扩展不会伤筋动骨大概率只是多几组约束和多几个随机变量的事。希望这篇拆解能帮正在做微网博弈定价和调度方向的朋友少走点弯路也欢迎有实际项目经验的人交流各自的避坑心得。
返回列表