
这几年做配电网规划的横向课题十个甲方有八个要问充电桩怎么布。但说句实话大部分项目里充电负荷都是被当作固定负荷处理的——某个节点一天有多少辆车充电就直接堆在那个节点上DG怎么分布、网损怎么算、电压怎么控制全都围绕这个搬不动的负荷展开。直到有一次项目评审专家提了一句你这些充电负荷凭什么不能换个地方充我才真正意识到空间可调度这四个字才是充电站与分布式电源联合配置里最值得深挖的东西。这篇文章我想把这件事讲透什么是充电负荷的空间可调度特性它如何改变联合配置模型的构建方式以及完整的Matlab求解框架怎么落地。内容涉及配电网DistFlow潮流约束、二阶锥规划SOCP、YalmipGurobi/启发式算法两种求解路径、IEEE 33节点算例的设置与结果解读最后还会把我实际复现过程中踩过的几个坑原原本本列出来。适合正在做配电网规划、电动汽车充电设施布点、分布式电源选址定容方向研究或工程项目的同行参考无论是入门还是已经写了半截代码应该都能找到对得上的那块拼图。1. 为什么要盯上空间可调度这个特性1.1 传统的充电站规划忽略了什么常规的充电站选址定容模型里充电负荷通常是这么处理的根据某个区域的车流量、保有量、平均充电功率预估出每个节点的充电需求曲线然后把它当成一个不可挪动的PQ负荷叠加到配网节点上。模型要干的事就是在备选节点里选几个位置配上若干台充电桩使得投资和运行的综合成本尽可能低。这样建模有一个隐藏的假设每个用户的充电地点是锁死的。但实际不是这样。私家车用户既可能在自己小区的慢充桩充电也可能在单位楼下充还可能在商场地下车库的快充站花四十分钟补电。货拉拉、网约车这类高频运营车辆更明显司机每天在哪个区域接单、跑到哪、在哪充电很大程度上是动态决策的。换句话说充电需求总量虽然客观存在但它在空间上的落点是有弹性的。这个弹性就是空间可调度特性。看得见摸得着的意义在于如果一个区域内分布式光伏午间大发、电压顶到接近上限那我们当然希望充电负荷往这边挤一挤就地消纳一部分光伏而晚间光伏出力归零、负荷高峰期则可以引导充电需求往电源侧充裕或者网架更坚强的节点走避免末端线路重载。1.2 空间可调度特性的物理基础与工程价值要把可调度从一句口号变成可计算的参数首先要搞清楚它的物理来源。它可以拆成三个层面来看用户行为弹性。相当比例的电动汽车用户对充电地点不是唯一确定的尤其是公共快充场景下哪里方便、哪里便宜、哪里不排队本身就构成一个选择集合。规划层面不需要精准还原每一个用户的习惯但可以把充电需求按一定比例视为可流动的。充电设施的多样性。住宅慢充、单位目的地充电、公共快充、换电站不同类型的设施在空间上天然分散同一个用户在不同日期、不同时段完全可能选择不同设施这为空间调度提供了设施层面的支撑。配网运行的实际需要。线路过载、变压器容量紧张、电压越限这些问题在小范围内是可以通过转移充电负荷来缓解的。在规划阶段把这个自由度利用起来等于用很小的代价换取了运行阶段更大的调节空间。工程价值体现在数字上更直接考虑空间可调度后充电站会倾向于建设在分布式电源容量充裕、就地消纳条件好的节点附近而不是单纯扎堆在负荷中心。这样一来配电网的倒送功率变少、网损下降、电压曲线更平稳DG利用率也能往上走。联合配置的价值恰恰来自这种源随荷动和荷随源动的双向协调。1.3 联合配置与单独配置的本质区别单独做分布式电源配置时充电站的位置已经定了DG只能被动适应负荷分布可选的容量上限被现有网架约束得死死的单独做充电站配置时DG容量已定充电负荷只能挤在现有的电源结构下找最优解。两种做法都是把对方当作不可变更的边界条件得到的最优其实是被另一半锁死的次优解。联合配置把两件事塞进同一个优化模型里一次性决定DG的选址定容和充电站的选址定容。复杂度的确上去了但是解空间更大能挖出来的效益也更扎实。尤其当充电负荷具备空间可调度能力的时候这个联合模型的潜力才真正被释放出来——充电负荷不再是给定的负担而是像抽水蓄能、储能一样成为可以参与空间优化的灵活性资源。所以联合配置这个题目的核心并不是把两个模型简单拼接而是找到一种方式让充电负荷的空间弹性反哺整个配电网的投资决策。2. 数学模型把可调度特性写成可求解的约束2.1 场景集与决策变量怎么设计规划模型的输入是典型场景。一般做法是选取若干典型日——比如风大光强的春秋典型日、夏季高温高负荷日、冬季晚高峰负荷日加上节假日特殊日——每个场景下按小时给出常规负荷曲线、光伏出力和风电出力曲线。场景数量太少结果偏保守场景太多求解规模爆炸。我常用的做法是先算四季典型日再用K-means把历史数据聚成6~8个场景兼顾精度和计算时间。决策变量分两组DG选址定容变量。确定在哪些备选节点安装光伏/风电各装多大容量。光伏容量按额定有功功率kW/MW计需要同时考虑逆变器额定容量和功率因数范围。充电站选址定容变量。确定在哪些备选节点建设充电站每站配置多少台直流快充桩或交流慢充桩。如果用连续优化DG容量和充电桩数量都当作实数变量求解快但结果需要取整如果考虑整数规划充电桩数量用整数变量更贴近实际。在这个问题上我倾向于混合整数二阶锥规划MISOCP的建模方式总投资决策用0-1变量表示是否建容量用连续变量或整数变量表示。明面上看求解慢一些但胜在结果可以直接用于工程方案不用再费劲做人工取整修正。2.2 目标函数年度综合成本怎么算联合配置的目标函数一般取规划期内的年综合费用最小把一次性投资折算到每年再叠加运行成本$$\min C C_{DG}^{inv} C_{CS}^{inv} C_{OM} C_{loss}$$DG投资年值$C_{DG}^{inv}CRF_{DG}\cdot\sum_{i}\left(c_{PV}S_{PV,i}c_{WT}S_{WT,i}\right)$其中 $S_{PV,i}$ 是节点 $i$ 配置的光伏容量$c_{PV}$ 是单位容量建设成本$CRF_{DG}$ 是资本回收系数。充电站投资年值$C_{CS}^{inv}CRF_{CS}\cdot\sum_{j}\left(c_{CS}^{0}\cdot u_j c_{CS}^{p}\cdot N_{CS,j}\right)$$u_j$ 表示是否在备选点 $j$ 建站$N_{CS,j}$ 是充电桩数量。年运维成本$C_{OM}$ 按设备投资的一定比例计取光伏、风电、充电桩的运维费率各有不同。年网损成本$C_{loss}c_{e}\sum_{s}\rho_s T_s\sum_{l}I_{l,s}^2 R_l$$\rho_s$ 是场景 $s$ 的权重比如天数占比$T_s$ 是场景时长。资本回收系数的计算公式是 $CRF r(1r)^{T_{life}}/((1r)^{T_{life}}-1)$$r$ 是贴现率$T_{life}$ 是设备使用年限。这里有一个血泪教训光伏和充电桩的寿命周期不一样常见分别取20年和10~15年如果混在一起用一个CRF折算结果会出现不小的偏差最好分别折完再加总。2.3 潮流约束与配电网运行约束配电网的连续潮流方程用DistFlow形式写最直观。对配网中从节点 $i$ 流向节点 $j$ 的支路$$P_{ij}-r_{ij}l_{ij} \sum_{k\in\mathcal{C}(j)}P_{jk}P_{j}^{load}-P_{j}^{DG}$$ $$Q_{ij}-x_{ij}l_{ij} \sum_{k\in\mathcal{C}(j)}Q_{jk}Q_{j}^{load}-Q_{j}^{DG}$$ $$v_j^2 v_i^2 - 2(r_{ij}P_{ij}x_{ij}Q_{ij}) (r_{ij}^2x_{ij}^2)l_{ij}$$其中 $l_{ij}$ 是支路电流平方$v_i$ 是节点电压幅值。这个方程组是非凸的直接求解既慢又容易掉进局部最优。工程上标准的做法是做一个二阶锥松弛$$l_{ij} \geq \frac{P_{ij}^2Q_{ij}^2}{v_i^2}$$变成不等式后可行域被放宽成一个凸锥问题变成二阶锥规划SOCP。这一步是整个模型能被高效求解的核心。除了潮流本身还必须加这几类约束节点电压上下限常见取 $[0.95,1.05]$标幺值即 $0.9025 \leq v_j^2 \leq 1.1025$线路电流上限 $l_{ij} \leq I_{max}^2$DG渗透率约束所有DG容量之和不超过系统最大负荷的一定比例通常取30%~50%充电站节点接入容量不越过该节点的可用变电容量2.4 空间可调度约束的数学表达与对比空间可调度特性最实用的数学处理方式是把充电负荷拆成固定分量可调度分量两部分。设场景 $s$ 在时段 $t$ 的全网总充电需求为 $D_{s,t}$其中比例为 $\alpha$ 的部分可在空间上重新分配剩余 $1-\alpha$ 保持原有分布固定部分仍按常规方法分摊到各节点$P_{CS,i,t}^{fix} \eta_i \cdot (1-\alpha)D_{s,t}$$\eta_i$ 是节点 $i$ 原本承担的充电需求比例。可调度部分作为优化变量由模型决定流动到哪些节点$\sum_i P_{CS,i,t}^{sch} \alpha D_{s,t}$。此外每个节点充电负荷有上限$0 \leq P_{CS,i,t}^{sch} \leq \min(P_{CS,i}^{cap}, P_{CS,i}^{grid}, P_{i}^{max})$分别对应充电站自身容量、配电网节点可用容量和线路传输能力。如果你希望细化到哪些需求区向哪些充电站转移的空间拓扑关系可以把 $\alpha$ 展开成分布系数矩阵 $y_{k,i,t}$表示需求区 $k$ 在时段 $t$ 分配给充电站候选点 $i$ 的充电需求比例然后强制 $\sum_i y_{k,i,t}1$并用距离/服务半径约束 $y$ 的可行域。这种写法在考虑交通约束时很合适但模型规模会明显变大。我的经验是配电网规划层面先用第一种聚合模型跑通需要写交通耦合分析时再升级成第二种两种形式的可调度约束在Matlab代码里其实只是几行矩阵乘法和等式约束的差别。直观对比一下传统负荷模型和空间可调度模型的核心约束差异对比项固定模型空间可调度模型充电需求归属每个节点固定比例部分需求自由分配可变自由度无各节点接受量可调对DG出力的适应被动承受主动匹配求解难度低中高但仍是凸/SOCP3. 求解思路与Matlab实现框架3.1 模型性质分析与求解器选型上面的模型做完二阶锥松弛之后整体是一个混合整数二阶锥规划MISOCP。如果规模不大可以直接用YalmipGurobi或Cplex求解——这也是我最推荐的第一版实现路线因为凸优化有全局最优解保证不需要折腾种群参数和收敛判据。但有时候问题会变得不那么友好候选节点多、典型日场景多、充电需求分时段建模又引入上百个时段变量MISOCP的求解时间可能飙到几十分钟甚至更久。这时候有两种变通策略分解式求解——外层用启发式算法比如灰狼优化GWO、粒子群PSO搜索选址定容方案内层用YalmipGurobi求解给定方案下的运行层SOCP这样整数决策和连续运行分开处理外层迭代100~200次每次内层秒级出解总时间可控。场景削减时间解耦——限制可调度系数的时间耦合程度把时间序列分段优化最后再做段间协调。我个人实际项目里的选择追求论文般全局最优就用MISOCP一把梭工程现场汇报需要快速出结果就用GWO内层SOCP。两个方案我在代码仓库里都保留切换起来只是主函数替换约束层代码完全复用。3.2 代码架构与核心代码实现Matlab代码整体分为四层数据层、场景层、模型层、求解层。目录结构如下joint_config/ ├── main.m % 主程序入口 ├── data/ │ ├── case33_net.m % IEEE 33节点系统参数 │ └── scen_data.mat % 典型日场景曲线 ├── model/ │ ├── build_constraints.m % 潮流运行约束Yalmip │ ├── build_objective.m % 目标函数 │ └── set_candidates.m % 备选节点与参数设置 ├── solver/ │ ├── solve_misocp.m % 直接MISOCP求解 │ └── solve_gwo_socp.m % GWO外层内层SOCP └── report/ └── plot_results.m % 结果出图主程序入口的伪代码%% main.m - 联合配置主程序 clc; clear; close all; % 1. 加载网络参数和场景数据 load(data/scen_data.mat); % scen.P_load, scen.P_pv, scen.P_wt, scen.rho mpc data(case33_net); % 2. 设置备选节点 cand.pv_nodes [7, 12, 18, 24, 30]; cand.wt_nodes [6, 14, 21, 25]; cand.cs_nodes [5, 8, 11, 17, 27, 32]; % 3. 模型参数 param.alpha 0.6; % 空间可调度比例 param.Vmax 1.05; param.Vmin 0.95; param.SmaxDG 0.6; % 各节点最大DG容量(MW) param.maxCharger 10; % 各充电站最大桩数 param.priceElec 0.5; % 购电电价(元/kWh) % 4. 求解 switch solveMode case misocp result solve_misocp(mpc, scen, cand, param); case gwo_socp result solve_gwo_socp(mpc, scen, cand, param); end % 5. 数据汇总和出图 plot_results(result, mpc);模型层是核心用Yalmip构建目标函数和约束的一种示例%% build_constraints.m - 关键约束构建片段仅展示核心逻辑 % 定义变量 V2 sdpvar(nb, nt); % 电压幅值平方 Pij sdpvar(nb-1, nt); % 支路有功 Qij sdpvar(nb-1, nt); % 支路无功 lij sdpvar(nb-1, nt); % 支路电流平方 PDG sdpvar(nDG, nt); % DG有功出力 QDG sdpvar(nDG, nt); % DG无功出力 SCS sdpvar(nCS, 1); % 充电站容量 PCS sdpvar(nCS, nt); % 充电站有功负荷 Constraints []; % 支路首端潮流DistFlow for k 1:nb-1 for t 1:nt i branch(k,1); j branch(k,2); r branch(k,3); x branch(k,4); Constraints [Constraints, ... Pij(k,t) - r*lij(k,t) ... sum_child_P(k,t) PCS_node(j,t) Pload(j,t) - PDG_node(j,t)]; Constraints [Constraints, ... V2(j,t) V2(i,t) - 2*(r*Pij(k,t) x*Qij(k,t)) ... (r^2 x^2)*lij(k,t)]; end end % 二阶锥松弛 Constraints [Constraints, ... lij(k,t) (Pij(k,t)^2 Qij(k,t)^2) / V2(i,t)];需要提醒的是Yalmip里直接写 $l_{ij} \geq \frac{P^2Q^2}{V^2}$ 是不行的要用cone()或者全部改成双线性表达式再用ccos/expose转换。正确写法是构造锥约束% 二阶锥等价写法 Constraints [Constraints, ... cone([2*Pij(k,t), 2*Qij(k,t), V2(i,t)-lij(k,t)], V2(i,t)lij(k,t))];3.3 与Matpower的协同细节很多同行喜欢用Matpower做潮流基准网络这里有个协作技巧Matpower内置的case33是交流潮流的完整数据节点导纳矩阵、斜率、各负荷但DistFlow约束需要的是支路拓扑和阻抗参数不必拘泥于Matpower的runpf。我通常只从case33里抽取bus、branch矩阵生成自己的网络结构然后用Yalmip重写潮流约束。抽取方式很简单function [branch, bus] load_network(casefile) mpc loadcase(casefile); bus mpc.bus(:, 1:3); % bus编号、类型、电压基准 branch mpc.branch(:, 1:4); % 首端、末端、r、x branch(:,3:4) branch(:,3:4) / mpc.baseMVA * 100; % 标幺换算 end这步换算出过岔子Matpower中支路阻抗是以100 MVA为基准的标幺值而配电网规划习惯用10 MVA或者直接用有名值。如果基准没统一后面的潮流约束、网损成本全会错得离谱。我的建议是全部在有名值域内建模然后在接入变压器处做好标幺换算每个数值都打印出来核对一遍。4. IEEE 33节点算例从结果怎么反推模型合理性4.1 算例设置与候选节点选择IEEE 33节点标准测试系统是配电网规划文献里最常见的验证平台首端节点1通过变压器与上级电网相连基准电压12.66 kV总有功负荷约3.715 MW无功约2.3 Mvar。我在做联合配置时做了三件事一是把33节点划分为三个馈线段在各段末端挑选DG备选节点常见候选是6、14、18、24、30这类离变电站较远、电压偏低的节点二是把充电站候选点布置在负荷集中区和未来车流密集区比如节点8、17、27、32这些点普遍网架较薄弱恰好能检验可调度带来的改善效果三是给出了光伏和风电出力曲线的典型日场景并对各场景赋权重。场景数据不是拍脑袋的实际做法是根据当地辐照度和风速小时数据用K-means聚成几个代表性曲线。比如夏季场景光伏出力从8点开始爬升、13点到达峰值然后下降冬季风电在晚间出力更高。每个场景对应一个时长权重系数全年8760小时按权重折算保证规划结果能反映全年运行状态的综合情况。4.2 三组方案对比及结果解读为了讲清楚空间可调度到底带来了什么算例里一般会设置三组对照方案A不装DG只建充电站充电负荷固定。方案BDG与充电站联合配置但充电负荷固定alpha0。方案CDG与充电站联合配置且充电负荷具备空间可调度能力alpha0.6。以我自己跑出来的趋势来说具体数值依赖场景参数但以下方向在任何合理参数下都成立方案年综合成本网损电量电压最低点DG年利用率A较高较高0.925无DGB中中0.95中等C低6%~12%低8%~15%0.97高8%~20%方案C的结果一出来充电站的位置分布会明显区别于BB模式下充电站几乎全部扎堆在初始负荷重的节点C模式下一部分充电站会转移到DG容量较大的节点附近形成就地消纳格局。这是因为可调度充电负荷能主动匹配光伏、风电出力的时空分布DG多余的出力被就近充电负荷吸收不再需要沿着长线路远距离输送网损自然减少同时充电负荷接入点附近因为有DG的电压支撑电压水平也比方案B更稳。这个结果反过来验证了模型合理性如果跑出来的方案C和方案B高度趋同充电站位置基本没变化那大概率是模型里空间可调度约束没生效——最常见的原因是在约束里忘记把可调度部分并入节点功率平衡方程导致可调度负荷只是名义上可变、实际没有进入潮流计算。4.3 敏感性分析可调度比例对配置结果的影响参数 $\alpha$空间可调度比例是全模型最重要的调节旋钮。令 $\alpha$ 从0变化到1追踪总成本和DG利用率的变化能画出经典的下沉曲线$\alpha$ 越大成本下降越多但边际效益递减——从0到0.4通常下降最快0.6以后逐渐趋缓。这说明工程上不需要追求百分之百的可调度适度引导用户充电行为就能获取大部分收益。实际规划中 $\alpha$ 的取值依赖用户调研和充电行为数据的统计结果。保守的规划师取0.2~0.4只把本来就顺路充电那一部分需求视为可流动激进一点取0.5~0.7认为通过价格引导和App推荐可以有效调动用户选择充电场地。我建议在报告中同时给出乐观、中性和保守三档 $\alpha$ 下的配置方案供决策方参考——这也是评审专家比较认可的处理方式。5. 复现过程中容易踩的坑5.1 二阶锥松弛不紧怎么办SOCP求解完成后不能直接采信必须先验证松弛的紧性。检验方法是读取每个支路各时段的 $l_{ij}$ 和对偶间隙 $l_{ij} - (P_{ij}^2Q_{ij}^2)/v_i^2$。如果间隙值基本在 $10^{-6}$ 量级说明松弛是紧的结果对应原问题最优解如果某些支路间隙达到 $10^{-3}$ 以上说明出了问题这时不能只顾着看目标函数值。松弛不紧的常见原因有三个目标函数没有充分激励网损最小化比如网损成本权重太小模型觉得没必要精确逼近潮流可行域、部分节点电压过低导致锥约束向右漂移、支路电流约束激活方式不对。处理手段依次是给网损成本加权或加一个小的惩罚项 $\mu\sum l_{ij}$$\mu$ 取 $10^{-4}$~$10^{-3}$ 即可、检查电压下限约束是否设置过松过松会让锥体开口变大、逐个支路看约束激活情况。正常调下来一两个条件就能解决。5.2 场景生成与数据预处理典型日场景这一环节看着不起眼实际最费时间。最容易犯的错是把辐照度、风速、负荷三种数据的统计口径混在一起某套历史数据是UTC时间、另一套是当地时区时间峰值对不上或者负荷数据是15分钟粒度、风光数据是1小时间粒度插值后出现锯齿。上个月我在帮学生跑一个类似的模型就卡在这里光伏午间出力曲线怎么都对不上负荷曲线peak时间最后发现两份历史数据的时间基准差了两个小时整整排查了一天才定位。我的建议是写一个统一的数据预处理脚本先统一时区、统一时间戳再统一时间分辨率最后按年/季分类做K-means聚类。每个场景除了曲线本身还要记录权重天数、最大负荷占比等元信息方便后面多场景加权汇总。这个脚本虽然不参与优化求解但决定了模型结果的可信度值得认真写。5.3 Yalmip/Gurobi调用与版本兼容配置Yalmip环境时最烦的问题就是求解器版本匹配。Gurobi、Cplex、Mosek这些商用求解器的许可证还在其次更多问题是Matlab版本和求解器版本接口不兼容比如新版Matlab自带的intlinprog和Yalmip的optimize调用有时会有警告或报错。建议固定一套经过验证的组合Matlab R2020b及以上 Yalmip 2021版 Gurobi 9.5/10.0。安装完成后先用Yalmip自带demoyalmiptest跑一遍确认所有求解器都识别正常。另外在调用optimize之前务必设置求解器选项比如ops sdpsettings(solver, gurobi, verbose, 2, gurobi.MIPGap, 0.001); result optimize(Constraints, Objective, ops);如果Gurobi提示license问题可以先改用内嵌的sedumi或SDPT3验证小规模模型的正确性再转Gurobi算大规模。这样隔离了建模错误和求解器错误排查起来会快很多。5.4 从33节点走向大系统的策略IEEE 33节点只是验证模型合理性的小试牛刀实际配电网常常是135节点、415节点、乃至上千节点的规模。直接套用同一套代码求解MISOCP的规模会让人崩溃。这里我把实际经验分享一下网络简化先把辐射状网络中那些末端轻载分支做等效合并戴维南等效/功率等值保留关键节点和重载支路模型规模可能缩小一半以上。场景削减用K-means或K-medoids把8760小时聚成10个以内场景用场景权重加权计算求解速度可以提升一个数量级。算法切换外层启用GWO/粒子群算法搜索整数选址变量内层运行SOCP求解连续运行变量。实测下来33节点几十秒、135节点几分钟就能收敛。结果校验大系统出结果以后一定要抽几个工况放到全网交流潮流里做校验比如用Matpower的runpf确认规划方案在全网模型下电压、电流不越限。这几招依次叠加下来基本能覆盖工程上常见的规模需求。千万记住模型和算法都要为能落地、能复现、能向评审交代服务不要为了炫技把简单问题复杂化。用SOCP能解决就不要硬上复杂算法先把准确的结果跑出来再根据实际诉求做扩展优化。至于代码整体架构我强烈建议从一开始就保持数据、模型、求解、报告四层分离。到了后期换网络、换算法、换参数的时候你会感谢当时坚持分层设计的自己。别问我怎么知道的——我第一版把所有逻辑揉在一个脚本里改一个数据要全局搜三遍那种痛苦写代码的人都懂。