做配电网优化这块的,迟早会碰到一个组合:含SOP的配电网重构。你下载了一篇论文的代码,发现对方用yalmip写得飞起,自己一跑就报错;你搜“二阶锥”,搜出来一堆数学推导,看懂了也觉得离代码十万八千里;你把模型好不容易塞进求解器,又发现要么松弛不紧,要么解出个孤岛网络。我当年第一次把SOP加进重构模型,光是“为什么这个约束要写成锥而不是直接平方”就卡了三天。这篇就专门把这件事讲透:配网重构、SOP、yalmip、二阶锥这四样东西是怎么拧成一股绳的,以及每一步代码和建模到底该怎么写。
先说清楚这是给谁看的。如果你在写电力系统方向的毕业论文、做配电网降损或DG消纳相关研究,或者刚接手一个含柔性互联装置的配电网优化课题,这篇文章可以帮你省掉大量的试错时间。我会从问题本身一路讲到yalmip代码实现,再到最常见的报错和修复方法,尽量让新手能直接“抄作业”,也让有基础的人能把一些“知其然不知其所以然”的地方补齐。
1. 含SOP配电网重构:你真正要解的模型长什么样
很多初学者立项之后第一件事就是找代码,然后发现代码看不懂。问题的根源不是代码写得差,而是你还没搞明白这个模型从上到下到底在设计什么。所以我先不碰代码,把物理问题拆给你看。
1.1 SOP到底是个什么设备
在配电网领域,SOP的全称是Soft Open Point,智能软开关,不是你在质量管理课上背的那种Standard Operating Procedure。这个区分在搜索资料的时候尤其重要,不然你查半天全是在讲作业指导书。
SOP本质上是一台电力电子装置,最常见的拓扑是背靠背的双向变流器,一个交流端口接在配电网的A点,另一个端口接在B点,中间是直流母线。它接的位置,通常是传统配电网里那些长期断开的联络开关处。普通联络开关只有两个状态:闭合或断开。闭合之后,两个馈线变成一个网络,潮流按阻抗自然分布;断开之后,两边彻底隔离。SOP不一样的地方在于,它让两端的功率可以连续调节,而且两端还能独立发出或吸收无功。
打个比方:联络开关像一扇门,要么开要么关;SOP像一扇带阀门的水闸,不但能控制水的流量,还能控制水流过时对两侧水位的影响。正是因为这种连续可控性,SOP被大量用在含有分布式电源、高负荷波动的配电系统里。
1.2 重构与SOP为什么要联合优化
配电网重构优化的是什么?简单说,就是通过调整分段开关和联络开关的开合状态,改变网络拓扑,找到网损最小、电压最稳或者负荷最均衡的运行方式。经典重构问题里,决策变量是每一组开关的0-1状态,目标函数通常是网损,约束条件包含潮流方程、节点电压上下限、支路电流上限,以及一条非常重要的“辐射状拓扑约束”。
如果你只是做纯重构,那问题是一堆0-1变量加非凸潮流,已经不好解了。但加上SOP之后,事情又多了一个维度:SOP两端接在哪个节点,它的有功传输和无功补偿怎么分配,又要满足哪些容量限制?
这里有一个关键认知:重构改变的是“网络骨架”,SOP改变的是“注入功率分布”。这两件事不是独立的,而是强耦合的。SOP传输的有功功率会改变线路潮流,进而影响最优开关组合;反过来,不同开关组合决定了SOP两端所处的电气位置,同一个SOP在不同拓扑下的调压降损效果可能天差地别。
所以你必须把SOP的连续决策变量和开关的0-1决策变量放进同一个优化模型里同时求解,而不是先做一次重构、再在固定拓扑下优化SOP。顺序求解速度是快,但结果很可能是次优的。联合优化的解,一般能比顺序优化多压掉不少网损,这也是论文里强调“SOP与重构协同”的根本原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 非凸问题怎么解:二阶锥松弛的来龙去脉
任何配电网优化问题,绕不开的拦路虎就是潮流方程。而这一节要讲的二阶锥松弛,就是驯服这头猛虎的主流工具。你别被“二阶锥”这个名字吓着,它的思路其实特别朴素:把一个难搞的非凸等式,放成一个好搞的凸不等式。
2.1 DistFlow方程里那个最麻烦的非线性项
配电网潮流计算,最常用的方程是DistFlow模型。它的形式有很多种,但核心就几点:有功平衡、无功平衡、电压降方程,还有一个反映电流平方与功率关系的等式。写成最直观的形式,大概是这样的:
对于支路ij,首端是i,末端是j,有功和无功分别为P_ij和Q_ij,电流幅值平方I_ij^2,电压幅值平方V_i^2和V_j^2,支路电阻电抗R_ij和X_ij。潮流方程里有这么一条:
I_ij^2 = (P_ij^2 + Q_ij^2) / V_i^2
这个等式的麻烦在于,P_ij、Q_ij、V_i都是变量,分子是非凸的二次项,分母又有电压变量,整个等式构成的可行域是完全非凸的。如果你直接把这条约束丢给求解器,求解器一点办法都没有,因为它不是线性规划,也不是二次规划,而是一个混合整数非凸非线性问题。在大规模网络上,这种问题理论上很难求到全局最优。
2.2 三步完成二阶锥松弛:换元、放缩、转形式
解决思路分三步。第一步是换元。既然I_ij^2和V_i^2总是成对出现,那干脆把它们各自定义成一个新变量,比如用l_ij表示I_ij^2,用u_i表示V_i^2。这样电压降方程里的二次项就直接线性化了,状态空间里少了一堆二次项,这是换元的核心收益。
第二步是处理那个最扎手的约束。原来的等式是:
l_ij * u_i = P_ij^2 + Q_ij^2
这是一个等式,两边相乘,非凸。现在把它放缩成一个不等式:
l_ij * u_i >= P_ij^2 + Q_ij^2
看到这里你可能会担心:把等式变成大于等于,解出来的还是原来的问题吗?这就是二阶锥松弛的全部秘密所在。松弛本身不会收紧解的可行域,反而会扩大可行域,所以求解出来的目标值是原问题的下界。后面我会专门讲怎么判断松弛是不是“紧”的。
第三步是转成标准二阶锥形式。上面这个不等式虽然看着简单,但直接丢给求解器还是不行,需要改写成求解器认识的格式。标准二阶锥约束是范数小于等于某个线性表达式的形式:
|| [2P_ij; 2Q_ij; u_i - l_ij] ||_2 <= u_i + l_ij
你把两边同时平方展开,会发现它正好等价于u_i*l_ij >= P_ij^2 + Q_ij^2。这就是为什么说二阶锥是DistFlow松弛的天然形式:旋转锥在代数上被等价换成了标准锥,求解器可以直接处理。
2.3 松弛是否精确:求解之后必须检查的一件事
二阶锥松弛理论上只是给原问题提供了一个下界,不是严格等价。但在大多数配电网重构场景里,只要目标函数是网损最小化,SOP容量不卡得过死,松弛通常会自然收紧到等号。原因是目标函数里希望电流平方l_ij尽量小,而锥约束又要求l_ij不能太小,两股力量一挤,解就会落在锥边界上。
但“通常”不等于“一定”。我在实际跑IEEE 33节点和IEEE 123节点算例的时候,都遇到过个别支路的松弛间隙偏大的情况。所以求解完之后,必须做一步校验:取最优解,逐条支路计算松弛间隙,也就是对比l_ij * u_i和P_ij^2 + Q_ij^2之间的差值。如果所有支路的最大间隙在10^-5这个量级以下,那你可以放心说这个解是可信的;如果间隙达到10^-2甚至更大,说明松弛过松,当前解不能直接用。
需要我提醒你的是:论文里常写“二阶锥松弛是精确的”,这句话是有前提条件的。不要一看到精确两个字,就把校验这一步省了。校验代码就几行,却能避免你拿着一个物理上不可实现的方案去汇报。
3. 建模仿真工具选型:yalmip和求解器怎么搭
工具选型这个环节,很多初学者不重视,直接下个MATLAB就开始写,结果卡在安装、license、求解器调用这些地方一整天。这一节把工具链讲清楚。
3.1 为什么建模几乎都用yalmip
你如果去看配电网优化方向的论文,作者使用的建模工具十有八九是yalmip。这不是偶然,而是因为yalmip做了一件事:把建模和求解器彻底解耦。你只需要用MATLAB定义决策变量、目标函数和约束,剩下的事情交给yalmip完成。想换求解器的时候,改一行参数就行,不用重写模型。
举个例子,你用一块“0-1变量 + 连续变量 + 二阶锥约束”的模型,如果手写求解器接口,你需要自己去弄清楚某个求解器接受的标准格式,然后手工把约束矩阵一行行拼出来。这个过程极其痛苦,改一个变量维度就要改一大堆索引。yalmip里用binvar定义开关变量,用sdpvar定义连续变量,约束写着非常接近数学公式的表达,模型可读性和调试效率能高出一个量级。
另外,yalmip对二阶锥有天然支持。你不需要手动把锥约束转化成求解器的C++接口格式,直接在约束里写norm(...,2) <= 表达式,yalmip会自动识别并传递给求解器。这一个特性对配电网研究来说几乎是决定性的。
3.2 求解器选型与yalmip安装配置全流程
yalmip本身不是求解器,它只是一个建模层,真正求解还需要一个底层求解器。配电网重构加SOP这个场景,模型属于混合整数二阶锥规划(MISOCP),能用到的求解器主要是Gurobi和CPLEX这两家。它们在学术界都有免费授权,申请流程不复杂,用学校的教育邮箱基本都能下来。
安装方面,我做一份可以直接照做的清单:
- 下载yalmip,解压后放到一个固定目录,比如D:\yalmip。
- 在MATLAB里执行addpath(genpath('D:\yalmip')),然后用savepath保存路径,这样重启MATLAB之后不用重复添加。
- 单独安装求解器。以Gurobi为例,安装后要在MATLAB里运行gurobi_setup,让MATLAB能找到Gurobi的可执行文件。
- 在yalmip中执行yalmiptest,如果所有测试项都通过,说明环境OK。这一步能帮你提前发现版本不兼容的问题。
有一个点要特别说:Gurobi的版本和MATLAB版本以及yalmip版本三者之间存在兼容性问题。新版Gurobi要求MATLAB R2020a以上,旧版yalmip也可能不识别某些新求解器的参数。如果你装完出现“Solver not found”或者“Unable to create Gurobi environment”,先别急着怀疑代码,优先检查版本组合。
3.3 求解器参数设置:常用但常被忽略的两个选项
求解器装好只是第一步,参数设置才是拉开求解效率差距的关键。这里我只强调两个最常用的,其他的等你跑大算例再慢慢研究。
第一个是时间限制。MISOCP问题本质上是分支定界,最坏情况下计算量可以爆炸。你在调模型的时候,不想等一个小时才知道当前参数组合行不行,所以一定要设置时间上限,比如在optimize调用里加上sdpsettings('solver','gurobi','gurobi.TimeLimit',600),让求解器最多跑10分钟,时间到了就返回当前最优解。这样你能在可控时间内调整模型。
第二个是整数间隙容忍度。分支定界算法会不断收紧上下界,当上下界之间的百分比间隙小于某个阈值时,求解器认为已经求到最优,提前终止。默认值一般是10^-4,很严格。如果你发现求解时间过长,而且也不需要那么精确,可以把整数间隙放宽到10^-2甚至10^-1,速度经常能快几倍。
4. 完整建模实操:目标函数与约束逐个落地
工具链没问题了,现在进入正题:含SOP配电网重构的完整模型长什么样。我会按目标函数、潮流约束、SOP约束、拓扑约束四个模块逐条讲清楚,并解释每一条约束为什么这么写。
4.1 目标函数:网损最小化
配电网重构最常见的优化目标是有功网损最小。在DistFlow模型里,支路ij的有功损耗等于R_ij * I_ij^2。做了换元之后,就是R_ij * l_ij。所以目标函数是所有支路损耗求和:
min sum(R_ij * l_ij)
这里有个细节:为什么目标函数里没有直接写SOP的损耗?因为很多研究在建模阶段忽略SOP自身的损耗,把它当作理想变换器。如果考虑SOP损耗,通常的做法是在目标函数里加一个线性项,比如k1*(P_sop1的绝对值) + k2*(P_sop2的绝对值)。但绝对值在优化里不够友好,需要引入辅助变量线性化,这里不展开。建议初学阶段先用无损耗模型,把主线跑通,再考虑扩展。
你可能还会看到一些论文在目标函数里加电压偏差项,或者加开关操作代价项。这些都可以在网损最小化的基础上叠加。但需要注意的是:多目标项的权重怎么设,会直接影响解的性质。如果不是课题要求,我建议第一版始终以网损最小化为唯一目标,这样结果干净,好分析。
4.2 潮流约束与二阶锥表达
潮流约束是整个模型的主体。对每条支路,需要写电压降方程、功率平衡方程和二阶锥约束三部分。
电压降方程在换元之后形如:
u_j = u_i - 2(R_ij * P_ij + X_ij * Q_ij) + (R_ij^2 + X_ij^2) * l_ij
注意这里u_i和u_j分别表示节点i和j的电压幅值平方。这条约束在辐射状网络和环网里都适用,因为它是基尔霍夫电压定律的直接代数表达。
功率平衡方程则要按节点来写。对每个节点n,所有从该节点流出的支路有功之和,加上所有从其他节点流入该节点的支路有功(扣除线路损耗),再加上该节点的外部注入功率,总代数和为0。外部注入功率等于发电机出力减去负荷,再加SOP注入。在实际代码里,这部分是最容易出错的,因为支路潮流方向的定义如果不统一,正负号很容易搞反。
二阶锥约束就是前面写的标准形式:
|| [2P_ij; 2Q_ij; u_i - l_ij] ||_2 <= u_i + l_ij
在yalmip里可以直接写成:
code复制Cons = [Cons, norm([2*P(k); 2*Q(k); u(frm(k)) - l(k)], 2) <= u(frm(k)) + l(k)];
这里frm(k)表示支路k的首端节点编号。这条约束的作用是通过变量之间的关系,把电流平方、功率和电压天然地扣在一起。
还有一个避坑点:l_ij必须是连续非负变量,并且要设置上限。如果不设上限,big-M约束会失去意义。一般可以取线路电流最大值的平方,乘以一个1.2的安全系数,作为l_ij的上限。
4.3 SOP运行约束怎么写
SOP的模型可以拆成三块:有功耦合约束、无功调节范围、容量限制。
有功耦合约束是最基本的一条:两端有功功率之和为0。也就是说,一端从电网吸收多少有功,另一端就往电网注入多少有功:
P_sop1 + P_sop2 = 0
如果考虑SOP损耗,这个等式右边就不是0,而是损耗项。但上面说了,初学先忽略。
无功调节指的是SOP两端可以独立补偿无功。补偿能力受容量限制,每一端都有各自的容量圆约束:
P_sop1^2 + Q_sop1^2 <= S_sop^2
P_sop2^2 + Q_sop2^2 <= S_sop^2
这两个约束本身是二次的,但因为是“圆内可行”,天然是凸的。在yalmip里可以直接写成cone形式:
code复制Cons = [Cons, cone([P_sop1; Q_sop1], S_sop)];
Cons = [Cons, cone([P_sop2; Q_sop2], S_sop)];
这里cone(x, y)表示||x||_2 <= y。yalmip会自动识别成二阶锥约束。注意,这两条约束不需要做任何近似,因为它本来就是凸约束。
节点功率平衡方程里也要加入SOP项。假设SOP两端分别接在节点p和节点q,那么在节点p的注入功率里要加上P_sop1和Q_sop1,在节点q的注入功率里要加上P_sop2和Q_sop2。并注意方向:一般定义SOP向所连节点注入功率为正。
4.4 开关状态与辐射状拓扑约束
配电网正常运行要求网络必须是辐射状的,也就是无环且连通。这是重构问题里最容易被“想当然”的部分。
先说最直接的约束:每条支路都有0-1状态变量z_ij,支路断开时功率强制为0,闭合时可以传输功率。这种强制关系用big-M实现:
-M * z_ij <= P_ij <= M * z_ij
-M * z_ij <= Q_ij <= M * z_ij
0 <= l_ij <= L_max * z_ij
big-M的选取很有讲究。M如果取得太大,数值稳定性差,求解器容易陷入无意义的解;M如果取太小,可能会削掉可行域。M一般取该支路允许流过的最大功率的1.1倍左右,不要全网络统一用一个夸张的大数。
然后是辐射状约束。很多初学者只写了闭合支路数量等于节点数减一,也就是sum(z) = N-1。这条约束是必要条件,但不充分。为什么?因为可能同时出现一个环和一个孤岛,环上支路数多一条,孤岛上支路数少一条,数量上依然满足N-1,但网络并不是辐射状连通网络。
解决办法有很多,我推荐虚拟潮流法,也叫单商品流法。具体做法是:给每条支路额外定义一个虚拟潮流变量f_ij,它只用来验证拓扑连通性,和真实电力潮流无关。根节点产生N-1的虚拟流量,其余每个节点消耗1的虚拟流量。每条支路只有在闭合时才能传输虚拟潮流:
-M_flow * z_ij <= f_ij <= M_flow * z_ij
然后写节点虚拟流量平衡:对每个节点,流入该节点的虚拟流量减去流出该节点的虚拟流量,等于一个常数。根节点是N-1,其他节点是-1。这样一组约束就能同时保证连通性和无环性。M_flow这里可以取节点数N,因为虚拟流量最大值就是N-1,取N绰绰有余且数值友好。
这个方法初看有点绕,但它在代码里的实现非常方便,而且求解器处理线性约束比处理别的连通性约束要舒服得多。你如果去看高水平论文,这种方法也是主流。
5. MATLAB核心代码与求解闭环
模型讲完,这一节我把上面所有内容落到一段可运行的伪代码里。我不追求这一段代码直接跑通所有算例,但它的结构和关键约束写法,可以移植到你的项目里。
5.1 变量声明与数据结构设计
第一步是准备网络参数。建议直接调用MATLAB的matpower格式数据,比如case33bw就是IEEE 33节点的标准算例。你需要把支路首末端节点、电阻、电抗分别提取出来:
code复制mpc = loadcase('case33bw');
branch = mpc.branch;
N = size(mpc.bus, 1);
E = size(branch, 1);
frm = branch(:, 1);
to = branch(:, 2);
R = branch(:, 3);
X = branch(:, 4);
决策变量分三类:开关状态用binvar,潮流连续变量用sdpvar,SOP变量单独定义:
code复制z = binvar(E, 1); % 支路开关状态,1闭合,0断开
P = sdpvar(E, 1, 'full'); % 支路有功,参考方向为frm->to
Q = sdpvar(E, 1, 'full'); % 支路无功
l = sdpvar(E, 1, 'full'); % 支路电流平方
u = sdpvar(N, 1); % 节点电压平方
f = sdpvar(E, 1, 'full'); % 虚拟潮流
P_sop = sdpvar(2, 1, 'full'); % SOP两端有功
Q_sop = sdpvar(2, 1, 'full'); % SOP两端无功
值得说明的是,u这个变量我默认上限是1.1的平方,下限是0.9的平方,也就是电压幅值允许在0.9到1.1之间波动。这是配电网的常规约束。
5.2 约束装配:从节点平衡到锥约束
先把约束集合初始化,再逐块往里面加。
电压与电流约束:
code复制Cons = [];
Cons = [Cons, u(1) == 1.0]; % 根节点电压固定为1.0
for k = 1:E
Cons = [Cons, 0 <= l(k) <= L_max * z(k)];
Cons = [Cons, -M * z(k) <= P(k) <= M * z(k)];
Cons = [Cons, -M * z(k) <= Q(k) <= M * z(k)];
Cons = [Cons, u(to(k)) == u(frm(k)) - 2*(R(k)*P(k) + X(k)*Q(k)) + (R(k)^2 + X(k)^2)*l(k)];
Cons = [Cons, norm([2*P(k); 2*Q(k); u(frm(k)) - l(k)], 2) <= u(frm(k)) + l(k)];
end
节点功率平衡需要构造节点-支路关联关系。用一个循环来写最直观:
code复制Pd = mpc.bus(:, 3) / Sbase; % 有功负荷标幺值
Qd = mpc.bus(:, 4) / Sbase; % 无功负荷标幺值
for n = 1:N
out_idx = find(frm == n);
in_idx = find(to == n);
p_bal = sum(P(out_idx)) + sum(P(in_idx) - R(in_idx) .* l(in_idx));
q_bal = sum(Q(out_idx)) + sum(Q(in_idx) - X(in_idx) .* l(in_idx));
p_inj = -Pd(n) + P_sop_inj(n);
q_inj = -Qd(n) + Q_sop_inj(n);
Cons = [Cons, p_bal == p_inj];
Cons = [Cons, q_bal == q_inj];
end
注意这里P_sop_inj是一个长度为N的向量,只在SOP所连节点处有值,其余位置为0。更稳妥的写法是直接用P_sop1、P_sop2通过索引赋值到对应节点。
辐射状约束用虚拟潮流法:
code复制for n = 1:N
out_idx = find(frm == n);
in_idx = find(to == n);
if n == root
Cons = [Cons, sum(f(out_idx)) - sum(f(in_idx)) == N - 1];
else
Cons = [Cons, sum(f(out_idx)) - sum(f(in_idx)) == -1];
end
end
for k = 1:E
Cons = [Cons, -N * z(k) <= f(k) <= N * z(k)];
end
SOP约束:
code复制S_sop = 0.5; % SOP容量,标幺值
Cons = [Cons, P_sop(1) + P_sop(2) == 0];
Cons = [Cons, cone([P_sop(1); Q_sop(1)], S_sop)];
Cons = [Cons, cone([P_sop(2); Q_sop(2)], S_sop)];
目标函数:
code复制obj = sum(R .* l);
最后求解:
code复制ops = sdpsettings('solver', 'gurobi', 'verbose', 2, 'gurobi.TimeLimit', 600);
diagnostics = optimize(Cons, obj, ops);
5.3 求解结果处理与网络体检
求解完成后,第一件事不是看目标函数值,而是检查diagnostics.problem是否为0。如果不是0,说明求解过程有问题,需要根据返回码排查。
目标函数值直接用value(obj)得到。但更关键的是对结果做一套“体检”,我每次跑完算例都做三件事:
第一,检查每条支路的松弛间隙。逐条计算value(l) * value(u(frm))和value(P)^2 + value(Q)^2的差值,看是否在10^-5量级以内。
第二,检查电压是否越限。把value(u)开根号,看最小值和最大值是否在0.9到1.1的范围内。
第三,检查重构后的拓扑。用value(z)大于0.5的支路生成一个图对象,用MATLAB的graph和conncomp函数检查连通分量个数,必须是1,并且支路数必须是N-1。这一步能直接抓出孤岛或环网问题。
6. 常见问题与排查技巧实录
下面这些坑,都是我实打实踩过的。有些问题你查手册查不到,只有跑过一遍才会遇见。
6.1 模型报不可行:先查辐射状约束和节点平衡
碰到infeasible problem,大多数人的第一反应是怀疑二阶锥约束或者big-M有问题,但其实最常出问题的是辐射状约束和节点功率平衡。
虚拟潮流法看起来简单,但符号方向很容易错。我建议你单独把辐射状约束提取出来,假设所有支路都闭合,只跑这个约束,看能不能得到可行解。如果这样都不可行,那肯定是约束写错了。
节点功率平衡另一个常见问题是SOP注入方向搞反。SOP两端注入功率定义为正时,如果代码里把一端加成正、另一端加成负,在忽略损耗的前提下,目标函数会逼着这一个虚拟的功率对来回复制能量,看起来能解,但网损会虚高。排查方法也很简单:把SOP容量设成0再跑一次,如果结果和纯重构一致,说明SOP模型没问题;如果不一致,查注入方向。
6.2 求解很慢:big-M取值与对称性破坏
含0-1变量的二阶锥问题求解慢,几乎是必然的,但慢到什么程度,和big-M的取值关系非常大。我见过有人全网络统一M=10000,结果求解器在各种分支上瞎搜索,一小时不出结果。把M改成对应支路额定功率的1.1倍左右之后,几分钟就收敛了。
另外,如果你的网络里有多个可以开断的联络开关,而且它们在电气位置上是对称的,求解器的分支定界可能会反复搜索对称分支。这时候可以增加一些破坏对称性的约束,比如限制“闭合的联络开关数量不超过某个上限”,或者给联络开关设置优先级。这属于进阶技巧,但在大算例里非常管用。
6.3 二阶锥松弛不紧:怎么判断和补救
前面说过,二阶锥松弛需要事后校验。如果某条支路松弛间隙偏大,常见的补救办法有两个。
第一个办法是在目标函数里加一个很小的惩罚项,比如:
sum(R .* l) + epsilon * sum(l)
epsilon取10^-4或者更小。这个小惩罚会促使l尽量小,把解往锥边界上推,同时不影响主目标的量级。第二个办法是削减该支路的L_max,也就是把l的上限定得更紧,但前提是你确认这条支路确实不会过载。
6.4 yalmip常见报错翻译:从入门到熟练
我遇到最多的一类yalmip报错是“No suitable solver for the model class”。这句话翻译过来就是:你的模型里含有yalmip解决不了的约束类型,或者你没有安装支持该类型的求解器。排查思路是,模型是MISOCP,首先确认求解器选了Gurobi或CPLEX,其次确认这些求解器在yalmiptest中是通过的。
另一个高频问题是“Numeric problems”。这种报错通常不是模型逻辑错误,而是数值问题,根源多半是big-M太大,或者变量量纲不一致。我建议整个模型统一用标幺值,电压基准选10kV的话把电压标幺化,功率基准选1MVA,这样所有决策变量都在0到1的合理范围内,求解器处理起来会舒服很多。
最后还有一个隐蔽问题:复用了全局变量名导致约束被意外覆盖。yalmip的约束是拼接的,如果你在循环里用同一个约束变量名,一定要用Cons = [Cons, ...]这种方式累加,而不是Cons = ...覆盖掉。这个小问题,卡住过不少初次接触yalmip的人。
我个人在实际操作中的体会是,含SOP配电网重构这套东西,最耗时间的不是建模,也不是求解,而是排查那些看起来不合理的结果。每当你拿到一个新算例,先跑一个最简单的场景,比如所有开关保持原始状态、SOP不投运,验证潮流本身是正确的,再去逐步加上拓扑优化和SOP优化。这种“由简到繁”的调试路线,能帮你把模型里的每一个模块都验证干净,最后合到一起的时候才不会翻车。还有一个小技巧想分享给后来者:做IEEE 33节点这种经典算例时,记得先找一篇公开的复现结果,把你自己的输出和目标值做对比。如果数值对不上,优先检查基准值和标幺化,这一项错了一切都白搭。
