☰
分布式电源优化配置的二阶锥松弛与MATLAB+YALMIP实现
2026/10/8 17:04:53 网站建设 项目流程

前阵子帮几个做配电网规划的朋友审程序,发现一个很有意思的现象:很多人一提到分布式电源优化配置,第一反应就是上智能算法——粒子群、遗传算法轮番上,把网损、电压、成本全塞进适应度函数里,跑个几千代碰运气。倒不是说启发式算法没用,而是这个问题的数学结构,明明可以写得非常干净:潮流约束经过二阶锥松弛之后,配上 MATLAB+YALMIP 建模,用 CPLEX 或 Gurobi 这种商业求解器,几十秒内就能拿到带最优性证明的解。分布式电源优化配置 + 二阶锥 + 编程方法这套组合,正是目前配电网规划论文和工程可研里最主流、也最值得掌握的技术路线。

这篇文章就从一个实际可跑的算例出发,把完整链路走一遍:为什么要用二阶锥、DistFlow 潮流方程怎么一步步松弛成锥约束、MATLAB+YALMIP 里怎么写、CPLEX/Gurobi 怎么调,以及我在这条路上踩过的坑。无论你是刚接触配电网优化的研究生,还是被智能算法坑过、想换个严谨求解方案的工程师,这篇文章应该都能让你少走不少弯路。

1. 为什么分布式电源优化配置会写成二阶锥

1.1 分布式电源配置到底在优化什么

分布式电源优化配置,通俗说就是回答两个问题:分布式电源装在哪里,装多大。这里面既可能包含光伏、风电这类间歇性电源,也可能包含燃气轮机、储能等可调度资源。配好了,可以降低网损、改善电压分布、延缓配电网扩容;配得不好,轻则网损不变甚至上升,重则引起节点电压越限、线路过载、逆潮流倒送等一堆麻烦。

一个完整的优化配置模型,目标函数常见的做法是这几种:

  • 年综合费用最小,包含 DG 投资成本、运行维护成本、网损费用,有时还加上购电费用;
  • 系统有功网损最小;
  • 节点电压偏差最小;
  • 或以上多个目标的加权组合。

约束条件则至少包含潮流约束、节点电压上下限约束、支路电流上限约束、DG 安装容量上限约束。如果还考虑了 DG 的选址问题,那就会引入 0-1 整数变量——某个节点建不建 DG——模型就会从纯连续优化升级为混合整数优化。

我在这篇文章里,主线采用"网损最小"作为目标,同时把"DG 是否安装"这个 0-1 决策放进去。这样既能让读者理解 SOCP 松弛的核心,又能完整演示混合整数二阶锥规划(MISOCP)在 YALMIP 里的写法。等你掌握了这个框架,想换成年综合费用目标,或者加时序场景,都是改目标函数和约束集的问题,不用推翻重来。

1.2 潮流约束的非凸性让求解变得尴尬

很多人一开始会想:既然要做规划,那我直接用牛顿-拉夫逊法求解交流潮流,再套一层粒子群、遗传算法去搜 DG 位置和容量不就行了?

这个思路没有错,但问题在于非线性的交流潮流方程是非凸的。非凸意味着什么?意味着整个可行域可能有大量局部极值点,启发式算法只能保证"找到一个可行解",无法证明这个解离全局最优有多远。运气好的时候找到的解挺漂亮,运气不好就只能在论文里画一张收敛曲线自我安慰。更麻烦的是,外层智能算法每评估一个粒子都要跑一次完整潮流,算 33 节点可能还行,一旦扩展到 100+ 节点、多场景、多时段,计算量会迅速爆炸。

而二阶锥规划(SOCP)不一样。SOCP 是一种特殊的凸优化问题,可行域是凸的,局部最优就是全局最优。再加上 CPLEX、Gurobi 这类商业求解器采用分支定界法处理整数变量,配合线性松弛,可以在有限时间内给出"全局最优解",并附带最优性间隙(MIP Gap)。在工程可研里,你能给业主一个"这个解离最优解偏差不超过 0.1%"的量化保证,这比启发式算法的一句"算法收敛到最优"要硬气得多。

1.3 为什么偏偏是二阶锥,而不是线性规划

既然凸优化这么好,那直接用线性规划(LP)简化潮流不更省事?这就要看你要什么精度的潮流模型了。

线性化的潮流模型(比如忽略网损的 DistFlow 线性形式)处理规划问题非常快,但它把网损项直接丢掉了——而你优化目标恰恰就是网损,这会陷入一个逻辑矛盾:你想降低的东西,在你的模型里根本不存在。此外线性潮流在电压偏差较大、DG 渗透率较高时,误差会明显变大。

二阶锥的好处在于:它保留了潮流方程里最关键的非线性项 ——有功无功的平方项 —— 但不让这个非线性项破坏凸性。它是"精确性"和"可解性"之间一个非常合适的平衡点。对于辐射状配电网,DistFlow 潮流方程经过变量替换和凸松弛后,可以严格转换成二阶锥形式。在绝大部分实际场景下,这个松弛是精确的,也就是解出来的结果和原交流潮流模型几乎等价。这一点在后面的推导里你会看得很清楚。

这里顺手整理了一个求解器的对比,方便大家做技术选型:

求解器支持 SOCP支持整数变量MATLAB 接口备注
Gurobi支持支持(MISOCP)自带,gurobi_setup.m一步配置求解速度快,学术界/工业界都很流行
CPLEX支持支持(MISOCP)需安装配套接口老牌稳健,文档多,节点和割平面参数细
MOSEK支持支持自带SOCP 内点法很强,整数能力一般
ECOS支持不支持YALMIP 内置免费,连续 SOCP 完全够用
SCS支持不支持YALMIP 内置免费,大规模问题表现好
Sedumi / SDPT3支持不支持YALMIP 内置传统半定/SOC 求解器,速度一般

如果模型里没有 0-1 整数变量,那么免费的 ECOS、SCS 完全可以跑完连续 SOCP;一旦加入"节点装不装 DG"这种选址变量,就变成 MISOCP,还是老老实实上 Gurobi 或 CPLEX 吧。

2. DistFlow 潮流方程的凸松弛推导

2.1 先认识 DistFlow:辐射网的潮流专用方程

要做配电网优化,一般不用交流潮流的一般形式(节点导纳矩阵那个),而是用DistFlow 支路潮流方程。它的核心假设很贴合配电网:辐射状结构,根节点是变电站,潮流逐级向外流动,忽略支路对地电容,并把电压相角的影响用较小的误差换掉。

对每条支路i -> j,DistFlow 用四个变量描述潮流:

  • P_ij:从节点 i 流向节点 j 的有功功率(支路首端功率)
  • Q_ij:从节点 i 流向节点 j 的无功功率
  • U_i:节点 i 的电压幅值平方,即U_i = V_i^2
  • L_ij:支路 ij 的电流幅值平方,即L_ij = I_ij^2

标准 DistFlow 方程组如下:

P_ij - r_ij * L_ij = sum(P_jk) + P_load_j - P_DG_j Q_ij - x_ij * L_ij = sum(Q_jk) + Q_load_j - Q_DG_j U_j = U_i - 2 * ( r_ij * P_ij + x_ij * Q_ij ) + ( r_ij^2 + x_ij^2 ) * L_ij

其中r_ij、x_ij是支路电阻和电抗,sum(P_jk)表示从节点 j 流向它所有子节点的有功之和。第一个方程是节点有功平衡,第二个是节点无功平衡,第三个是电压降落方程。这三条都是线性的,所以 DistFlow 的非线性只来自最后一个变量关系。

2.2 DistFlow 唯一的非线性项,来自电流的定义

交流电路里电流、功率和电压还有一层天然约束:

I_ij^2 = ( P_ij^2 + Q_ij^2 ) / V_i^2

用我们定义的变量替换,就是:

L_ij = ( P_ij^2 + Q_ij^2 ) / U_i

这是一个等式约束,而且P^2 + Q^2除U的形式是一个非凸约束。问题就出在这里。如果直接把这个约束丢给求解器,整个模型就回到非凸非线性规划的老路上,无法保证全局最优。

二阶锥松弛的做法,就是把这个等式约束放宽成不等式:

L_ij >= ( P_ij^2 + Q_ij^2 ) / U_i

注意这个放宽的方向是精心选择的:原本"等于",现在允许"大于等于"。也就是说,模型允许电流幅值平方比实际需要的功率/电压比值更大。听起来像是放水,但关键在于,目标函数是网损最小,网损和 L 直接成正比,所以优化器会本能地把 L 压到最小。只要没有其他约束拦着,最优解里的 L 就会贴在不等式边界上,也就是取等号。于是松弛问题和原问题在最优解处等价。

2.3 把不等式写成一目了然的二阶锥标准式

L >= (P^2 + Q^2) / U虽然直观,但要直接进入求解器,最好写成一阶形式的标准二阶锥约束。整理一下:

L * U >= P^2 + Q^2

这个式子两边一乘,看起来仍然不是锥。标准二阶锥的形式是|| [x; y] ||_2 <= z。对上面的约束做一个恒等变形:

4 * ( P^2 + Q^2 ) + (U - L)^2 <= (U + L)^2

展开化简就能得到:

|| [ 2P ; 2Q ; U - L ] ||_2 <= U + L

这才是 YALMIP 里可以直接用的标准形式。如果你用cone()函数,写出来就是:

cone([2*P; 2*Q; U_fb - L], U_fb + L)

cone()在 YALMIP 里定义的是norm(x, 2) <= y,其中第一个参数是列向量,第二个参数是标量。这一句就完整表达了两条支路潮流约束的组合关系,非常干净。

到这里,DistFlow 的四条方程里三条是线性的,最后一条被松弛成了二阶锥约束。整个配电网潮流模型就变成了一个凸的 SOCP 模型。如果再加上 DG 选址的 0-1 变量,就是 MISOCP。

2.4 完整数学模型长什么样

把上面推导的方程拼起来,得到一个可用于编程的完整模型。我用最常用的网损最小目标来展示:

目标函数:

min J = sum( r_ij * L_ij )

考虑投资成本时,可以直接在后面加一项alpha * sum(C_dg_i * S_dg_i),其中 alpha 是网损费用和投资费用的权重系数。

约束条件:

约束类别数学形式说明
节点有功平衡P_ij - r_ij * L_ij = sum(P_jk) + P_load_j - P_DG_j流入功率减去支路损耗,等于负荷加流出功率
节点无功平衡Q_ij - x_ij * L_ij = sum(Q_jk) + Q_load_j - Q_DG_j无功同理
电压降落U_j = U_i - 2*(r_ij*P_ij + x_ij*Q_ij) + (r_ij^2 + x_ij^2)*L_ij线性方程
电流定义松弛`
根节点电压U_1 = 1变电站母线电压设为 1 pu 标幺值
电压上下限U_min <= U_i <= U_max一般取 0.95^2 ~ 1.05^2
DG 出力上限0 <= P_DG_i <= S_DG_i有功不能超过配置容量
DG 无功上限Q_DG_i <= P_DG_i * tan(acos(pf))按功率因数约 0.9 折算
DG 安装决策0 <= S_DG_i <= S_max * x_i,x_i ∈ {0,1}只有 x_i=1 的节点允许装 DG
DG 总容量上限sum(S_DG_i) <= S_total_max按并网批复或消纳能力约束

给变量符号做个统一约定,编程时就不会乱:

符号含义单位(标幺)
P_ij/Q_ij支路首端有功/无功pu
U_i节点电压幅值平方pu^2
L_ij支路电流幅值平方pu^2
S_DG_i节点 i 的 DG 配置容量pu
x_i节点 i 是否安装 DG0/1
P_load_i/Q_load_i节点负荷pu

3. MATLAB + YALMIP + CPLEX/Gurobi 的工程落地

3.1 环境版本和安装避坑

先说版本。理论上 MATLAB R2019b 及以上都可以,YALMIP 目前仍在活跃更新,直接在yalmip.github.io下载最新压缩包,解压后addpath(genpath('yalmip文件夹')),再savepath保存路径即可。这种直接从官网拉源码的方式,比很多来路不明的网盘资源靠谱得多。

求解器的安装是大多数人卡壳的地方。Gurobi 相对省心:安装 Gurobi 后,在 MATLAB 里运行 Gurobi 安装目录下自带的gurobi_setup.m,把接口加到 MATLAB 路径,然后yalmiptest就能检测到。CPLEX 则需要 IBM 的安装包,并配好对应 MATLAB 版本的接口。很多老版本 CPLEX 的 mex 文件会因为 MATLAB 版本升级而失效,这时要么换新版 CPLEX,要么在 MATLAB 当前版本的支持矩阵里找对应接口。我个人的建议是:如果新项目没有历史包袱,优先选 Gurobi;如果是和已有 CPLEX 论文代码对比,才用 CPLEX。两者的 MISOCP 求解能力都在第一梯队,但 Gurobi 的授权和安装流程对 MATLAB 用户更友好。

有个容易被忽略的点:如果没有商业求解器授权,可以在 YALMIP 里先用sdpsettings('solver','ecos')或solver','scs'跑连续 SOCP 问题练手。ECOS/SCS 都是免费开源求解器,而且 YALMIP 内置了接口配置文件,路径都不需要自己配。但一旦模型带整数变量,免费求解器能处理的规模和数据稳定性都很有限,还是要回到商业求解器上来。

3.2 算例数据准备:IEEE 33 节点系统和标幺化

我用的是电力系统优化里最常见、也最轻量的IEEE 33 节点辐射状配电网。如果你电脑里有 MATPOWER,可以直接加载它自带的case33bw数据:

mpc = loadcase('case33bw'); baseMVA = mpc.baseMVA; % 基准功率,一般 10 MVA bus = mpc.bus; branch = mpc.branch;

这里有一个非常重要的细节:MATPOWER 的 branch 数据里,电阻电抗单位是欧姆,不是标幺值。节点电压倒是已经给了标幺值形式,所以潮流计算里电压直接可以用,但阻抗必须做标幺化换算:

% 基准阻抗 V_base_kV = bus(1, 11); % 基准电压,case33bw 里是 12.66 kV Z_base = V_base_kV^2 / baseMVA; % Z_base = 12.66^2 / 10 ≈ 16.03 欧姆 r_pu = branch(:, 3) / Z_base; % 支路电阻标幺值 x_pu = branch(:, 4) / Z_base; % 支路电抗标幺值 P_load = bus(:, 3) / baseMVA; % 有功负荷标幺值 Q_load = bus(:, 4) / baseMVA; % 无功负荷标幺值

很多新手把欧姆值直接当期"pu"用,算出来的电压曲线平得诡异,网损也小得离谱,基本就是这个原因。之前我帮人排查一个模型,解出来网损只有 0.0002 pu,明显量级不对,一查就是阻抗没除基准值。

在写模型之前,统计一下基本数据:

n = size(bus, 1); % 33 个节点 nbr = size(branch, 1); % 32 条支路 S_max = 0.2; % 单节点 DG 最大容量,2 MW / 10MVA = 0.2 pu pf = 0.9; % DG 功率因数

另外,对于 33 节点系统,case33bw的支路顺序基本上就是按"父节点 -> 子节点"排列的,大部分支路满足branch(k,1) < branch(k,2),可以直接用。如果不放心,可以用 BFS 从根节点 1 出发理顺拓扑。这里为了代码简洁,我直接按 MATPOWER 数据方向的常规假设来用。

3.3 YALMIP 核心建模代码逐段拆解

下面这段就是整个 MISOCP 模型的核心。我把每个 block 拆开讲。

第一步:定义决策变量。

U = sdpvar(n, 1); % 节点电压幅值平方 L = sdpvar(nbr, 1); % 支路电流幅值平方 P = sdpvar(nbr, 1); % 支路有功潮流 Q = sdpvar(nbr, 1); % 支路无功潮流 P_DG = sdpvar(n, 1); % DG 有功注入 Q_DG = sdpvar(n, 1); % DG 无功注入 S_DG = sdpvar(n, 1); % DG 配置容量 X = binvar(n, 1); % 选址变量,1 表示该节点安装 DG

如果只做定容不做选址,就把X删掉,S_DG的上限直接用常数S_max卡住。完整版里加上X,展示的是更通用的选址定容模型。

第二步:写约束集合。

C = []; % 电压上下限,根节点电压固定为 1 pu C = [C, 0.95^2 <= U <= 1.05^2]; C = [C, U(1) == 1]; % DG 出力约束 for i = 1:n C = [C, 0 <= P_DG(i) <= S_DG(i)]; % 有功不超过容量 C = [C, Q_DG(i) <= P_DG(i) * tan(acos(pf))]; % 功率因数约束 C = [C, Q_DG(i) >= - P_DG(i) * tan(acos(pf))]; % 考虑容性/感性调节 C = [C, 0 <= S_DG(i) <= S_max * X(i)]; % 容量与选址变量的耦合 end % 可选:DG 总容量约束 % C = [C, sum(S_DG) <= S_total_max];

这里S_DG(i) <= S_max * X(i)是选址和定容的关键耦合约束。如果X(i)=0,容量只能为 0;如果X(i)=1,容量放宽到上限。这种写法在 MISOCP 里非常常见,本质是一个大 M 约束,只不过把S_max当成了 M。

第三步:写支路潮流约束。

for k = 1:nbr fb = branch(k, 1); % 父节点 tb = branch(k, 2); % 子节点 rk = r_pu(k); xk = x_pu(k); % 二阶锥约束,对应 L >= (P^2 + Q^2) / U C = [C, cone([2*P(k); 2*Q(k); U(fb) - L(k)], U(fb) + L(k))]; % 电压降落方程 C = [C, U(tb) == U(fb) - 2*(rk*P(k) + xk*Q(k)) + (rk^2 + xk^2)*L(k)]; end

这一段是整个模型的精髓。cone()的第一参数是[2P; 2Q; U_fb - L],第二参数是U_fb + L。YALMIP 看到这种结构,会自动识别为二阶锥约束,传给 Gurobi/CPLEX 时也走对应的圆锥接口,速度会快很多。

第四步:节点功率平衡约束。

对于辐射网,每个非根节点只有一个父支路。我用一个parentbr数组记录每个节点的父支路编号,children存每个节点的子支路编号,然后逐节点写功率平衡:

% 计算父子关系 parentbr = zeros(n, 1); children = cell(n, 1); for k = 1:nbr fb = branch(k, 1); tb = branch(k, 2); parentbr(tb) = k; children{fb}(end+1) = k; end % 节点功率平衡 for j = 2:n % 根节点 1 是松弛节点,跳过 kp = parentbr(j); % 父支路编号 rk = r_pu(kp); xk = x_pu(kp); % 流出有功 = 该节点所有子支路首端功率之和 outP = 0; outQ = 0; for kc = children{j} outP = outP + P(kc); outQ = outQ + Q(kc); end % 有功平衡:上游注入减去损耗 + DG - 负荷 = 下游流出 C = [C, P(kp) - rk*L(kp) + P_DG(j) - P_load(j) == outP]; % 无功平衡 C = [C, Q(kp) - xk*L(kp) + Q_DG(j) - Q_load(j) == outQ]; end

这里P(kp) - rk*L(kp)是父支路送达到节点 j 的功率,这个写法扣除了支路损耗,是精确版 DistFlow。很多文献里为了简化会省掉损耗项,对于辐射网 33 节点这种阻抗不大、网损小的问题影响不大,但既然模型里已经引入了 L,顺手把损耗扣掉并不增加复杂度,反而让结果更严谨。

第五步:目标函数和求解设置。

% 目标函数:网络有功损耗最小 J = sum(r_pu .* L); % 求解设置 ops = sdpsettings('solver', 'gurobi', 'verbose', 1, 'gurobi.MIPGap', 1e-3); % 如果用 CPLEX,则: % ops = sdpsettings('solver', 'cplex', 'verbose', 1, 'cplex.mip.tolerances.mipgap', 1e-3); % 求解 result = optimize(C, J, ops);

optimize返回后,result.problem等于 0 表示成功求解,非 0 需要查yalmiperror(result.problem)看具体错误。这是 YALMIP 里最基本也最常被忽略的检查步骤。

3.4 求解器的参数设置细节

在 YALMIP 里设置求解器参数,格式是'求解器名.参数名'。Gurobi 的 MIPGap 在 YALMIP 里的字段名是gurobi.MIPGap,而 CPLEX 是cplex.mip.tolerances.mipgap,两家命名风格差异很大,切换求解器时特别容易搞混。

几个我常用的参数组合:

ops = sdpsettings(... 'solver', 'gurobi', ... 'verbose', 1, ... 'gurobi.MIPGap', 1e-3, ... 'gurobi.TimeLimit', 300, ... 'gurobi.NumericFocus', 1); % 数值稳定性优先
  • MIPGap:1e-3 表示当整数解的gap小于 0.1% 时停止,足够工程使用。想要更精确可以设 1e-4,代价是求解时间变长。
  • TimeLimit:超过 300 秒强制返回当前最优整数解。规划问题不需要像运行调度那样抢时间,但卡住不动时有一个兜底总比干等强。
  • NumericFocus:Gurobi 的数值病态开关,模型里面如果存在数量级相差很大的系数,建议打开。

如果你用的是连续 SOCP(没有X变量),Gurobi 会直接走连续二阶锥算法,不需要设 MIPGap,求解速度通常在几秒以内。加了 0-1 分支之后,求解时间取决于候选节点数量。33 节点如果允许全节点安装,33 个 0-1 变量分支起来也不会太慢;但到 100+ 节点时,就要往下文说的提速技巧上靠了。

4. 结果校验与几个真正有用的工程技巧

4.1 松弛间隙检查:验证"松弛是紧的"

二阶锥松弛的数学优雅是一回事,工程上能不能信是另一回事。跑完模型,第一件事不是画图,而是检查每条支路的松弛间隙。你要确认松弛不等式在最优解处基本都是取等号的,否则模型和原问题就不等价了。

计算方法很简单。对每条支路:

gap = L_opt - (P_opt.^2 + Q_opt.^2) ./ U_parent_opt;

其中U_parent_opt = U_opt(branch(:,1))。如果这个 gap 相对L_opt的比例在 1e-3 量级甚至更小,松弛就是紧的,结果可信。如果某个支路 gap 很大,说明该支路电流被约束拉离了物理下限,可能出现电压越限约束卡得太紧、或者网损目标被其他权重项干扰的情况。

我在实际跑 33 节点案例时,通常所有支路的相对间隙都能低于 1e-8,这已经很接近数值精度极限了。如果你的模型出现较大间隙,先别急着信结果,回头检查一下是不是电压上限约束设得过窄,或者目标函数里额外加的投资项权重过大。

4.2 电压分布:模型结果到底改变了什么

求解完成后,把电压结果取出来开方,就得到每个节点的电压幅值标幺值:

U_opt = value(U); V_opt = sqrt(U_opt);

对比一下两种场景:一是电网不装 DG 的基准潮流电压,二是优化配置 DG 后的电压。你会看到 DG 接入点附近电压有明显抬升。如果某些节点电压抬到了 1.05 附近,说明 DG 容量已经接近该节点的承载上限。这个信息比网损数字更有工程意义,因为配电网规划中电压越限往往是比网损更"硬"的约束——你不可能为了省电费让用户电压超标。

顺手提一句,如果模型里设置了Q_DG的无功调节能力,电压改善效果会比纯有功注入更明显。逆变器型的 DG 完全可以利用无功调节来抑制过电压,这也是分布式电源优化配置里值得深入研究的方向。

4.3 算得快和算得准的几个思路

求解速度问题在 MISOCP 里非常现实。我自己的经验是,以下几招最有效:

  • 限制候选节点。工程上不是每个节点都适合装 DG,比如只有末端负荷重、电压偏低的节点才真正需要 DG 支撑。把候选节点从 33 个缩到 5~10 个,整数变量数量直接降一个量级,求解时间可以缩短 10 倍以上。
  • 先跑连续松弛,再分支定界。把X变量的整数约束释放成0 <= X <= 1,先解一个连续 SOCP,然后把结果作为整数搜索的热启动值。YALMIP 里可以用assign()和initialized参数把初始解喂给求解器,能显著减少分支数。
  • 放宽 MIPGap。工程方案对比阶段,MIPGap 设 1e-2 完全够用;只有最终方案才需要收紧到 1e-3 或 1e-4。
  • 统一数量级。这个问题我在项目里反复遇到。如果你把基准功率设为 10 MVA,负荷和 DG 都在 0.01~0.2 pu 之间,电压约束在 1 附近,支路阻抗在 1e-3 量级,这种数量级对求解器非常友好。反过来,如果谁用了瓦特、欧姆、伏特做单位,数值差几十万倍,求解器的线性松弛和数值分解都会出奇奇怪怪的问题。
  • 删除冗余变量。不要在模型里定义永远用不到的P_DG、Q_DG的全节点变量。虽然稀疏技术能处理,但约束数量多了会让预求解阶段变慢,也容易埋数值隐患。

这里要给一个小提示:连续 SOCP 和 MISOCP 的求解时间差异是天壤之别。如果模型里不需要干选址,就不要轻易引入 0-1 变量;但如果你要说服业主/导师这个节点该不该投资,那 0-1 变量又是不可或缺的。所以建模之前先想清楚,你要的是"容量优化"还是"选址定容",这会直接决定模型复杂度和求解策略。

5. 我踩过的坑和这套模型的扩展方向

5.1 三个能让你少加班的坑

第一个坑:把欧姆当标幺用。这个前面已经提过,但我还是想再敲一遍黑板。配电网优化里所有参数必须统一成 pu 值才能进求解器。电压幅值平方 U 默认基准是 1 pu,带进去的电压约束是 0.9025~1.1025(0.95^2 和 1.05^2),如果忘了平方,电压就会约束错位。见到电压曲线全部顶在上限附近的,先查电压约束写的到底是不是平方值。

第二个坑:YALMIP 版本太老导致 cone() 识别异常。老版本 YALMIP 对锥约束的预处理能力有限,某些情况下会直接把锥约束展开成大量线性约束,白白牺牲性能。做事之前先跑一次yalmiptest,确认 YALMIP 能正确识别你写的cone(),再去开 boss 求解器。

第三个坑:松弛不紧时强制用结果做决策。虽然辐射网、网损最小目标下松弛几乎总是紧的,但当你加了小时级时序、储能充放电、响应型负荷之类的新约束后,二阶锥松弛可能在某些时段出现明显间隙。这时候结果会偏乐观,不适合直接出方案。我的习惯是:求解完用 MATPOWER 或牛顿法做一次精确潮流校核,看看锥间隙是否造成实际误差。如果误差超过 1%,我会考虑加入割平面或者改用更严格的多边形近似。

5.2 从静态规划走向更真实的场景

这篇文章里跑的是单时段静态优化。实际工程里,DG 出力是随时间变化的,负荷也有日曲线、季节差异,所以往"多时段"扩展几乎是必然的。扩展方法很直接:把每时刻的负荷作为一组场景,模型里给每条支路、每个节点增加时间维度变量;目标函数改成全时段网损之和。代价是变量数和约束数随周期数量线性增长。这时候前面的"限制候选节点"和"MIPGap 放宽"这两个技巧就变得非常重要。更进一步,还可以用 K-means 或场景削减方法,把 8760 小时的曲线压缩成十几个典型日,解算速度和精度的平衡会好很多。

从模型能力上说,还可以把储能、无功补偿装置、联络开关(配网重构)一并纳入,形成一个包含连续和整数变量的混合整数规划大模型。只要核心的 DistFlow 锥松弛不变,描述储能 SOC 递推的线性约束,描述开关状态的 0-1 变量,都是往现有框架里"加菜"的事。这也是我推荐大家把二阶锥这套方法学扎实的原因——它是配电网优化里的底层基础设施,学会一次,后面几乎所有规划问题都能套同一个 YALMIP 框架。

最后分享一个我自己坚持了很久的习惯:任何优化程序,跑完都必须做一次"基准模型复算"。就是先把 DG 全部设成 0,用同一个 YALMIP 框架解一个没有 DG 的纯网络模型,和 MATPOWER 的精确潮流对比,对不上就说明建模环节有问题,而不是求解器有问题。这是个笨方法,但真的能帮你避开 90% 的模型错误。配电网优化程序写得再快再好,前提都是模型本身站得住脚。

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

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

立即咨询