光伏渗透率一上来,配电运维群里关于电压越限的报修单肉眼可见地变多了——中午轻载时末端电压冲高,傍晚负荷上来电压又往下掉。过去处理电压问题的方式无非是调有载分接开关、投切电容器,但这里面的代价越来越大。最近我在做含储能及SOP(Soft Open Point,柔性开断点)的多时段配网优化模型,用Matlab实现了主动配电网的电压与无功功率协调控制,也就是标题里那套东西。这篇就把从模型搭建到代码落地的完整过程捋一遍,包括储能SOC约束怎么处理、SOP的功率注入建模怎么下笔、求解器怎么配置,以及我实际跑算例时踩过的一些坑。如果你正在做配电网优化方向的研究,或者刚接触主动配电网、拿着代码对着变量名发懵,这篇应该能帮你省下不少时间。
先说明一下模型定位:这是一个多时段(典型24时段或96时段)的日前优化调度模型,控制对象主要是SOP两端的有功/无功功率和储能充放电功率,目标是在满足潮流和安全约束的前提下,让全天网损和电压偏差尽量小。模型建好后,核心就是一个二阶梯锥规划(SOCP)问题,用Matlab里常用的Yalmip工具箱加商业求解器直接解。下面按我实际动手的顺序来拆解。
1. 传统配电网调压手段为什么越来越吃力
1.1 分布式光伏给配电网带来的“双向难题”
传统配电网是放射状单向潮流结构,功率从变电站母线流向末端负荷,节点电压沿着馈线一路降低。过去调压逻辑很简单:保证首端电压不低,末端电压就别想低到哪去,再用台区无功补偿补一补,问题不大。
分布式光伏大规模接入后,这个逻辑彻底变了。晴朗天中午恰恰是负荷低谷,光伏出力却达到峰值,馈线末端出现有功倒送,末端电压反而比首端还高。到了傍晚,光伏出力断崖式下跌,负荷高峰到来,末端电压又快速下探。一天之内,同一根馈线要面对两个方向相反的电压问题——白天压上限,晚上托下限。这种“双向电压问题”恰恰是传统调压手段最不擅长的。
更麻烦的是,很多分布式逆变器长期按功率因数1运行,不参与无功调节。你让它发一点无功,它就直接减有功出力,发电量受损。这时候“主动配电网”的理念就出来了:与其被动等电压越限再补救,不如在网络层主动调节功率流动——这就是SOP这类柔性设备登场的背景。
1.2 传统电压调节手段的“单点调节”天花板
到具体设备层面,配电网里能调电压的也就那几样:有载调压变压器(OLTC)、并联电容器、SVG/STATCOM。每样都有它的价值,但也都有明显的天花板:
| 设备 | 调节方式 | 优势 | 固有局限 |
|---|---|---|---|
| OLTC | 分接头离散/连续 | 调压范围大 | 动作次数受限、响应慢、不改变馈线间潮流分布 |
| 并联电容器 | 分组投切 | 成本低、易维护 | 只能离散调节、只能发容性无功,电压高时反而帮倒忙 |
| SVG/STATCOM | 连续无功调节 | 响应快、双向无功 | 通常装在变电站侧,无法实现馈线间的有功转供 |
这些设备的共同问题是:只能在“单点”上做文章,解决不了“空间错配”——也就是A馈线光伏大发功率用不完,B馈线却是重负荷等着功率支援的情况。配电网长期是闭环设计、开环运行,联络开关常年断开,两条馈线之间的功率支援能力被这个物理断点硬生生切掉了。要让断开点变成可控的功率通道,就需要SOP这种电力电子设备来接管。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SOP到底是个什么设备:从二值开关到连续功率端口
2.1 背靠背换流器:配电网里的“功率路由器”
SOP的全称是Soft Open Point,柔性开断点。它安装在传统联络开关的位置,但内部是背靠背的电压源型换流器(VSC),直流侧用电容耦合,交流侧分别接两条馈线。从外部看,它就是一个两端口的功率控制设备。
它比传统联络开关强在哪?传统联络开关只有两个状态:合上或者断开,操作一次需要倒闸流程,分钟级起步,而且合环还会带来短路电流和保护配合问题。SOP则相当于在两条馈线之间装了一个“功率路由器”:有功功率可以从A馈线连续平缓地流向B馈线,也可以反向流动,而且两端的无功功率互不干扰、独立调节。响应速度在毫秒级,一台设备同时起到了潮流控制和电压支撑两个作用。
关键一点:SOP不是把两个馈线直接短接,而是通过直流环节隔离。一侧馈线发生故障时,另一侧几乎不受影响,这对保护整定非常友好,也为故障后快速恢复供电提供了可能。
2.2 潮流模型里的SOP等效注入与容量约束
在配电网潮流模型里,我不需要关心换流器内部IGBT怎么触发,只需要把SOP等效成两个节点上的可控功率注入。以双端SOP为例,设两个端口分别接入节点i和节点j:
- 有功功率平衡(不计损耗时):
P_SOP,i + P_SOP,j = 0 - 各端口容量约束:
P_SOP,i² + Q_SOP,i² ≤ S_SOP,i²,P_SOP,j² + Q_SOP,j² ≤ S_SOP,j²
这套模型简洁、凸、好求解,是文献里的标准做法。方向约定建议统一为“流入节点为正”,我在代码里也是这么写的。如果实际想考虑换流器损耗,可以在功率平衡里加一个损耗项,但在日前优化阶段一般先忽略,重点看电压和网损的优化效果。
容量约束为什么用圆而不是矩形?因为换流器的视在功率限制决定了有功和无功之间存在耦合,强行拆成矩形可行域会高估它的调节能力,优化结果在工程上不可执行。
2.3 三端与多端SOP的建模扩展
很多场景下双端SOP还不够用,比如一个核心供电区有三条馈线交汇,这时候可以做三端SOP甚至多端SOP。模型上只是变成多个功率注入端口:每个端口都有各自的容量圆约束,端口之间用总功率平衡约束关联,Σ P_SOP,k = 0。多端SOP的本质是多端直流系统,各端电压等级可以不同,控制自由度更高,但优化模型的结构和双端几乎一样,只是变量数量增多。代码里把端口数定义成矩阵的维度就行,不需要另起炉灶。
3. 多时段优化模型的搭建:目标函数、约束条件与时间耦合
3.1 为什么必须做多时段而不是单时段
如果有人问“我只做一个断面的优化行不行”,答案很直接:不行。原因有两点:
第一,光伏出力和负荷的时序性强,单时段只能看到某个时刻的局部情况。同样的SOP功率指令,在上午和傍晚的最优方向完全可能相反;单时段优化没有全局视野,算出来的结果很可能在下一个时段就需要大幅调整。
第二,储能是天然的时间耦合设备。SOC是跨时段变量,单时段模型里储能根本没有意义——你不知道它之前充了多少、之后该放多少。多时段模型用一整天的联立优化,才可能把“低谷充电、高峰放电”这种能量搬移行为自然刻画出来。
时段粒度方面,我建议先用24时段(每小时一个点)调试模型逻辑,跑通后再切换到96时段(15分钟一个点)贴近工程调度习惯。96时段对求解器内存和变量规模的要求会明显上升,新手直接上96时段,出了问题很难排查。
3.2 目标函数:全天网损最小加电压偏差惩罚
我采用的目标函数是全天各时段网损之和,再加上节点电压相对参考值的平方偏差惩罚:
code复制min F = Σ_t [ Σ_(i,j) R_ij · I_ij,t² + λ · Σ_i (V_i,t − V_ref)² ] · Δt
如果只写网损最小这一项,会有一个问题:优化器只关心降低损耗,对“电压在限值内但已经很接近边界”这种状态毫无感知。加入电压偏差惩罚项后,模型会自动把电压往参考值附近拉,结果更贴近工程实际。λ的取值需要做灵敏度分析,因为网损单位是kW,电压偏差单位是pu²,量纲完全不同,λ取0.1还是100,结果差异会非常大。
如果需要考虑运行经济性,还可以在目标里加入从上级电网购电的费用项。但注意:引入购电成本后,储能“低价充、高价放”的行为会变得更加激进,这时候必须确保充放电互斥约束写对了,否则模型可能出现既充电又放电的套利怪象。
3.3 潮流约束:DistFlow方程与二阶锥变换
配电网是放射状网络,节点数多、环网少,直接用全量交流潮流建模既慢又容易不收敛。更合适的方式是采用DistFlow分支潮流方程。定义变量时一律用“平方量”:V_i²、I_ij²,这样方程可以写成线性形式:
节点功率平衡:
code复制Σ_(j,i) P_ji − Σ_(i,k) P_ik = P_load,i − P_pv,i − P_SOP,i − P_ESS,i
Σ_(j,i) Q_ji − Σ_(i,k) Q_ik = Q_load,i − Q_pv,i − Q_SOP,i
支路电压降落方程:
code复制V_i² − V_j² = 2(r_ij·P_ij + x_ij·Q_ij) − (r_ij² + x_ij²)·I_ij²
支路电流定义方程:
code复制I_ij² = (P_ij² + Q_ij²) / V_i²
这个电流定义方程是等式约束,非凸,直接扔给求解器会报告“nonconvex”。解决办法是做二阶锥松弛,把它放宽为不等式:
code复制‖ [2P_ij; 2Q_ij; V_i² − I_ij²] ‖₂ ≤ V_i² + I_ij²
这本质上是一个旋转二阶锥约束,在Yalmip里写成cone形式。为什么可以松弛?因为目标函数里包含网损,网损最小会推动电流趋向最小可行值,所以最优解处松弛通常取等号。这就是SOCP求解的物理基础。该松弛在辐射状网络、负荷接入合理的条件下被证明是精确的,实际计算中也很少遇到松弛不紧的情况。
3.4 储能约束与SOC递推
储能模型的变量包括充电功率、放电功率和SOC,约束分三层:
第一层是功率边界,充电和放电功率都不能超过额定值。第二层是SOC递推:
code复制SOC(t+1) = SOC(t) + P_ch·η_ch·Δt/E − P_dis·Δt/(η_dis·E)
其中E是额定容量,η_ch和η_dis分别是充放电效率。第三层是SOC上下限,以及初始SOC的设定。
关于“充放电互斥”,常见写法是引入两个二进制变量,分别作为充电和放电的开关,再加u_ch + u_dis ≤ 1。但我个人建议:最初调模型时先别写二进制变量,直接让充电功率和放电功率的数值范围限制在正区间,配合目标函数的网损最小特性,模型会自动避免同时充放——因为一边充一边放纯粹是能量浪费。只有在目标函数里存在电价套利空间、且两阶段电价差极大时,才必须上二进制约束。这个取舍能大幅降低求解难度,尤其96时段下影响更明显。
末端SOC要不要强制回归初始值?学术论文里经常写SOC(T) = SOC(0),这样第二天可以从同样状态继续调度。但工程上如果你是按“某一天的实际运行”来研究的,强制末端SOC等于初值可能导致可行域过窄甚至无解。更合理的做法是把末端SOC放宽到一个范围内(比如0.3~0.7),或者在目标里加一个末端SOC偏离惩罚项。
3.5 SOP约束与网络安全约束
SOP自身的约束前面已经提过,功率平衡加容量圆。如果考虑寿命损耗,还可以加相邻时段功率调节量限制(爬坡约束),但VSC响应速度快到毫秒级,日前调度层基本不受这个限制,可以不加。
系统级安全约束包括:节点电压上下限(用平方量表示为V_min² ≤ V_i² ≤ V_max²)、支路电流上限、根节点与上级电网的交换功率限制,以及光伏逆变器的无功出力范围。这些约束都是线性的,装配起来不费劲。最容易写错的是电压约束——直接用V_sqr >= 0.95是错的,应该是V_sqr >= 0.95^2,因为变量本身已经是电压平方。
4. 储能与SOP的协同逻辑:一个管空间,一个管时间
4.1 两者的分工其实非常清晰
储能和SOP放在一起,很多人第一反应是“设备越多越复杂”,但实际上两者的功能正交性很强。SOP解决的是空间维度的功率转移——A馈线多余的功率通过SOP送到B馈线去;储能解决的是时间维度的能量搬移——中午的光伏电量存起来,晚上再放出来。一个“在空间上搬”,一个“在时间上搬”,配合起来恰好覆盖了配电网协调控制的两个主要维度。
我用一个典型晴天的日运行过程来说清楚它们怎么协作:
- 早晨光伏出力开始爬升,馈线末端电压出现抬升趋势。此时SOP先把一部分有功从光伏馈线转到相邻馈线,同时发出感性无功吸收无功,延缓电压上升。
- 正午光伏达到峰值,这是电压越限最危险的时段。储能切入充电模式,把一部分多余光伏电量吸收掉;SOP继续转供另一部分有功,剩余的调节容量用于无功补偿。两条线一起动作,电压尖峰被明显压平。
- 傍晚负荷高峰、光伏大幅跌落,电压下行压力出现。储能转为放电模式,向馈线注入有功;SOP切换传输方向,把功率从负荷较轻的馈线转送到负荷较重的馈线,必要的时候用剩余容量发容性无功托高电压。
- 夜间低谷时段,储能重新充电,SOP处于轻载状态,为第二天的调节预留空间。
如果把SOP和储能拆开单独用,效果都要打折扣:只有SOP时,光伏功率如果已经超过全网负荷需求,多余的功率只能靠弃光解决;只有储能时,A馈线的功率还是到不了B馈线,局部电压问题依然存在。二者组合后,系统才同时具备“跨馈线调配”和“跨时段搬移”两种能力。
4.2 控制框架:日前优化加日内修正
从控制层级看,我在Matlab里搭建的这个模型属于“日前离线优化”层。它基于次日光伏和负荷预测数据,一次性求解出全天96个时段的SOP功率指令和储能充放电计划,作为运行基准。日内真实运行时,还需要滚动修正层——每隔15分钟或1小时用实测数据重算一次未来时段的计划,以及就地控制层——用SOP本体的P/Q自动控制响应秒级扰动。
这篇文章的模型聚焦日前层,但它给出的正是整个控制链条最关键的“参考值来源”。没有这层优化,后面的实时控制就失去了方向。这也是为什么多时段优化模型在主动配电网研究中始终是核心工具。
5. Matlab建模实现:从数学表达式到能跑的代码
5.1 工具箱与求解器选型
这个模型我用的工具链是Matlab + Yalmip + Mosek,求解器也可以换成Gurobi或Cplex,三者对二阶锥的支持都很好。Yalmip是一个建模层,它让你用自然语言描述优化问题,底层调求解器去解,省去了手写锥约束接口的麻烦。Mosek对SOCP的处理很稳健,报错信息也相对友好;Gurobi的优势在于大模型求解速度,96时段大规模算例时优势更明显。
安装这类工具箱有一个老生常谈但必须强调的坑:所有工具箱和求解器文件务必放在全英文路径下,Matlab工作目录也尽量不要出现中文。求解器dll加载失败、Yalmip识别不到求解器的报错,八成和路径有关。
5.2 算例基础数据准备
算例我选的是IEEE 33节点系统,这是配电网优化领域用得最广泛的测试系统。系统基准电压12.66 kV,基准功率10 MVA,总负荷约3.7 MW左右。原始数据用Matpower或直接从公开论文里提取。我在SOP接入点方面,选择在传统的联络开关位置接入双端SOP;储能则放在光伏接入较多、电压问题较突出的节点附近。
负荷曲线按典型日峰谷特性生成,光伏出力曲线假设为晴天单峰形状,峰值出现在正午。为了避免建模阶段数据细节把人绕晕,建议前几次调试先用简单的正弦型或抛物线型曲线,等模型跑通后再换成实测数据。
5.3 核心代码框架与关键片段
这里给出我在实际调试中使用的代码骨架。注意这是结构示意,跑通版的完整约束装配需要根据网络参数逐条展开,但整体骨架就是这个样子:
matlab复制%% 参数设置
T = 24; % 时段数,调试阶段先用24
nb = 33; % IEEE 33节点系统节点数
nl = 32; % 支路数
dt = 1; % 时段长度,单位小时
eta_ch = 0.95; % 充电效率
eta_dis = 0.95; % 放电效率
E_rated = [0.5; 0.5]; % 储能额定容量,单位MWh
P_bess_max = [0.25; 0.25]; % 储能最大充放电功率,单位MW
S_sop = 0.8; % SOP单端容量,单位MVA
V_ref = 1.0; % 参考电压标幺值
lambda = 10; % 电压偏差惩罚系数,需灵敏度分析
%% 变量定义
V_sqr = sdpvar(nb, T, 'full'); % 节点电压平方
I_sqr = sdpvar(nl, T, 'full'); % 支路电流平方
P_branch = sdpvar(nl, T, 'full'); % 支路有功
Q_branch = sdpvar(nl, T, 'full'); % 支路无功
P_sop = sdpvar(2, T, 'full'); % SOP两端有功注入
Q_sop = sdpvar(2, T, 'full'); % SOP两端无功注入
P_ch = sdpvar(2, T, 'full'); % 储能充电功率
P_dis = sdpvar(2, T, 'full'); % 储能放电功率
SOC = sdpvar(2, T+1, 'full'); % 储能荷电状态
u_ch = binvar(2, T); % 充电标志(可选)
u_dis = binvar(2, T); % 放电标志(可选)
C = [];
obj = 0;
for t = 1:T
% DistFlow支路约束(以支路k连接from,to为例)
% C = [C, V_sqr(from,t) - V_sqr(to,t) == 2*(r(k)*P_branch(k,t) + x(k)*Q_branch(k,t)) ...
% - (r(k)^2 + x(k)^2)*I_sqr(k,t)];
% C = [C, cone([2*P_branch(k,t); 2*Q_branch(k,t); V_sqr(from,t)-I_sqr(k,t)], ...
% V_sqr(from,t)+I_sqr(k,t))];
% SOP功率平衡与容量约束
C = [C, P_sop(1,t) + P_sop(2,t) == 0];
C = [C, P_sop(1,t)^2 + Q_sop(1,t)^2 <= S_sop^2];
C = [C, P_sop(2,t)^2 + Q_sop(2,t)^2 <= S_sop^2];
% 储能SOC递推与边界
C = [C, SOC(:,t+1) == SOC(:,t) + (P_ch(:,t)*eta_ch - P_dis(:,t)/eta_dis)*dt ./ E_rated];
C = [C, SOC(:,t+1) >= 0.2];
C = [C, SOC(:,t+1) <= 0.9];
C = [C, P_ch(:,t) >= 0];
C = [C, P_dis(:,t) >= 0];
% 如果启用充放电互斥(可选)
% C = [C, P_ch(:,t) <= P_bess_max .* u_ch(:,t)];
% C = [C, P_dis(:,t) <= P_bess_max .* u_dis(:,t)];
% C = [C, u_ch(:,t) + u_dis(:,t) <= 1];
% 目标函数累加
obj = obj + sum(I_sqr(:,t) .* R_branch) + lambda * sum((V_sqr(:,t) - V_ref^2).^2);
end
C = [C, SOC(:,1) == 0.5]; % 初始SOC赋值
ops = sdpsettings('solver', 'mosek', 'verbose', 2);
sol = optimize(C, obj, ops);
代码里我故意没写全节点功率平衡约束,因为这部分在不同系统的节点编号和负荷数据下写法差异很大。核心要理解的是:节点功率平衡把所有“注入”和“流出”功率在同一个节点方程里对齐,注入包括SOP有功、储能放电、光伏出力;流出包括负荷、储能充电。符号稍微搞反一个,整段结果就会面目全非。
5.4 求解提速与结果提取
多时段模型求解速度的关键在两个方面。一是约束装配方式,用for循环逐条加约束最直观,但T=96时Yalmip内部处理会比较慢;加速做法是先定义约束元胞数组,循环里只往里塞约束,最后一次性vertcat,能快不少。二是求解器参数,sdpsettings('solver','mosek','verbose',2)只控制输出级别,真正影响求解时间的是模型本身——变量多、二进制变量多,时间会成倍增长。
结果提取统一用value()函数。我通常先提取储能SOC画一条曲线看看是否平滑,再提取SOP两端有功看方向是否符合预期,最后提取各时段电压分布看是否夹在上下限之间。三步检查都过了,这个解才可以进入后续分析。
6. 算例验证与实战踩坑记录
6.1 一个典型算例的设置与结果趋势
以IEEE 33节点系统为例,我设置了一个光伏渗透率不算低的典型日场景,SOP接在传统联络开关位置,储能放在光伏接入密集的末端节点附近。模型跑通后,先做三个方案对比:无SOP无储能、仅SOP、SOP+储能。结果趋势是很明显的:
- 加入SOP后,系统日网损相对基础方案有可观下降,下降百分比取决于SOP接入位置和容量配置,常见区间在百分之十几到百分之三十左右。
- SOP投入后,电压越限问题基本消除,尤其是光伏大发时段末端电压被明显压低。
- 再加入储能后,光伏峰值时段的电压尖峰进一步被削掉,傍晚峰荷时段的电压凹陷也被托了上来,储能的能量搬移优势和SOP的空间调配优势叠加在一起,电压曲线几乎被压成一条平直线。
检查模型正确性有个好办法:把SOP容量设成0、储能容量也设成0,此时模型应该退化成普通的潮流优化结果。如果退化后结果和潮流计算工具算出的基础潮流对不上,说明约束装配有问题,这和“先调通小系统再加设备”的思路是一回事。
6.2 我实际踩过的坑,按杀伤力排序
第一个坑是SOC初值。Yalmip变量默认没有初值,如果你在递推式里用了SOC(:,1)却没给它赋值,求解器可能直接报错,也可能给出一个数值上看起来合理但物理上完全不可行的解。解决方式是显式加一行SOC(:,1) == 0.5,并在递推结束时检查末端SOC是否落在合理区间。
第二个坑是电压平方约束写错。变量是V_sqr,它代表的是电压的平方,所以上下限写成V_min^2 <= V_sqr <= V_max^2,而不是V_min <= V_sqr <= V_max。这个错误非常隐蔽,因为模型依然有解,只是电压真实值会踩出限值。
第三个坑是二阶锥的写法。有人习惯用norm([...]) <= ...表达锥约束,但Yalmip里某些写法不会被识别为凸约束,求解器会报“nonconvex”。更稳妥的是直接用cone()函数显式声明。物理直觉上也要清楚:松弛后的锥是“电流可以偏大”,而目标函数会把它拉回来,所以不能为了稳妥把锥的方向写反。
第四个坑和路径有关。之前我有一次在带中文名的文件夹里跑模型,Mosek的dll加载失败,报错信息却指向莫名其妙的模型错误。排查了很久才意识到是求解器没加载成功,Yalmip默默换成了内置的最简求解器。这类环境问题,最直接的规避方式就是全英文路径。
第五个坑是设备容量设得太离谱。SOP容量如果远超馈线实际可传输功率,优化结果中SOP会长时间满功率运行,看似“充分利用”,实际已经违背工程约束。建议建模时按馈线最大可转供功率的合适比例设置SOP容量,并做容量灵敏度分析,观察网损和电压改善是否随容量增加而边际递减。
第六个坑是贪多求全。OLTC、电容器组、SVC、储能、SOP全塞进同一个优化模型里,二进制变量数量爆炸,问题从SOCP直接变成混合整数二阶锥规划(MISOCP),求解时间从几秒变成几十分钟甚至不收敛。除非研究目的就是多设备协同,否则建议把连续调节的SOP和储能作为主控设备,OLTC和电容器用固定时段表或事后校验处理,这样模型既聚焦又可控。
第七个坑是用96时段直接调试。我后来总结的顺序是:先用24时段跑通、用5%的容差检查SOC曲线、用电压曲线确认方向,再切换96时段做正式算例。一步到位直接上96时段,排查问题的时间成本会翻好几倍。
做这个模型前后折腾了差不多一个月,最大的体会是:SOP和储能协同优化的难点不在算法多高深,而在于把物理设备的运行边界在数学里表达准确。SOC递推符号写错一个,二阶锥方向搞反,结果都会非常离谱。另外多时段模型一定要先用小算例调通逻辑,再上大规模系统。如果你也正在搭类似的主动配电网优化模型,建议第一步别急着加复杂目标函数,先把潮流约束跑精确,再逐步加SOP、加储能,每一步都对比结果变化。这样哪怕后面报错,也能很快定位是哪一层约束出了问题。
