
1. 无序充电的隐患与动态电价引导充电的本质逻辑1.1 为什么无序充电会让配电网措手不及先说一个我在实际项目中反复遇到的场景。某个居民小区的变压器容量是500kVA基础负荷晚高峰大约300kW正常运行问题不大。但随着小区里电动汽车越来越多每天傍晚下班回家十几辆、几十辆车几乎同时插上充电枪每辆按7kW慢充来算的话30辆车就是210kW的额外负荷。基础负荷300kW加上充电负荷210kW稳稳超过500kW变压器过载、低压侧电压跌落、线路发热这些问题全都来了。如果接入的是快充桩60kW甚至120kW的功率两三辆同时充就够让一台配变告警。从负荷形态上看无序充电的特点是时间高度集中、功率逐辆叠加。所谓的无序并不是说用户有意制造问题而是每个人都假设我回家就插上充电枪随时要用车完全没有考虑邻居是否也在充电。电动汽车的保有量渗透率一旦过了某个阈值这种羊群效应式的充电行为必然和电网晚高峰形成叠加。那问题来了车主真的需要一回家就立刻以最大功率充电吗大量通勤场景下一辆电池容量60kWh的车每天通勤消耗也就是15%~25%的电量。下班到家SOC还剩60%甚至70%都很正常。换句话说用户真正需要的约束不是插上就满功率充而是第二天出发前电池达到目标电量。这两个约束之间有极大的调度空间电动车本身就有天然的柔性调节潜力。1.2 多时段动态电价是怎么传导调节信号的动态电价本质上是一个价格信号驱动的资源分配机制。把一天划分为峰、平、谷等多个时段每个时段对应不同的电价用电成本高的时段自然抑制充电需求电价低的时段则吸引充电负荷转移。对于像电动汽车这种需求可以在数小时内平移的负荷来说这种价格引导比行政手段强制错峰要温和得多也更容易被用户接受。我整理了一份典型峰平谷电价结构时段类型时间范围电价元/kWh峰时10:00-15:0018:00-21:001.2平时07:00-10:0015:00-18:0021:00-23:000.7谷时23:00-07:000.4假设一辆电池60kWh的车到家SOC为30%目标充电到95%需要充入39kWh。如果从18:00开始以7kW满功率充大约到23:35充满按实时计价规则计算费用大概在45元左右。但如果把充电开始时间推迟到23:00次日6:20左右就能充满所有电量都计在谷时电价上费用只有15.6元。这就是接近3倍的价差也是用户侧可感知的激励。这里有一个需要讲清楚的概念划分有序充电与有序充电控制是两个不同层级的事情。本文讨论的优化属于日前计划级也就是已经知道了次日全天电价曲线和车辆接入预测信息离线计算每一辆车的最优充电功率曲线。至于实时控制那是在计划基础上根据实际到达车辆、实时负荷波动再做的修正。初学的时候不要把这两层搅在一起先把日前计划做扎实实时修正只是在这个基准上的小步调整。1.3 电动车充电优化到底优化的是谁的指标这其实是最容易被忽略但最要命的问题。建模的时候必须先想清楚你站在谁的立场上做优化站在用户角度核心诉求是充电费用最小。目标函数就是每一辆车在各时段的充电功率乘以对应电价再累加。站在电网角度核心诉求是负荷曲线平稳也就是削峰填谷目标函数往往写成负荷方差的极小化。大多数研究做的是两者的加权组合用参数去调节用户和电网之间的利益平衡。这个立场差别会直接导致你的最优解长得完全不一样。只优化费用结果一定是几乎所有电量都堆到谷时段谷时段本身以及其他非峰时段也可能被充出新高峰只优化负荷方差可能在某个时段要求用户以较低的功率充电甚至推迟充电导致用户费用上升。实际工程里充电运营商的立场往往介于两者之间既希望用户满意度高又不能让台区过载。2. 优化模型的分步构建决策变量、目标函数与全套约束推导2.1 决策变量和仿真场景的参数设定建模的第一步是把物理过程抽象成数学表达。这里我用的决策变量是充电功率矩阵P(i,t)表示第i辆车在第t个时段的充电功率。调度周期可以选择24个一小时时段也可以选择96个十五分钟时段。时间粒度越细对电价跳变的刻画越准但变量维度也成倍增加。初版模型用24个小时时段足够了后面需要精细分析时再加密到96点。场景参数按典型的居民区慢充场景来设置参数符号典型取值车辆数量N50~100辆电池容量E_i40~60 kWh均匀分布初始SOCSOC_init,i20%~90%随机目标SOCSOC_target,i90%~100%随机最大充电功率P_max,i7 kW慢充桩充电效率η0.92到家时间t_start,i18:00~20:00出发时间t_end,i次日07:00~08:00有一个特别多初学者踩的坑出发时间跨天的问题。比如车主18:00到家次日7:00出发如果用一天内的小时数直接表示7点在数值上小于18点建模时就会出现时段错乱。我的做法是统一把调度周期设为48小时或给时间轴加偏移量比如把当天18:00记为t18把次日07:00记为t31247通过一个逻辑变量判断充电窗口内的时段。2.2 目标函数设计三选一还是加权组合上面已经提到目标函数有三种常见形式我分别展开说。第一种用户侧充电费用最小min Σ_i Σ_t price(t) × P(i,t) × Δt这个目标非常直白代码写起来也简单就是功率矩阵和价格向量做点乘再求和。问题在于所有车都会往谷时段挤可能造成谷时段集中充电的局部负荷过高。所以这个目标通常要配合各时段总充电功率上限之类的约束使用。第二种电网侧负荷曲线方差最小min Σ_t (L_base(t) Σ_i P(i,t) - L_avg)²其中L_base(t)是基础负荷L_avg是全天平均负荷。这个目标追求的是总负荷曲线尽可能平坦削峰填谷效果直接体现在目标函数里但完全没有考虑用户电费成本车主不一定买账。第三种也是最常用的加权多目标min α × fee β × varianceα和β的取值表示你更偏向哪一方。实际操作中我习惯先固定β1把α从0.01扫到10绘制出一条费用-方差的帕累托前沿曲线。这比拍脑袋定一个权重有说服力得多也能直观看出不同偏好下最优解的迁移规律。2.3 约束条件的完整拆解与符号细节约束条件我按重要性从高到低排列每一条都会直接影响解的可行性。SOC连续性约束SOC(i,t1) SOC(i,t) η × P(i,t) × Δt / E_i这是整个模型的物理引擎表示电池电量随充电功率的动态累积。这里有一个常见符号混淆充电效率η是乘在功率上的也就是充入电池的实际功率是η×P(i,t)但P(i,t)本身是充电桩输出的功率。很多人的模型里η放错位置导致实际充入电量偏大或偏小。充电功率上下限0 ≤ P(i,t) ≤ P_max,iSOC本身的范围约束SOC_min ≤ SOC(i,t) ≤ SOC_max通常SOC_min取0.1SOC_max取0.95。上限不取1.0是为了给电池留寿命余量也贴合实际BMS控制策略。出行需求约束SOC(i,t_end) ≥ SOC_target,i这保证车主第二天出发时电量够用是整个模型里和用户直接体验最相关的约束。充电窗口约束t_start,i ≤ t ≤ t_end,i之外的所有时段P(i,t)强制为0这个约束我倾向于直接通过决策变量的索引范围实现而不写成显式约束方程能省掉不少冗余行。变压器容量约束推荐加L_base(t) Σ_i P(i,t) ≤ P_trans这个约束把优化结果和真实配电网容量关联起来是后来我做工程落地时最看重的一条。基础模型可以先不加但只要有条件建议一开始就把它纳入。根据我的经验初版模型不要把约束做得太精致比如充电过程不允许中途中断这类约束虽然贴近用户偏好但会把线性规划变成混合整数规划求解难度直接上一个台阶。基础模型先保留约束1~5跑通之后再加变压器容量约束和用户行为约束一步一步来每加一条约束都对比一下它对结果的影响这样做研究的时候你能讲清楚哪条约束导致了哪些变化。3. 求解器选型精确解CPLEX与启发式PSO的适用边界3.1 为什么第一版我强烈建议用YALMIP工具箱搭配CPLEXMatlab下做优化建模最顺手的方式是YALMIP工具箱。它的作用是把你的数学模型翻译成求解器能识别和求解的标准形式你不需要手动构造约束矩阵A、b、Aeq、beq这些只需要声明决策变量、写目标函数、加约束然后调用optimize()一句命令完成求解。我第一版通常写成这种结构% 决策变量N辆车 × T时段 的功率矩阵 P sdpvar(N, T, full); % 目标函数总充电费用最小 fee sum(sum(P .* repmat(price, N, 1) * dt)); objective fee; % 约束集合 constraints []; % SOC连续性约束、功率上下限、出行需求约束逐条添加 for i 1:N for t t_start(i):t_end(i)-1 constraints [constraints, SOC(i,t1) SOC(i,t) eta * P(i,t) * dt / E(i)]; end constraints [constraints, SOC(i, t_end(i)) SOC_target(i)]; end constraints [constraints, 0 P P_max]; % 调用求解器 optimize(constraints, objective, sdpsettings(solver, cplex)); P_opt value(P);这种写法最大的好处是模型和求解器解耦。你想换Gurobi、换MOSEK只需要改solver参数模型代码完全不用动。对于车辆数小于100、时段数24~96的小规模问题CPLEX基本在几秒内给出全局最优解用来做基准结果非常合适。3.2 粒子群PSO的实现思路从编码方式到适应度函数当车辆数上升到几百甚至上千或者你加了0/1变量后变成混合整数规划CPLEX的求解时间会急剧上升。这时候就需要启发式算法出场。PSO粒子群算法是电力系统优化里用得最多的启发式算法之一。核心思路每个粒子代表一个完整的充电计划粒子的位置向量是一个N×T维的数组里面第(i,t)个元素就是第i辆车在第t时段的充电功率。粒子的速度向量表示解空间中移动的方向和步长。适应度函数是PSO的灵魂。我的做法是function f fitness(x, params) % x 是 N*T 维的位置向量先reshape成矩阵 P reshape(x, params.N, params.T); % 计算目标函数值比如总费用 obj sum(sum(P .* params.price_matrix)) * params.dt; % 计算约束违反量乘以惩罚系数加到适应度 penalty 0; % 检查SOC最终值、功率上下限等累加违反量 ... f obj params.penalty_factor * penalty; end惩罚系数的设置很讲究。太小大量不可行解混进种群算法根本收敛不到可行域太大搜索初期所有粒子都被惩罚项压得失去多样性容易陷入局部最优。我的经验是先设一个中等偏小的值观察gBest曲线是否抖动再逐步调大。速度与位置更新公式是标准形式v w * v c1 * rand(size(v)) .* (pbest - x) c2 * rand(size(v)) .* (gbest - x); x x v;惯性权重w从0.9线性衰减到0.4学习因子c1c21.4962种群规模50~100迭代次数200~500。这几组参数在我的多个模型上表现都比较稳定可以作为起点。3.3 两个求解器怎么配合使用我强烈建议有条件的同学两个都写。用CPLEX解出来的结果作为精确基准用PSO结果代表实际可落地的工程解两者的差距用相对误差来衡量。如果PSO的结果和CPLEX最优解的偏差超过5%先不要急着怀疑算法大概率是惩罚参数或者种群规模没调对。这里也顺带提一句很多审稿人会问既然CPLEX能解为什么还要用PSO你必须能回答这个问题。合理的答案是一方面说明模型在小规模下的最优性一方面展示方法在大规模场景下的可扩展性。这两者并不矛盾而是互补。4. Matlab代码逐段拆解数据生成、主循环与约束构建的实战细节4.1 数据生成随机车辆参数与电价曲线怎么构造才够严谨在做仿真研究时车辆参数的随机生成方式直接决定了结果是否有说服力。我习惯用蒙特卡洛抽样来生成一个居民小区的电动汽车接入场景。rng(42); % 固定随机种子保证实验可复现 N 50; % 车辆数 T 24; % 调度时段数小时 dt 1; % 时段长度小时 % 电池容量40~60 kWh 均匀分布 E 40 20 * rand(N, 1); % 初始SOC20%~90% 均匀分布 SOC_init 0.2 0.7 * rand(N, 1); % 目标SOC90%~100% 均匀分布 SOC_target 0.9 0.1 * rand(N, 1); % 最大充电功率统一7 kW慢充 P_max 7 * ones(N, 1); % 充电效率 eta 0.92; % 到家时间18~20点 t_start 18 2 * rand(N, 1); % 出发时间次日7~8点统一加24小时偏移 t_end 31 rand(N, 1); % 分时电价元/kWh峰平谷三段 price [0.4 * ones(1,7), ... % 0-7点谷时 0.7 * ones(1,3), ... % 7-10点平时 1.2 * ones(1,5), ... % 10-15点峰时 0.7 * ones(1,3), ... % 15-18点平时 1.2 * ones(1,3), ... % 18-21点峰时 0.7 * ones(1,3)]; % 21-24点平时这里有几个细节需要强调关于rng固定随机种子很多人一上来就忽略。加入这一行你每次运行代码结果完全一致不仅方便自己调试也方便别人复现你的实验。发论文时把种子数字写在附录里审稿人印象分会好很多。t_end采用31而不是7直接避开了跨天比较的坑。在后续SOC计算时循环范围从t_start到t_end自然覆盖夜间时段。电价向量长度要严格等于T否则后面repmat广播时维度对不上。这种低级错误排查起来特别浪费时间。4.2 主程序框架从初始化到结果可视化的完整流程整个主程序的结构如下%% 1. 参数初始化 % 上一节代码块中的内容 %% 2. 生成基础负荷曲线可以用典型日负荷数据 % 简单模拟一个居民区基础负荷晚高峰在19点左右 t 1:24; L_base 150 80 * exp(-((t - 19).^2) / 12) 40 * exp(-((t - 8).^2) / 8); %% 3. 定义决策变量与目标函数YALMIP版 P sdpvar(N, T, full); fee sum(sum(P .* repmat(price, N, 1))) * dt; objective fee; %% 4. 构建约束 constraints []; % SOC连续性和功率限制的循环代码参见前文 %% 5. 调用CPLEX求解 optimize(constraints, objective, sdpsettings(solver, cplex)); P_opt value(P); %% 6. 结果后处理 % 计算每辆车SOC轨迹 SOC_traj zeros(N, T1); SOC_traj(:,1) SOC_init; for t 1:T SOC_traj(:,t1) SOC_traj(:,t) eta * P_opt(:,t) * dt ./ E; end %% 7. 绘图总负荷曲线、费用对比、SOC轨迹 figure; plot(1:T, L_base, k-, LineWidth, 1.5); hold on; plot(1:T, L_base sum(P_opt,1), r-, LineWidth, 1.5); xlabel(时间/h); ylabel(负荷/kW); legend(基础负荷, 含充电负荷);这个流程把建模-求解-分析三层分得很清楚每一层都可以独立替换。比如你想换PSO求解只需要替换第3~5步后处理代码不用动。4.3 最容易翻车的三个代码细节第一矩阵维度对齐。YALMIP里用repmat把价格向量广播成N×T矩阵时如果price是行向量、P是N×T矩阵维度才能匹配。很多人习惯把price写成列向量报错时怎么都找不到原因。第二SOC循环里的数据类型混用。t_start和t_end是我生成的随机数用于for循环时必须取整floor或ceil否则Matlab会直接在for循环定义处报错或者循环次数不符合预期。我建议从一开始就把t_start和t_end定义为整数向量后面省心很多。第三P_opt的取值处理。value(P)返回的是sdpvar对象的最优数值但求解器给出的结果经常带小数点后十几位的浮点噪声比如功率值出现-1e-9这样的负极小值。后处理时建议加一句钳位处理P_opt max(P_opt, 0); % 把数值噪声归零5. 仿真结果的分析方法论、收敛性问题排查与扩展方向5.1 结果对比的三件套负荷曲线、费用柱状图和SOC轨迹把模型跑通之后最怕的就是只会画一张优化后的负荷曲线就收工。我做结果分析时至少会做三组对比。第一组无序充电、仅谷时充电与有序充电三种策略的负荷曲线对比。无序充电是每辆车一到家就满功率充到目标SOC。仅谷时充电是策略极端情况把所有可平移电量全放到谷时。有序充电则是今天模型求解的结果。这三条曲线放在同一张图里削峰填谷的效果一目了然。如果有序充电的曲线和无序充电差别不大那你的电价信号或者约束设置一定有问题。第二组日均充电费用柱状图。把三种策略下用户平均充电费用算出来做对比柱状图。这个指标直接反映电价激励的有效性也是用户最能感知的部分。第三组选三四辆有代表性的车画SOC轨迹。比如一辆早到家早出发的、一辆晚到家早出发的、一辆SOC初始值特别低的看它们各自的充电行为差异。这比只画总负荷曲线生动得多也能帮助读者理解约束是怎么起作用的。评价指标我建议至少计算峰值负荷、负荷方差、峰谷差、用户平均充电费用这四个。整理成表格放在论文里比大段文字描述有说服力得多。5.2 PSO不收敛的排查链路很多同学跑来问我为什么我的PSO结果那么差排查路径其实高度一致我按顺序列一下。先看适应度曲线走势。如果gBest曲线在迭代后期仍然大幅震荡多半是惩罚系数太小种群里有大量不可行解。处理办法是把惩罚系数向上调调到结果出现可行但不优的迹象后再微调下降。如果适应度曲线单调下降但很快就停滞说明w衰减太快或者种群规模太小粒子失去多样性全部挤在局部最优附近。处理办法是调整w的衰减速度或者换用自适应惯性权重。如果问题本身变量维度特别高比如N200、T96就是19200维PSO基本会失效。这时候不要硬扛两个方向一是降低时间粒度从96点降到24点二是把连续功率离散成几个档位0/3.5/7kW三档把连续优化退化成组合优化配合整数编码处理。最后对比CPLEX结果。如果小规模下PSO结果和精确解偏差超过5%基本可以断定是算法实现问题不是模型问题。5.3 参数灵敏度分析与扩展方向完整的研究不应该只做单一场景。我建议至少跑三组参数扫描扫描维度取值观察指标峰谷价差0.3、0.6、0.9元用户费用下降比例车辆渗透率10、50、100辆负荷方差、变压器负载率目标权重α/β0.01~10帕累托前沿、负荷削峰率这一组表格做完你的论文就从我实现了一个模型升级到我系统分析了关键参数对结果的影响说服力完全不同。扩展方向上最值得做的是V2G也就是把单相充电功率改为双向功率让电动汽车在峰时向电网放电。目标函数和约束需要新增放电功率变量和电池循环损耗成本项基础模型加这一层复杂度并不算太大。其次是模型预测控制MPC把日前计划改成滚动时域优化实时电价加进来后就是一套完整的需求响应策略。这两个方向都是当前研究热点也都有成熟的Matlab实现路径。我在实际跑这些模型的时候最大的体会是不要一上来就追求大而全的场景。先把10辆车、24时段的case跑通确认每个约束都生效、每条结果曲线都有合理解释再逐步放大规模。规模一大调试时间成倍增长各种数值问题、维度问题全都会冒出来。耐心点一个小而正确的模型远比一个大而跑不通的模型有价值。