☰
基于二阶锥规划的主动配电网动态最优潮流建模与求解实践
2026/9/29 17:34:42 网站建设 项目流程

1. 从一次夜间的调度困境说起:动态最优潮流到底难在哪

去年我帮一家地市供电公司做配电网评估项目,遇到一个很典型的场景。凌晨的光伏出力曲线早就归零,馈线上的负载却在悄悄爬升,节点电压出现越限的苗头。调度员盯着SCADA系统里的几十个节点,要考虑要不要投电容器组、储能该充电还是放电、有载调压变压器的分接头要不要动。手忙脚乱调完一轮,下一轮风又变了,又是新一轮调整。整个过程完全依赖人工经验,既累又容易漏。

这就是主动配电网(ADN)动态最优潮流要解决的问题。所谓"动态",不是指时间常数意义上的暂态,而是说我要把未来一段时间(通常是24小时)的潮流优化整体打包求解。每个时段里都要满足潮流方程、节点电压上下限、设备出力边界,同时设备之间还有跨时段耦合——储能电池的荷电状态(SOC)是连续的,上一小时充了多少电,决定下一小时还能放多少;有载调压变压器的分接头不能频繁动作,一天之内动作次数有上限。

这里有个核心矛盾:潮流方程本身是非线性的,交流潮流模型带有电压的平方项和相角的余弦项,属于典型的非凸问题。一旦叠加了时序约束、离散变量(变压器档位、电容器组投切),问题就变成混合整数非线性规划(MINLP),理论上是NP难的。你直接扔给求解器,计算时间随节点规模迅速膨胀,在配电网这种动辄几百上千个节点的场景下基本跑不动。启发式算法(粒子群、遗传算法)虽然能解,但既不能证明最优性,又对初值敏感,参数调起来让人头疼——每个节点、每条线路的参数不同,同一套算法换个网架结构就得重新调参。

我需要把这个过程自动化、严谨化,而且要让模型在可接受的时间内给出可行解。经过一番调研和实测,我最终把技术路线锁定在"二阶锥规划(SOCP)"上。这篇文章就把从建模到实现的完整链条摊开讲,包括背后为什么要这么做、设备模型怎么进约束、求解之后怎么校验精度。适合正在做配电网优化方向的研究生、从事配电网规划运行的工程师,以及想快速上手最优潮流建模的开发者参考。

2. 选型逻辑:为什么二阶锥规划在主动配电网里成了主流

2.1 传统求解思路的瓶颈

在聊SOCP之前,先看看传统手段为什么不够用。配电网最优潮流最常见的形式是把潮流约束写成极坐标下的交流潮流方程,包含电压幅值、相角、有功无功注入。这是一个多变量、非线性、非凸的可行域,目标函数通常是最小化网损或运行成本。经典求解思路大致有几类:

  • 牛顿类内点法直接求解KKT条件,速度快但只能保证局部最优,初值不好就会收敛到次优解。
  • 半定规划(SDP)松弛把问题升维到矩阵空间,理论性质好,但对配电网这种节点多、支路多的网络,矩阵变量的规模偏大,求解内存和时间都不太友好。
  • 启发式算法灵活性强,能塞进各种复杂约束,但没有最优性保证,跑十次可能得到十个不同结果。

实际项目里还有个现实问题:配电网里大量设备是离散动作的——并联电容器组按组投切,变压器分接头按档位调节。MINLP模型即便对小算例能解,规模化之后也基本失控。所以我需要找一个松弛方式:既能处理非凸的潮流方程,又保持凸优化的优良性质,让求解器有收敛性和最优性保证。

2.2 DistFlow方程与变量替换

配电网和输电网最大的区别是:网络拓扑几乎总是辐射状(树形),潮流方向相对明确,线路电阻/电抗比(R/X)偏大。针对辐射状网络,有一类经典潮流方程叫Branch Flow Model(又称DistFlow),把每条支路上的潮流通过"首端有功、首端无功、电流幅值"三层关系传递下去。表达式如下:

对于支路(i, j):

  • P_ij - sum(P_jk + r_jk * I_jk^2) = P_j
  • Q_ij - sum(Q_jk + x_jk * I_jk^2) = Q_j
  • U_j = U_i - 2(r_ij * P_ij + x_ij * Q_ij) + (r_ij^2 + x_ij^2) * I_ij^2
  • I_ij^2 * U_i = P_ij^2 + Q_ij^2

前三个方程看着已经是二次的了,关键是第四个等式有平方项和乘积项,非凸。这里有一个关键的变量替换操作:把电压幅值平方U_i^2替换为新变量u_i,把电流幅值平方I_ij^2替换为新变量l_ij,于是最后一个约束变成:

l_ij * u_i = P_ij^2 + Q_ij^2

这个约束依然是非凸的。但如果我们只关心功率流动的物理可行域,可以把等式松弛成不等式:

l_ij * u_i >= P_ij^2 + Q_ij^2

这里有个直觉:这个不等式意味着支路电流至少满足"传输同样功率所需的最小电流"。把不等式标准化之后,它就变成标准的旋转锥约束(rotated second-order cone),属于二阶锥规划的一种形式。二阶锥规划本质上是线性规划和凸二次规划的推广,可行域是凸的,全局最优解可以被高效找到。

2.3 松弛是否精确:一个绕不开的问题

这里有个每个做SOCP的人都会被问的问题:你把等式松弛成不等式,解出来的结果还准吗?答案是:在一定条件下,松弛是精确的。

关键在于目标函数的"方向"。如果目标函数是凸的,且对电流(或网损)有单调激励——比如最小化网损、最小化购电成本——那么最优解会把不等式推向等式边界,因为电流越大损耗越大,成本越高。只要网络拓扑是辐射状的,DistFlow约束本身又保证了节点功率平衡,松弛后的解就会自动满足l_ij * u_i = P_ij^2 + Q_ij^2,从而还原为物理可行的交流潮流解。

但如果你把目标函数设置成比如"最大化线路潮流裕度"或者"最小化电压偏差的正一次项",这类目标可能导致锥松弛过松,解出不可行结果。这点务必记住:模型加约束之前,先想想目标函数会不会让松弛变"懒"。我在实际项目中做校验时有个习惯——求解完SOCP问题后,额外算一下每个支路的锥间隙(即不等式左右两端的相对偏差)。如果最大值超过1e-4,基本可以怀疑是模型有问题,需要检查约束和目标函数的方向。

理论背景交代完了,下面进入正题:具体每个设备模型怎么进约束。

3. 设备模型的数学化:储能、光伏、OLTC、无功补偿怎么进模型

3.1 分布式电源模型:PQ节点与逆变器无功能力

主动配电网里的分布式电源主要分两类:一类是同步机型分布式电源(小型燃气轮机、小型水电机组),可以当作常规PQ节点甚至PV节点处理;另一类是逆变器接口型(光伏、风电、储能),其有功出力和无功出力都可以独立控制,约束范围是逆变器容量限制。

逆变器接口型DG的模型一般写作:

  • P_dg_min <= P_dg(t) <= P_dg_max
  • Q_dg_min <= Q_dg(t) <= Q_dg_max
  • P_dg(t)^2 + Q_dg(t)^2 <= S_inv^2

最后一个约束是逆变器容量圆约束,它本身就是一个二阶锥约束,和我们的SOCP模型天然兼容。对于光伏,P_dg_max由当前时段的预测出力和光照强度决定;对于风电,P_dg_max由风速预测决定。这些都是模型的输入参数,不作为决策变量。

有个细节值得注意:很多文献会把DG的无功约束直接写成一个固定的上下限,比如±0.4倍的额定容量。但在实际建模中我建议按逆变器容量圆来写,因为这样能捕获"有功导致无功裕度下降"的真实物理现象——中午光伏满发时,逆变器已经接近容量极限,无功调节能力其实很小,如果你按固定无功上限建模,就会高估DG的无功支撑能力,算出来的电压分布偏乐观。

3.2 储能系统:时序耦合的关键角色

储能是所有设备里最需要小心建模的,因为它的状态变量SOC在时间维度上是链式耦合的。典型模型:

  • SOC(t+1) = SOC(t) - (eta_c * P_ch(t) - P_dis(t) / eta_d) * delta_t / E_rated
  • 0 <= SOC(t) <= 1
  • 0 <= P_ch(t) <= P_ch_max * u_ch(t)
  • 0 <= P_dis(t) <= P_dis_max * u_dis(t)
  • u_ch(t) + u_dis(t) <= 1

其中u_ch和u_dis是0-1变量,表示充放电状态不能同时为1。这里有一个常见误区:有人为了省事,不引入0-1变量,只允许P_ch和P_dis同时存在但方向相反(即用净功率定义)。这在单纯的经济调度里没问题,但在配电网潮流模型里会带来隐患——因为电网潮流方程用有功和无功作为两个独立变量,如果净功率为正时储能可能被描述成既充电又放电,这相当于对同一个物理装置做了双重结算,会低估运行成本、高估调节能力。

严格的做法是引入互补约束或0-1变量。不过0-1变量会让模型变成混合整数二阶锥规划(MISOCP),求解变慢。实际工程里我常用一个折中方案:如果时间步长足够小(比如15分钟),且目标函数里充电和放电价格差异不大,可以先不加0-1变量,用功率符号约束(用SOC的递推关系把状态固定住)再结合惩罚项。这种做法本质上是在精度和速度之间找了个平衡点。

储能的无功能力一般也走逆变器模型,即:

  • P_ess(t)^2 + Q_ess(t)^2 <= S_ess^2

和DG一样,注意有功出力会影响无功上限。

3.3 有载调压变压器(OLTC)与线路调压器

配电网里升压/降压变压器有分接头,可以调节电压,但它有两个工程限制:一天之内动作次数有限、相邻时段档位变化不能太频繁。如果不加约束,求解器会让变压器每15分钟换一档,现实中分接头的机械寿命根本扛不住。

建模时引入整数变量tap(t),表示t时段的档位:

  • U_j(t) = U_i(t) * (1 + tap(t) * delta_u) / r_tap

这个等式的非线性比较强,通常要做近似处理。常见做法是简化成电压幅值比例关系,然后在DistFlow模型里把变压器当作一个带变化的虚拟阻抗。更直接的办法:把网架中的变压器支路建模为"理想变压器+串联阻抗",理想变压器侧的电压幅值关系写成:

u_j(t) = u_i(t) * (1 + tap(t) * delta_u)^2

这个约束里u和tap是相乘关系,不是凸的。工程中常用的大招是把档位变化量作为决策变量,用大M法和辅助变量做线性化,或者直接对电压比做枚举(如果档位数量不多)。

还要加上动作次数约束:

  • |tap(t) - tap(t-1)| <= max_delta_tap
  • sum(|tap(t) - tap(t-1)|) <= max_total_action

这些约束对MISOCP来说都容易加,但求解时间会明显增加。我通常在概念验证阶段先不带档位约束,把变压器当成变比固定的节点处理;确认模型跑通了,再加上整数变量。

3.4 并联补偿装置:电容器组与SVC

配电网里的无功补偿主要有两类:一类是机械式投切的电容器组(离散动作),另一类是动态无功补偿装置SVC/SVG(连续调节)。电容器组模型是:

  • Q_cap(t) = n_cap(t) * Q_step
  • 0 <= n_cap(t) <= N_cap_max, n_cap为整数

SVC模型就是连续无功源:

  • Q_svc_min <= Q_svc(t) <= Q_svc_max

这两类相对简单,直接进节点功率平衡方程就行。唯一需要注意的是,如果电容器的投切和前一时段状态有关(比如避免频繁投切),那也得像OLTC一样加动作次数的整数约束。

4. 动态端口:把24小时串联成一个整体问题

4.1 时段划分与典型日选择

做动态最优潮流,第一步其实不是写约束,而是决定怎么划分时间窗口。时间窗口太粗(比如1小时一个点),会低估光伏出力的快速波动,SOC递推的误差也被放大;太细(比如5分钟一个点),决策变量数量暴涨,求解器和内存压力都很大。

我在项目里一般先用15分钟步长做24小时规划,一天共96个时段,算是精度和计算量的折中。如果只做典型日分析,建议从全年8760小时数据里挑选"光伏大发+负荷高峰"叠加的日子,因为这种场景下电压越限的风险最高,最能暴露模型的约束能力。

4.2 储能SOC递推:初始值与末端约束

动态问题的关键是把储能SOC的递推关系写对。除了前面写过的差分方程,还有一个微妙的地方:一天的规划周期结束时,SOC应该落在什么位置?如果什么都不约束,求解器很可能把储能"榨干",最后SOC跑到0,次日无法继续运行。现实中储能需要为第二天留出余量。

工程上常用的处理方式有几种:

  • 固定末端SOC等于初始SOC(保证日循环电量平衡);
  • 末端SOC设定为一个区间,比如0.2~0.3;
  • 在目标函数里加末端SOC偏离惩罚项。

我在实际项目中倾向用"初始SOC=末端SOC+松弛偏差"的做法,并在目标函数里对偏差加小惩罚系数。这样模型既不会强迫储能必须严格回到初始值(给调度留灵活度),又不会出现末日清仓式的极端策略。

4.3 跨时段爬坡:光伏逆变器和常规机组的出力变化率

常规发电机组有爬坡约束,这个大家都熟悉。但主动配电网里还有一个常被忽略的爬坡——光伏逆变器的有功功率变化率。虽然逆变器本质上是电力电子器件,爬坡可以做到很快,但为了避免对上级电网产生冲击,并网导则通常要求有功变化率受限。这个约束在优化模型里可以写成:

  • |P_dg(t) - P_dg(t-1)| <= ramp_max

爬坡约束是线性的,加进去没有技术难度,但会限制求解器的"跳跃能力",从数值角度来说,它反而常常让SOCP问题更快收敛。

4.4 一次性求解还是滚动时域

动态最优潮流有两个实现路线:一次性求解24小时的全时段模型(open-loop),或者用模型预测控制(MPC)滚动求解。前者结构简单、适合离线分析,后者对预测误差更鲁棒、适合在线调度。

在写论文或者做规划评估时,一次性求解就行,重点是把约束写完整。但如果要部署到实际运行环境,我建议至少做两层:先用SOCP做24小时的日前计划(开环),然后在日内用MPC滚动修正。SOCP的求解速度足够支撑MPC的场景——一个100节点配电网的96时段SOCP模型,在桌面级求解器上通常能在几十秒到几分钟内解完。

5. 实现细节:标幺化、建模框架、求解器选型与精度校验

5.1 标幺化:被低估的一个环节

很多初学者直接拿有名值(kW、kVar、V、Ω)去建模,结果数值范围跨越好几个数量级:功率是10^3级别,电压是10^4级别,阻抗是10^-2级别。二阶锥规划的锥约束对数值尺度非常敏感,这种数量级差异会让求解器在数值鲁棒性上吃大亏,甚至出现"看起来收敛但结果明显不对"的情况。

正确做法是基准功率和基准电压各取一个值:

  • S_base = 1 MVA(或10 MVA)
  • U_base = 12.66 kV(对中压配电网)
  • Z_base = U_base^2 / S_base

所有设备的功率、线路阻抗、电压幅值都除以各自的基准值,让变量落在0.01~10这个量级。特别是电压平方变量u_i,标幺化之后在0.8~1.2附近,松紧度最合适。如果你的网架有多个电压等级,要注意变压器两侧的基准电压要按变比配套,否则标幺值会在变压器处出现不连续。

5.2 建模框架与求解器对比

我在Matlab环境里首选YALMIP做建模层,因为它语法简练,底层可以无缝切换求解器。Python环境下可以用CVXPY,社区生态也越做越好。两者都能表达二阶锥约束和混合整数变量。

求解器方面,实测下来各有所长。表格列一下:

求解器类型适用场景许可证
Mosek连续SOCP/SDP大规模连续问题,数值最稳定商业授权(学术免费)
Gurobi连续/混合整数二阶锥(MISOCP)含OLTC、电容器组等离散变量的场景商业授权(学术免费)
CPLEX连续/混合整数二阶锥老牌,稳定性好商业授权
SDPT3连续SDP/SOCP学术研究,小规模问题免费
ECOS嵌入式和常规SOCP轻量级,适合小算例MIT协议

就我的使用体验来说,只要不涉及整数变量,Mosek是首选,收敛快、警告少。一旦模型里加了0-1变量,Mosek就不行了,必须换Gurobi或CPLEX跑MISOCP。Gurobi的MISOCP在配电网模型里表现相当稳定,一个96时段的算例放在它手里基本不用操心求解器层面的问题。

5.3 YALMIP建模核心代码骨架

一段最简可跑的YALMIP+Mosek核心框架如下,方便快速搭积木:

% 决策变量 u = sdpvar(N, T); % 电压幅值平方 P = sdpvar(N-1, T); % 支路有功(去掉根节点) Q = sdpvar(N-1, T); % 支路无功 l = sdpvar(N-1, T); % 支路电流幅值平方 P_dg = sdpvar(N_dg, T); % DG有功 Q_dg = sdpvar(N_dg, T); % DG无功 SOC = sdpvar(N_ess, T); % 储能荷电状态 constraints = []; for t = 1:T % 节点功率平衡 for i = 1:N if is_root(i) constraints = [constraints, P(1,t) == P_in(t)]; else constraints = [constraints, P_parent(i,t) - sum(P_child(i,:,t)) == ... P_load(i,t) - P_dg_map(i,t)]; end end % 支路电压-潮流耦合 for e = 1:n_branch constraints = [constraints, l(e,t) .* u(to_node(e),t) >= P(e,t)^2 + Q(e,t)^2]; constraints = [constraints, u(to_node(e),t) == u(from_node(e),t) ... - 2*(r(e)*P(e,t) + x(e)*Q(e,t)) ... + (r(e)^2 + x(e)^2)*l(e,t)]; end % 电压上下限 constraints = [constraints, U_min^2 <= u(:,t) <= U_max^2]; end % 储能SOC递推 for t = 1:T-1 constraints = [constraints, SOC(:,t+1) == SOC(:,t) ... - (eta_c*P_ch(:,t) - P_dis(:,t)/eta_d)*dt/E_rated]; end ops = sdpsettings('solver', 'mosek', 'verbose', 2); optimize(constraints, objective, ops);

注意这段代码里我故意用l(e,t) * u(to_node(e),t) >= P^2 + Q^2的形式,而不是展开成二阶锥标准形式,YALMIP会自动识别并转换为锥约束。这是最省心的写法,也最容易出bug的地方是节点编号和支路方向的对应关系,写错一个索引结果就很离谱。

5.4 求解后的交流潮流校验

求解器给出的是松弛问题的解,即使锥间隙很小,我仍然建议在代码流程中加一个事后校验环节:把SOCP求出的节点电压和支路功率代入原始交流潮流方程,检查功率不平衡量。

这个校验有多重要?我用一句话说明:你算出来的目标函数值很漂亮,但如果解不满足原始潮流方程,那这个"最优解"在物理上根本不存在,属于数学上的可行、物理上的幻象。校验方法是在每条支路上计算:

  • 从节点i流出的功率减去上游注入功率,是否等于节点负荷减DG出力
  • 电压幅值关系和支路电流是否满足欧姆定律

如果功率不平衡量超过1e-3(标幺值),我会回头检查是不是目标函数导致锥松弛过松,或者是标幺化出了问题。

6. 实战中踩过的坑:收敛性、精度与性能的平衡

6.1 锥松弛过松的典型案例

有一次我在做一个最大化DG消纳的模型,目标函数是让DG总出力最大。求解器很快返回"最优解",但事后校验发现多个支路的锥间隙高达0.2,也就是说松弛解和物理可行解差了20%。问题出在目标函数方向:最大化DG出力会让模型倾向于"尽可能多地把功率送不出去也要送",此时优化器会利用松弛后的不等式空间来虚增传输能力,导致结果对潮流方程完全不忠实。

当时我的处理方式是改成两阶段目标:第一阶段先最大化DG出力,记录最优值;然后把这个最优值作为等式约束固定下来,第二阶段再最小化网损。这样目标函数变成"最小化网损",锥松弛重新变得精确,DG消纳量和潮流可行性都能兼顾。这是个很实用的技巧——用两个目标叠加去引导松弛精度。

6.2 储能SOC初始值的敏感性

储能SOC的初值对解的影响比很多人想象的大。如果初值设成0.5,末端不约束,你会看到SOC在夜间低谷段疯狂充电、白天高峰段疯狂放电,看起来调度很完美。但如果初值设成0.1,可能会触发"白天充电不足、晚上放不出电"的边界解。更要命的是,当SOC贴着上限或下限走时,储能的实际调节能力变成零,但模型里可能还是认为它能参与无功调节(因为逆变器容量约束没变),这又会导致电压结果的偏差。

实操建议:做灵敏度分析时,把SOC初值从0.1到0.9扫一遍,看目标函数和电压曲线的差异。如果差异超过可接受范围,说明储能调用策略对初值过于敏感,建议在目标函数里加SOC中线恢复的惩罚项,或者缩短优化周期(比如每次只优化未来4小时)。

6.3 离散变量带来的组合爆炸

加了OLTC档位和电容器组整数变量之后,模型从SOCP变成MISOCP。3个OLTC各21个档位、5组电容器各3组投切状态,组合起来就是(21^3)*(3^5)≈1200万种组合,想靠枚举显然不现实。Gurobi这类求解器内置了分支定界(branch and bound),但求解时间会随离散变量个数指数式增长。

实践里我一般先用连续松弛跑一遍(把所有整数变量当成连续量),看看哪些离散变量在最优解里长期贴着边界,然后把这些变量固定住,只对真正活跃的离散变量保持整数性。这种"连续预筛+整数精修"的做法,能把MISOCP的求解时间从几十分钟压到几分钟,精度损失通常很小。

6.4 大M法的数值灾难

把逻辑约束(比如充放电互斥)转成线性表达式时,大M法最常用。但M值不能拍脑袋写个1e6,因为SOCP求解器内部对M值很敏感,过大的M会让解在数值上不稳定,产生"低精度可行解"甚至伪解。

我习惯的做法是:逐个约束分析变量的物理边界,M值设为边界上限的1.1倍。例如充放电功率上限是P_max,那M取1.1*P_max就够了。宁可每个约束都单独设M,也不要统一用一个超大的数字。如果你看到求解器返回"NUMERICAL_ERROR"或者"SUBOPTIMAL"的求解状态,先检查所有大M的取值,这是最高频的原因。

6.5 计算时间与精度的螺旋

配置出一套可以部署的代码之后,你会发现性能瓶颈往往不在求解器本身,而在模型表达。同样的数学问题,YALMIP里写法不同,前处理时间能差出好几倍。

几个提速经验:

  • 能用线性约束表达的,不要绕弯写锥约束;
  • 所有常数项尽量提前计算,不要在每个时段的约束里重复调用函数;
  • 如果嵌套了大量循环(for t, for node),可以考虑向量化或矩阵化表达,YALMIP对矩阵表达式的前处理更快;
  • 求解器选项里关闭不必要的日志输出、设一个合理的求解时间上限(参考你的需求,比如300秒),超时就直接出当前最优可行解,别让它在间隙很小的解上继续磨。

另外,建议养成每次求解后检查求解器状态的习惯:solve_time、gap、simplex_iter、problem状态这些字段全都要打印出来。很多"结果不对"的问题,根源其实是求解器根本没收敛,只是解出了一个可行解,却被你当成最优解用了。

最后再分享一个小技巧:SOCP模型的二阶锥约束可以预先归一化,也就是把每个锥约束的尺度调整到同一水平。这个技巧来自我在一次实际项目中被数值警告折磨到崩溃后的顿悟——当时一个包含DG、储能、OLTC、电容器的完整模型在Mosek里始终报数值问题,我把所有锥约束都拿去做了一次归一化分析,发现有些约束的尺度是1e-3,有些是1e3,吓出一身冷汗。统一尺度之后再跑,一次过。这种经验不好写进文档里,但在实际项目里能救你命。

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

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

立即咨询