☰
多微网电能交易非合作博弈动态定价仿真与MATLAB实现
2026/10/1 4:07:01 网站建设 项目流程

前阵子做多微网电能交易仿真,最大的体会就是:多微网交易策略这件事,看起来是电力系统问题,本质上是利益分配问题。几个微电网聚在一起,各自有光伏、储能、负荷,白天有人多余电,晚上有人缺电,怎么定价才能让大家都愿意参与内部交易,而不是一股脑都去找主网?我用非合作博弈模型在MATLAB里做了一套动态定价仿真,把交易策略完整跑通了。今天把建模思路、价格迭代机制、代码实现和调试经验一次性整理出来,给想在这个方向起步的朋友做个参考。整篇内容不吹概念,直接讲能跑的框架和真实踩过的坑。

1. 多微网交易到底难在哪:先看问题模型

1.1 一个具体场景:三个微网,各怀心思

先构造一个我经常用的算例场景。园区里有三个微电网,姑且叫 A、B、C:

  • A 网光伏装机量大,白天发出来的电远大于自身负荷,盈余很多,但傍晚之后就基本靠储能撑着;
  • B 网是办公楼区域,白天负荷高,屋顶光伏只能覆盖一部分,属于典型的“白天缺电户”;
  • C 网有一个容量比较大的储能和部分可调负荷,白天可以存电,晚上可以放电,还有点灵活性。

三个微网都接入同一个配电台区,物理上可以互相交易,也可以各自找主网购售电。问题是:A 网多余的电要不要卖给 B 网?以什么价格卖?C 网储能什么时候充满、什么时候释放?如果三个微网都只想着自己利益最大化,最后能不能达成的那个状态,是不是对整体也足够好?

这类问题在过去并不算突出,因为大量微网都是“自发自用、余电上网”,按固定的上网电价和购电电价跟主网结算。但现在微网越来越多,再去套单一电价的模式,就会出现两个尴尬局面:白天光伏大发的时候,多个微网同时涌向主网卖电,主网消纳压力很大;晚上负荷高峰,几个缺电微网又同时向主网购电,配变很容易顶不住。明明局部就有供需互补空间,却因为缺少合理的价格信号,谁也调动不起来。

1.2 为什么集中优化方案不好用

很多人第一反应是:既然要让系统总体最好,那干脆由调度中心统一优化算了。把所有微网的光伏出力、负荷预测、储能SOC、设备约束全部收上来,求解一个全局最优,然后下发每个微网的充放电指令。这在数学上确实可行,也确实能得到系统层面的最优解,但实际落不了地。

原因有三个。第一,微网属于不同利益主体,没有义务把自己的真实运行数据完整上报给别人,尤其是涉及成本和边界约束的信息。第二,集中优化把微网变成了“执行单元”,剥夺了它们自主决策的权利,一旦优化结果让某个微网明显吃亏,它根本没有动力配合。第三,集中模型规模一大,全网联合优化很容易出现“一个主体数据更新,全盘重算”的情况,计算效率和维护成本都很高。

所以我在这个项目里最终没有走集中优化路线,而是选了非合作博弈。本质上就是让每个微网自己当决策者,在统一的市场规则和价格信号下各自优化,通过价格来回迭代,找到一个谁都不想单方面改策略的“纳什均衡”状态。这种方法不需要任何微网公开自己的成本函数,只需要它们基于价格给出电量和交易响应,对隐私保护和分布式落地的友好程度高很多。

用一个不太严谨但很形象的类比:集中优化像是学校食堂统一配餐,虽然营养搭配可以做到全校最优,但众口难调,大家不满意也没得选;非合作博弈更像是自由菜市场,每个摊位自主定价,买菜的人根据价格选菜,最后价格自动调整到大家都能接受的位置。

1.3 非合作博弈建模的核心要素

建立博弈模型,先要把三个基本要素定义清楚:

  • 参与者:所有参与电能交易的微电网,设为 N 个,编号 i = 1, 2, ..., N;
  • 策略空间:每个微网可以控制的变量,包括每个时段向市场申报的购电量、售电量,储能充电/放电功率等;
  • 收益函数:每个微网在某种策略组合下获得的效用,一般是运行收益减去购电成本,再减去储能损耗、弃光惩罚等。

在这个框架里,每个微网的决策不是孤立的。A 网想多卖电,但能不能卖出去,取决于当前市场价格和 B、C 网愿意买多少;B 网想少买点高价电,但能不能做到,取决于自己的负荷刚性和 C 网储能是否愿意在晚间放电。价格就是连接所有决策的纽带。

纳什均衡的定义也很直白:给定其他微网的策略不变,任何一个微网单独改变自己的策略,都不可能获得更高的收益,此时所有微网的策略组合就是一个均衡。我在仿真里要找的,就是这个策略组合。

2. 动态定价机制:让价格自动反映供需

2.1 价格更新方程的设计逻辑

博弈模型确定了“谁在决策”,还需要一个“价格从哪来”的机制。我采用的是迭代式动态定价,不依赖集中出清,而是通过观察每个微网的响应,持续修正市场价格。

假设内部交易市场采用统一电价 p,单位是元/kWh。给定价格 p(k),每个微网会优化出一个购售电量结果。把第 k 轮所有微网的净购电需求累加:

I(k) = sum(P_buy_i(k)) - sum(P_sell_i(k))

如果 I(k) 大于 0,说明当前价格下买方需求大于卖方供给,价格应该往上调;如果 I(k) 小于 0,说明供大于求,价格应该往下压。标准的价格更新公式写成:

p(k+1) = p(k) + tau * I(k)

其中 tau 是价格调整步长,数值越大收敛越快,但太大容易振荡。我实测下来,tau 取 0.01 到 0.05 之间比较稳,具体要看系统容量基数和价格量纲。价格上下界可以设在主网购电电价和上网电价之间,避免交易价格被调到不合理区间。

这个机制很像“看不见的手”的离散版本。最妙的地方在于,它不需要知道每个微网内部的成本函数,只需要观察微网对当前价格的响应量。每个微网都是黑箱,市场只跟它们要一个“在这个价格下你买多少、卖多少”的答复。

2.2 微网内部优化:目标函数与约束

价格更新只负责协调,真正决定交易行为的是微网内部优化模型。对微网 i,给定外部价格 p 后,它需要求解一个单主体优化问题,目标函数我一般写成:

max sum_t [ p_t * P_sell_i(t) - p_t * P_buy_i(t) - c_loss * P_ch_i(t) - c_curtail * P_abandon_i(t) ]

其中:

  • P_sell_i(t) 是微网 i 在 t 时段卖到市场的功率;
  • P_buy_i(t) 是 t 时段从市场买进的功率;
  • P_ch_i(t) 是储能充电功率,充电过程有损耗,成本系数 c_loss 用来刻画电池循环损耗;
  • P_abandon_i(t) 是弃光功率,给它一个惩罚系数 c_curtail,让模型不会为了省钱随便弃掉清洁能源。

除了目标函数,约束条件才是微网优化真正的骨架:

  1. 功率平衡约束:光伏出力加储能放电加购电,必须等于负荷加储能充电加售电;
  2. 储能SOC动态约束:下一时段SOC等于当前SOC加上充电效率系数和放电效率系数折算后的净电量;
  3. SOC上下限约束:一般限制在 0.1 到 0.9 之间,防止电池过充过放;
  4. 充放电功率上限约束:储能功率不能超过额定值;
  5. 购售互斥约束:同一时段要么买要么卖,不能同时又买又卖,这个在优化里很重要,不然模型会利用买卖价差做无意义的套利。

这个子问题的目标函数如果是线性或二次的,加上线性约束之后是凸优化,MATLAB 里的 fmincon 可以直接求解。如果不考虑储能非线性损耗,甚至可以退化成线性规划,用 linprog 更快。

2.3 纳什均衡与收敛判断

价格迭代机制最终要回答一个问题:迭代到什么时候算完?我这里用两个收敛判据,满足任意一个都认为达到均衡:

  • 价格变化量小于阈值,也就是 abs(p(k+1) - p(k)) < eps_p;
  • 系统总净购电需求逼近 0,也就是 abs(I(k)) < eps_I。

两个判据说的其实是一回事:当总供需基本平衡且价格不再明显变化时,所有微网给出的策略已经互相匹配,谁也没法靠单方面改策略获得更多收益。这个状态就是纳什均衡。

有朋友问过我,是不是一定能收敛?理论上如果每个微网子问题都是凸优化,且价格更新映射满足单调性,迭代会收敛到均衡;但实际工程里目标函数如果加入了非线性的储能老化项、弃光惩罚项,可能破坏全局收敛性。所以我在仿真里从来不只是盯着“收敛”两个字,还会检查收敛点对应的总交易成本,确认它不是被某个局部极值带偏。

3. MATLAB代码实现:从博弈模型到可跑仿真

3.1 数据准备:光伏出力、负荷与储能参数

我习惯先造一组 24 个时段的基础数据,做方案验证时用“小时级分辨率”最省事。每个微网的数据结构用一个 struct 存起来,包含光伏预测曲线、负荷曲线、储能额定容量和功率、初始SOC等。下面这段代码是数据初始化部分:

clear; clc; N = 3; % 三个微网 T = 24; % 24小时 dt = 1; % 时间步长,单位h % 典型光伏出力标幺曲线(简单模拟,实际项目请替换为预测数据) pv_shape = [0 0 0 0 0 0.1 0.3 0.6 0.85 0.95 1.0 0.95 0.9 0.75 0.55 0.3 0.1 0 0 0 0 0 0 0]; pv_cap = [1.2, 0.6, 0.8]; % 各微网光伏装机,单位MW load_profile = [0.4 0.35 0.3 0.28 0.3 0.45 0.7 0.9 1.0 0.95 0.9 0.85 ... 0.8 0.85 0.9 1.0 1.1 1.2 1.05 0.9 0.8 0.7 0.6 0.5]; mg(1).pv = pv_shape * pv_cap(1); mg(2).pv = pv_shape * pv_cap(2) * 0.9; % B网光伏弱一些 mg(3).pv = pv_shape * pv_cap(3) * 0.7; mg(1).load = load_profile * 0.6; mg(2).load = load_profile * 1.1; % B网负荷大 mg(3).load = load_profile * 0.7; mg(1).E_max = 0.4; mg(1).P_max = 0.2; % 储能容量/功率上限,单位MWh/MW mg(2).E_max = 0.2; mg(2).P_max = 0.1; mg(3).E_max = 0.8; mg(3).P_max = 0.4; for i = 1:N mg(i).soc0 = 0.3; mg(i).eff_c = 0.95; % 充电效率 mg(i).eff_d = 0.9; % 放电效率 end

实际项目里 pv_shape 和 load_profile 应该来自预测系统,可以用光照辐照度数据折算光伏出力,用历史负荷曲线做相似日预测。这里先用平滑曲线验证算法逻辑。

3.2 单微网优化子问题求解

每个微网在给定电价 p 下,需要求解自己的最优买卖电量和储能充放电计划。我这里写一个函数,核心思路是定义决策变量、目标函数、约束,然后调用 fmincon:

function [buy, sell, soc] = solve_microgrid(p, data) % p: 当前交易电价,1xT向量 % data: 微网数据,包含 pv, load, E_max, P_max, soc0, eff_c, eff_d T = length(p); % 决策变量:buy(1:T) sell(1:T) ch(1:T) dis(1:T) x0 = zeros(4*T, 1); % 目标函数:最大化收益,同时惩罚弃光 pv = data.pv; load = data.load; E_max = data.E_max; P_max = data.P_max; soc0 = data.soc0; eta_c = data.eff_c; eta_d = data.eff_d; c_curtail = 0.05; % 弃光惩罚系数 fun = @(x) objective(x, p, pv, load, c_curtail, T); % 约束 Aeq = []; beq = []; lb = zeros(4*T, 1); ub = [inf(T,1); inf(T,1); P_max*ones(T,1); P_max*ones(T,1)]; % 非线性约束:功率平衡与SOC递推 nonlcon = @(x) constraints(x, pv, load, E_max, P_max, soc0, eta_c, eta_d, T); options = optimoptions('fmincon', 'Display', 'off', ... 'Algorithm', 'interior-point', 'MaxIterations', 500); [x_opt, ~] = fmincon(fun, x0, [], [], Aeq, beq, lb, ub, nonlcon, options); buy = x_opt(1:T); sell = x_opt(T+1:2*T); ch = x_opt(2*T+1:3*T); dis = x_opt(3*T+1:4*T); % 计算SOC曲线 soc = zeros(T+1, 1); soc(1) = soc0; for t = 1:T soc(t+1) = soc(t) + (ch(t)*eta_c - dis(t)/eta_d) * 1; end end

目标函数的实现另外写。这里有几个经验值得提:

  • 储能充电功率和放电功率要同时放进变量里,然后通过 SOC 约束和功率上限间接限制,不要直接用 buy 和 sell 代表储能的充放,否则建模容易混;
  • 为了让 fmincon 更快收敛,x0 不要给全零向量,可以先用 linprog 解一个忽略非线性约束的版本,把结果作为初值;
  • 如果目标函数里包含弃光惩罚,最好把弃光量显式表达成 max(0, pv + dis - load - ch - sell) 之类形式,但这个 max 操作是非光滑的,我一般用一个小技巧:把弃光也设成决策变量,并加约束 pv + dis + buy = load + ch + sell + curtail,curtail >= 0,这样全程保持线性约束。

3.3 主循环:价格迭代与均衡搜索

单微网子问题解决了,剩下的就是把 N 个微网串起来,跑价格迭代主循环:

% 参数设置 p_max = 0.8; % 交易市场上限价格 p_min = 0.2; % 交易市场下限价格 p0 = 0.4; % 初始价格 tau = 0.02; % 价格调整步长 Kmax = 200; % 最大迭代次数 tol_price = 1e-3; tol_balance = 1e-3; p = p0 * ones(1, T); for k = 1:Kmax total_buy = zeros(1, T); total_sell = zeros(1, T); for i = 1:N [buy_i, sell_i, soc_i] = solve_microgrid(p, mg(i)); mg(i).buy = buy_i; mg(i).sell = sell_i; mg(i).soc = soc_i; total_buy = total_buy + buy_i; total_sell = total_sell + sell_i; end imbalance = total_buy - total_sell; p_new = p + tau * imbalance; p_new = min(max(p_new, p_min), p_max); if max(abs(p_new - p)) < tol_price && max(abs(imbalance)) < tol_balance fprintf('收敛于第%3d轮,最终均价 %.3f 元/kWh\n', k, mean(p)); break; end p = p_new; end

这个主循环看着简单,其实已经把博弈求解的核心逻辑覆盖了:外层迭代价格,内层解每个微网的优化子问题,然后根据市场总供需修正价格,循环到均衡。如果迭代次数到了 Kmax 还没收敛,多半是 tau 太大或者初始价格选得离均衡太远。

3.4 绘图与结果导出

分析结果时我一般画三张图,配套的代码非常短:

figure; subplot(3,1,1); plot(1:T, p, 'o-'); grid on; xlabel('时段 (h)'); ylabel('价格 (元/kWh)'); title('动态定价演化结果'); subplot(3,1,2); bar(1:T, [mg(1).sell - mg(1).buy; mg(2).sell - mg(2).buy; ... mg(3).sell - mg(3).buy]', 'stacked'); xlabel('时段 (h)'); ylabel('交易功率 (MW)'); legend({'微网A','微网B','微网C'}, 'Location', 'best'); title('各微网净交易功率'); subplot(3,1,3); hold on; for i = 1:N plot(0:T, mg(i).soc, '-'); end hold off; grid on; xlabel('时段 (h)'); ylabel('SOC'); title('储能SOC轨迹');

第一张图看价格有没有收敛到合理区间,第二张图看各个微网的交易方向是否符合预期,第三张图检查储能没有触碰到上下界。这三张图基本能判断一轮仿真是否靠谱。

4. 仿真结果与参数敏感性分析

4.1 交易量、价格演化曲线

跑完一天的仿真,我通常会得到几类比较典型的画像。

价格曲线在午间会出现明显低谷,因为 A 网光伏大发,市场上卖电供给充足,价格被压到接近上网电价的位置;晚高峰时段 B 网负荷上升,C 网储能也开始放电报价,市场购电需求集中,价格抬升。整个价格曲线呈现出“午间低、傍晚高”的波动形态,比固定电价更能反映供需关系。

交易量方面,A 网在午间大量卖出光伏盈余,B 网在白天买入,C 网则呈现出“中午充、傍晚放”的套利型行为。最终系统对主网的净购电量明显下降,内部交易量上升。这说明动态定价确实刺激了微网之间的余缺互济。

值得强调的是,达到均衡时,没有任何一个微网可以通过单方面改变买卖策略获得更高收益。换句话讲,价格信号已经把所有微网的出力、储能、交易行为拉到了一个互相匹配的状态。

4.2 三种定价策略对比

为了验证动态定价的工程价值,我把固定电价、分时电价、博弈动态定价放在同一组数据下做了对比。结果用一张表总结:

对比维度固定电价分时电价非合作博弈动态定价
内部交易量低,微网之间几乎没有互动中等,峰谷价差能引导部分交易高,价格随供需自动调整
光伏消纳率有弃光风险较好最好,卖方微网主动下调报价促进消纳
系统总运行成本偏高中等可进一步降低
微网收益公平性单一价格对所有主体一刀切价差固定,灵活微网占便宜按供需贡献分配收益,各方自主性高
模型复杂度最低低中等,需要迭代求解

表格里的结论并不是说博弈动态定价一定在所有指标上碾压其他策略,而是说在“多主体自主决策”的大前提下,它更有希望同时兼顾整体效率和个体理性。

4.3 储能容量与价格弹性的影响

参数敏感性分析我重点看了两个变量。

一个是储能容量。当某个微网储能容量增大时,市场的“蓄水池”作用更明显,价格曲线波动幅度会收窄,尤其是在光伏高峰时段,储能吸纳多余电能,阻止价格过度下跌;晚高峰时段,储能释放电能,抑制价格过快上涨。反过来,储能容量太小,价格很容易在几个小时内大幅波动,甚至触发价格上下限约束。

另一个是负荷的价格弹性。如果微网负荷对价格完全不敏感,任何价格更新都只能通过储能调节,市场对供需的响应能力有限;如果能允许一部分可调负荷根据价格平移,市场可以明显更快收敛,均衡价格的波动也更小。实际工程中,那些带柔性负荷的微网,往往在交易博弈里更有竞争优势。

5. 实操中的坑与排查清单

5.1 迭代振荡的处理

我最先跑通的版本,用 tau = 0.1 进行价格更新,结果价格在 0.3 和 0.7 之间来回震荡,始终收敛不到均衡。原因是价格步长太大,微网对价格过于敏感,这轮价格升高导致大家集体少买多卖,下一轮价格又被打下去。

解决办法有两种。第一种是把 tau 减小,比如从 0.1 降到 0.02,系统会稳定很多;第二种是给价格更新加一个低通滤波,也就是 p(k+1) = p(k) + alpha * (tau * I(k)),其中 alpha 在 0.3 到 0.7 之间。本质都是降低单次价格修正的幅度,让微网响应不要被反复放大。遇到振荡先别改模型,先调这两个系数,多数情况能解决。

5.2 fmincon常见崩溃原因

很多人在 MATLAB 里跑类似模型时,会报 undefined function or method optimoptions。我遇到过几次,基本都是两个原因:一是当前 MATLAB 版本没有安装 Optimization Toolbox,或者 License 没配置好;二是脚本里用了高版本新增的选项,老版本不认识。

检查方法很直接:在命令行输入 ver 查看工具箱列表,确认 Optimization Toolbox 存在;如果存在但仍报错,把 optimoptions 换成 optimset,或者统一用 'Display','off' 搭配 optimoptions 的旧语法。另一次教训是 fmincon 初始点给得离可行域太远,导致模型提示约束冲突。解决方案是先解除储能SOC约束,用线性规划跑一个松弛结果做初值。

5.3 初始电价敏感性与多均衡问题

非合作博弈模型不是随便给个初始价格都能收敛到同一个结果。如果初始价格定在接近购电价格上限,微网会倾向于大量卖电,导致市场供过于求,价格一路被打压,最终可能收敛到一个低交易量、低均衡价格的角点;如果初始价格定在接近上网电价下限,结果又可能走向另一个方向。

我的经验是把初始价格选在主网购电价和上网电价之间的中点,或者用历史交易价格的平均值做初值。另外,检验多均衡的方法是:分别从多个初始价格出发跑仿真,对比均衡价格和成本。如果收敛点差异太大,需要检查是不是效用函数非凸、储能约束过强导致可行域被拆开。此时可以适当增加储能充放电损耗成本系数,让目标函数更接近严格凸,均衡更稳定。

5.4 仿真效率优化技巧

当微网数量从 3 个增加到 20 个,时段从 24 增加到 96 个,单轮求解量会指数增长。我试过最笨的办法是串行循环,跑一次完整仿真要几分钟,调一次参数等很久。

后来做了三处优化。第一,把每个微网的子问题从 fmincon 换成更快的线性规划或二次规划,只要模型允许,能用 linprog 或 quadprog 就尽量不用通用非线性优化器。第二,把主循环里的微网求解改成 parfor 并行,因为每个微网在当前价格下的优化是互相独立的,天然适合并行。第三,如果只是做机制验证,先在 24 时段尺度上把算法跑通,再扩展到 15 分钟粒度,不要一上来就到 96 个时段。

我在实际跑这套模型时最深的感受是,博弈模型的均衡不只是数学上存在就算完事。价格更新机制的稳定性、求解器选型、初值设置,这些工程细节才是真正决定模型能不能落到项目里的关键。如果你也准备做多微网交易策略,建议先从 3 个微网、24 时段的场景起步,把价格迭代、储能约束、数据精度这些环节调顺,再逐步扩展到大网络。后面如果想继续往深走,还可以把微网之间的网络拓扑约束、需求响应机制、以及新能源出力的随机性并进来,那算是这个方向的下一层玩法了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询