微电网多目标优化调度中改进粒子群算法的MATLAB实现与踩坑记录

发布时间:2026/11/3 23:54:14
微电网多目标优化调度中改进粒子群算法的MATLAB实现与踩坑记录

简介:针对微电网中风-光-柴-燃-储多能源协调调度问题,提供一套基于改进粒子群算法的多目标优化MATLAB程序,适合电力系统方向的研究生、工程师及对智能优化算法感兴趣的开发者借鉴。压缩包整体仅1.31MB,包含18个文件,其中以12个.m源代码为主,涵盖传统PSO与改进PSO两套对比实现;另有xlsx格式的输入数据、txt格式的程序说明及参考文献压缩包,便于快速上手与对照分析。已有2598人学习下载,属于较受关注的微电网调度类资源。程序内容涉及多目标Pareto支配关系、外部档案维护、Particle与Repository等核心模块,以及风光柴燃储各单元的运行约束和经济/环保目标权衡,可直接运行或二次修改,帮助读者深入理解改进粒子群的寻优机制并迁移至其他优化调度场景。

1. 改进粒子群算法为什么成了微电网调度的默认选项

微电网的多目标优化调度,简单说就是决定柴油机、储能和主网交互功率在每个时段怎么出力,让运行成本、污染排放和购电费用互相权衡。这个问题带有强约束、多峰值、非线性,标准粒子群算法跑起来很容易早熟,改进粒子群算法通过自适应惯性权重、变异和约束修正,成了 MATLAB 里复现率很高的一条路。无论你是正在做微电网仿真课设,还是想把论文里的调度策略落地成可运行程序,这套思路都值得完整走一遍。下面不绕弯子,直接从建模讲到 MATLAB 实现和踩坑记录。

2. 微电网多目标优化调度的数学建模:目标函数与约束怎么设才不翻车

微电网优化调度的第一步不是写粒子群,而是把物理系统变成数学表达式。模型建错,后面算法再漂亮结果也没法用。

2.1 调度目标:运行成本、排放成本与电网交互成本怎么折算

微电网里的可控设备,最常见的是柴油发电机、储能电池和主网联络线。光伏和风电一般按预测值处理,当作负荷的“负值”参与功率平衡。调度目标通常包含三项。

第一项是柴油机燃料成本。工程上常用二次函数拟合燃料消耗特性:

C_fuel = sum(a * P_dg² + b * P_dg + c)

这里的系数 a、b、c 可以通过柴油机耗量特性曲线拟合得到。如果手头没有厂家数据,常见做法是用最小二乘法拟合几个典型出力点的耗量数据;实在没有数据,也可以用线性系数代替,但优化结果会失去非线性特征,和真实调度偏差较大。

第二项是污染排放成本。把 NOx、SO2、CO2 分别乘排放因子,再乘单位环境治理成本,最后汇总成排放费用。注意柴油机的排放因子和电网侧购电的排放因子要分开写,因为电力的来源结构不同。电网侧购电排放因子通常取当地电网的平均值,这个值会随季节和时段变化,但日前调度里一般按常数处理。

第三项是主网交互成本。向电网购电按峰谷电价,向电网售电按上网电价。这里有一个容易被忽略的细节:如果决策变量写成“购电功率为正、售电功率为负”,成本表达式可以分段写,但需要注意购电电价通常高于售电电价。如果两个方向价格不同且允许同时购电和售电,优化算法会利用差价“套利”,得到物理上不存在的调度方案。因此约束里必须加一条:同一时段不允许既购电又售电。

这三项成本量纲都是“元”,看起来可以直接相加。但量级差异很大:一天燃料成本可能是几千元,排放成本只有几百元,电网交互可能是一百多元。直接相加,粒子群算法的寻优压力几乎全部集中在量级大的项上,小量级目标形同虚设。我通常先把每个目标除以一个基准值,让三项都在同一量级,再按权重相加。基准值可以取“所有负荷全部由主网购电”时的对应成本,也可以在每次迭代时用当前种群目标值做归一化。后一种做法更贴合算法收敛过程,但会增加计算量,对 24 小时调度来说 MATLAB 完全能接受。

2.2 约束条件:功率平衡、储能SOC、柴油机爬坡与出力限值

约束是微电网调度和一般函数优化最大的区别。粒子群算法本身无约束,所有约束都必须想办法嵌进适应度计算里。

功率平衡约束:每个时段,光伏预测功率加风电预测功率加柴油机出力加储能放电功率加主网购电功率,必须等于负荷功率加储能充电功率加主网售电功率。写成等式:

P_pv(t) + P_wt(t) + P_dg(t) + P_dis(t) + P_buy(t) = P_load(t) + P_ch(t) + P_sell(t)

为避免同时购电和售电,可以把 P_buy 和 P_sell 合并成一个决策变量 P_grid(t),正值为购买、负值为出售,表达式更简洁,也自然避免了套利问题。

储能 SOC 约束:SOC(t+1) = SOC(t) + (P_ch(t) * η_ch - P_dis(t) / η_dis) * Δt / Capacity。SOC 必须介于 [SOC_min, SOC_max],通常取 0.2 到 0.9。这里还要防止 SOC 在优化结束时偏低导致次日无法运行,一般加一个“末端 SOC 回弹”约束,让最终 SOC 接近初始 SOC,或者直接固定 SOC_final = SOC_initial。这个约束我曾在初版程序里漏掉,结果优化算法很聪明地把储能电量在一天结束时全部放空,虽然总成本最低,但第二天根本没有可用电量,实际调度完全不可行。

爬坡约束:柴油机相邻时段出力变化不能太大,|P_dg(t+1) - P_dg(t)| ≤ ramp_rate。这个约束涉及跨时段耦合,粒子位置的维度就是 24 小时,所有时间点放在一个向量里,检查时要循环扫描每个相邻时段。爬坡不设,柴油机出力会在两个相邻时段之间剧烈跳变,调度计划无法执行。

充放电功率限值:储能充电和放电功率各自不超过额定值,而且不能同时充放电。同时充放电在数学上是互补约束,处理起来有点麻烦。常见做法是设置一个变量表示净功率,充电为负、放电为正,然后通过非线性约束限定。在粒子群实现里,我一般直接把 SOC 变化当作决策量,再反推充放电功率,从根上避免同时充放电。

2.3 决策变量与调度周期:从日前调度到日内滚动

调度周期决定了粒子的维度。24 小时日前调度,时间分辨率 1 小时,那么每个可控变量有 24 个时段。如果可控设备包括柴油机、储能、主网交互,决策变量总数就是 3 × 24 = 72 维。粒子维度过高会严重影响粒子群收敛速度,所以不是特殊情况,不建议把时间分辨率设到 15 分钟还一跑就是好几天。

我常用的决策变量排布方式如下表,MATLAB 里所有变量拼成一个行向量,按“先设备、后时间”的顺序排列,这样在目标函数里拆包比较直观。

变量维度下界上界说明
柴油机出力1×240额定功率单位 kW
储能充电功率1×240额定充电功率充电为正
储能放电功率1×240额定放电功率放电为正
主网交互功率1×24-售电上限购电上限正为购电,负为售电

目标函数在 MATLAB 里按这个顺序拆包:

function f = microgrid_objective(x, para) % 按决策变量排列顺序拆包 n = para.nHorizon; % 调度时段数,默认24 Pdg = x(1:n); Pch = x(n+1:2*n); Pdis = x(2*n+1:3*n); Pgrid = x(3*n+1:4*n); % 柴油机燃料成本,二次函数拟合 fuelCost = para.a * Pdg.^2 + para.b * Pdg + para.c; fuelCost = sum(fuelCost); % 排放成本:柴油机和电网购电分别折算 emissionCost = para.emDg * sum(Pdg) + para.emGrid * sum(max(Pgrid, 0)); % 电网交互成本:正为购电成本,负为售电收益 gridCost = sum(para.buyPrice .* max(Pgrid, 0) + para.sellPrice .* min(Pgrid, 0)); % 总目标 f = fuelCost + emissionCost + gridCost; end

这段代码里,max(Pgrid,0) 和 min(Pgrid,0) 用分段方式区分购电与售电;para.buyPrice 和 para.sellPrice 是长度为 24 的数组,如果采用分时电价,每个时段的电价不同,必须用点乘而不是常量乘。这是程序里最容易写错的地方,直接用 sum(buyPrice * max(Pgrid,0)),如果 buyPrice 是向量,MATLAB 会报维度错误,如果用常量又等于把峰谷电价抹平了。

排放成本里,para.emDg 是柴油机单位出力排放成本,para.emGrid 是购电侧排放成本。注意这里是“成本”不是“排放量”,因为我们已经把排放因子和环境价格乘好了。如果后续要做灵敏度分析,可以把排放系数单独拆出来。

3. 改进粒子群算法:从标准PSO到能处理多目标的三个关键改动

3.1 标准PSO为什么容易早熟:惯性权重与学习因子的玄学

标准 PSO 的迭代公式不复杂。以最小化问题为例,每个粒子记录自身历史最优 pbest,整个种群共享全局最优 gbest,速度更新和位置更新如下:

v = wv + c1r1*(pbest - x) + c2r2(gbest - x) x = x + v

w 是惯性权重,c1、c2 是学习因子,r1、r2 是 [0,1] 均匀随机数。微电网调度目标函数有大量局部极小点,尤其是储能 SOC 在不同时段的充放电组合,让目标曲面非常不平滑。标准 PSO 里 w 固定时,要么前期收敛太快陷入局部最优,要么后期在最优解附近振荡不收敛,这就是大家常说的调参玄学。跑十次出十个不同调度计划,基本可以断定算法早熟。

解决早熟不是靠堆迭代次数,而是要把惯性权重和学习因子变成随时间变化的量。

3.2 自适应惯性权重与异步学习因子:参数怎么定

改进粒子群算法里,最常见也最稳的一套是:惯性权重线性递减,学习因子异步变化。迭代前期 w 大,c1 大,c2 小,粒子更多地参考自身历史最优,探索整个搜索空间;迭代后期 w 小,c2 大,粒子向全局最优靠拢,精细开采。

MATLAB 里可以单独写一个参数生成函数,每个迭代周期调用:

function [w, c1, c2] = ipsoparams(iter, maxIter, fit, fitAvg) % 线性递减惯性权重 wMax = 0.9; wMin = 0.4; w = wMax - (wMax - wMin) * iter / maxIter; % 根据个体适应度与种群均值的关系做调整 % 个体比平均差,保留更大惯性权重,加强探索 if fit > fitAvg w = min(w * 1.15, wMax); else w = max(w * 0.85, wMin); end % 异步学习因子:前期重自我,后期重全局 c1 = 2.5 - (2.5 - 0.5) * iter / maxIter; c2 = 0.5 + (2.5 - 0.5) * iter / maxIter; end

这里 fit 是当前粒子的适应度,fitAvg 是当前种群的平均适应度。如果当前粒子质量比平均差,就把惯性权重放大 15%,让这个粒子保留继续飞行的能力;如果质量比平均好,就把 w 缩小 15%,让它在局部精搜。注意加了限幅,防止 w 越界。

c1 和 c2 的范围我固定取 2.5 到 0.5、0.5 到 2.5,这是一组在工程问题里被验证过很多次的区间。如果你的调度周期短、粒子维度低,可以把 c1 初值降到 2.0,因为搜索空间没那么大。维度高的时候,前期探索必须足够充分,c1 初值升到 2.8 也不算夸张。关键看收敛曲线:如果前 20 代最优适应度就基本不动,说明 c1 太大,种群分裂严重;如果 10 代附近就聚集到某个局部解,说明衰退得太快,要减小初始 w 或增大初始 c1。

3.3 多目标处理:加权求和、罚函数与Pareto前沿的取舍

微电网调度本质上确实是多目标优化。但 MATLAB 工程实现里,大家不一定会把 Pareto 前沿跑出来,更多是用加权求和把多目标压成单目标。这背后有个现实原因:调度员要的是一个明确的出力计划,而不是一堆积权衡解。如果你的需求是把成本和排放都考虑进去,那加权系数就是你要调的核心参数。

加权后的适应度函数可以写成:

F = w1 * C_cost + w2 * C_emission + penalty

其中 w1 和 w2 代表决策偏好。但直接给权重比较难定。我习惯先单独跑一次“只优化成本”,记录成本最小值 Ccost_min;再跑一次“只优化排放”,记录排放最小值 Cem_min。然后把权重设为:

w1 = 1 / Ccost_min,w2 = 1 / Cem_min

这样两个目标在数值上都回到 1 附近,权重的比例变为纯偏好比例。这比起拍脑袋设 0.7 和 0.3 要可靠得多。这个方法特别适合第一次接触微电网多目标优化的读者,能避免“权重设太小,目标被淹没”的问题。NSGA-II 多目标优化这类算法常被拿来做 Pareto 前沿对比,但作为落地调度,加权加罚函数一般够用。

罚函数处理约束是另一个重点。粒子更新后可能不满足功率平衡或 SOC 约束,直接丢弃会损失粒子多样性,所以用惩罚项把不可行解的适应度抬高。惩罚项的写法很多,最稳的是:

penalty = sum(abs(powerBalanceViolation)) * p1 + sum(max(SOCViolation, 0)) * p2

p1 和 p2 要调到让不可行解的适应度明显高于可行解,但又不至于高到可行域外完全没有搜索梯度。这里有个踩坑点:惩罚系数过大会让算法把所有精力放在“满足约束”而不是“降低目标”,结果出来一个可行的但成本很高的调度;过小则约束根本约束不住。我的经验是把惩罚系数从 0.1 倍目标值往上试,每次查看最终解的约束违反量,直到违反量小于 0.01。

3.4 变异算子与种群多样性的兜底措施

即使有了自适应惯性权重,粒子群还是可能因为部分粒子被 gbest 吸引而聚集到同一区域。微电网调度里,储能 SOC 的时域耦合很容易形成“漏斗”,粒子一旦都滑进同一个局部低点,后面很难跳出来。所以我都会加一个变异步骤:每次迭代,按一定概率(比如 5%)随机选择部分维度,重新在这个维度的可行域内随机初始化。

实现起来就是在更新位置后加三行:

mask = rand(size(x)) < 0.05; % 5%的概率触发变异 x(mask) = lb(mask) + rand(1, sum(mask(:))) .* (ub(mask) - lb(mask));

注意这里的 lb 和 ub 要跟决策变量一一对应。变异维度选在储能充放电时段效果最明显,因为 SOC 的耦合关系最容易限制搜索方向。变异概率不是越大越好,超过 10% 会导致算法退化成随机搜索,收敛曲线一直下不去。5% 是我在 24 小时调度问题里常用的起点,最后再看收敛曲线微调。

4. MATLAB程序实现:把改进粒子群调度跑通的最小可复现方案

4.1 程序架构与文件清单:主函数、目标函数、约束检查、PSO迭代

我习惯把一个完整的调度程序拆成四个文件,别全部塞在一个脚本里。微电网的数据、预测负荷、电价都是固定的,但运行一次可能需要换参数,拆开更好维护。文件清单如下:

文件作用关键输出
main_ipsoschedule.m主函数,读参数、初始化种群、调用迭代、画图调度计划、收敛曲线
microgrid_objective.m目标函数目标值
microgrid_constraint.m约束违反量计算penalty
ipsoparams.m自适应参数生成w, c1, c2

如果你要跑对比实验,再加一个 standard_pso.m,把改进逻辑去掉,其他部分共用,就能直接对比改进前后的收敛效果。这是论文里常用的“改进前后对比”套路,也是验证改进有效的必要步骤。

4.2 核心代码:改进PSO主循环的参数与逻辑说明

主循环是整段程序的骨架。下面是一个可以直接抄下来改参数的最小版本:

% main_ipsoschedule.m clear; clc; rng(2024); % 参数初始化 para.nHorizon = 24; % 调度时段 para.nPop = 50; % 粒子数 para.maxIter = 200; % 迭代次数 para.penaltyFactor = 100; % 惩罚系数起点 % 决策变量边界 nVar = 4 * para.nHorizon; % 柴油机、充电、放电、主网交互 lb = [zeros(1, 2*para.nHorizon), ... zeros(1, para.nHorizon), ... -para.sellLimit*ones(1, para.nHorizon)]; ub = [para.PdgMax*ones(1, para.nHorizon), ... para.PchMax*ones(1, para.nHorizon), ... para.PdisMax*ones(1, para.nHorizon), ... para.buyLimit*ones(1, para.nHorizon)]; % 初始化种群 X = zeros(para.nPop, nVar); V = zeros(para.nPop, nVar); for i = 1:para.nPop X(i,:) = lb + rand(1, nVar) .* (ub - lb); V(i,:) = 0.1 * (lb + rand(1, nVar) .* (ub - lb) - X(i,:)); end % 计算初始适应度 fitness = zeros(para.nPop, 1); for i = 1:para.nPop fitness(i) = evaluate( X(i,:), para ); end [pbest, pbestVal] = deal(X, fitness); [gbestVal, gbestIdx] = min(fitness); gbest = X(gbestIdx, :); % 迭代主循环 for iter = 1:para.maxIter fitAvg = mean(fitness); for i = 1:para.nPop [w, c1, c2] = ipsoparams(iter, para.maxIter, fitness(i), fitAvg); r1 = rand(1, nVar); r2 = rand(1, nVar); V(i,:) = w * V(i,:) + c1 * r1 .* (pbest(i,:) - X(i,:)) + c2 * r2 .* (gbest - X(i,:)); % 速度限幅,防止越界 V(i,:) = max(V(i,:), (ub - lb) * -0.2); V(i,:) = min(V(i,:), (ub - lb) * 0.2); X(i,:) = X(i,:) + V(i,:); % 边界反射处理 outLow = X(i,:) < lb; X(i,outLow) = lb(outLow); outUp = X(i,:) > ub; X(i,outUp) = ub(outUp); % 变异 mask = rand(size(X(i,:))) < 0.05; X(i,mask) = lb(mask) + rand(1, sum(mask)) .* (ub(mask) - lb(mask)); newFit = evaluate( X(i,:), para ); if newFit < fitness(i) fitness(i) = newFit; pbest(i,:) = X(i,:); end if newFit < gbestVal gbestVal = newFit; gbest = X(i,:); end end % 记录收敛曲线 convergence(iter) = gbestVal; end

主循环的逻辑是按时间顺序更新每个粒子:先按当前迭代动态计算 w、c1、c2,再更新速度、限幅、位置、边界反射、变异,最后评估新适应度并更新 pbest 和 gbest。这里速度限幅我取上下界跨度的 20%,太大会让粒子在可行域边缘反复弹跳,太小会拖慢收敛。

边界反射是处理越界粒子最常用的手段。这里直接把越界维度拉回边界,而不是随机重置,好处是保留该粒子在其他维度上的搜索信息。如果你发现算法在边界附近停滞,可以把“拉回”改成“将越界维度的速度取负一半”,这样粒子能弹回内侧继续搜。

变异概率和惩罚系数都在主函数里集中定义,方便批量跑实验。注意 evaluate 里调用了 objective 和 constraint,实现如下:

function f = evaluate(x, para) f = microgrid_objective(x, para) + para.penaltyFactor * microgrid_constraint(x, para); end

4.3 结果输出:绘制调度计划、目标函数收敛曲线与SOC变化

程序跑完,要能直接出三张图:调度计划堆叠图、收敛曲线、储能 SOC 变化。调度计划堆叠图可以用 bar 加堆叠样式实现:

% 从gbest里拆出各设备出力 n = para.nHorizon; Pdg = gbest(1:n); Pch = gbest(n+1:2*n); Pdis = gbest(2*n+1:3*n); Pgrid = gbest(3*n+1:4*n); figure; bar([Pdg; Pdis; max(Pgrid,0)]', 'stacked'); hold on; plot(para.Pload, 'k-', 'LineWidth', 1.5); legend('柴油机','储能放电','购电','负荷'); xlabel('时段'); ylabel('功率/kW'); grid on;

这里充电功率和售电功率是负荷侧,单画。SOC 曲线单独画一条:

% SOC迭代 SOC = zeros(1, n+1); SOC(1) = para.SOC0; for t = 1:n SOC(t+1) = SOC(t) + (Pch(t)*para.etaCh - Pdis(t)/para.etaDis) * para.dt / para.capacity; end figure; plot(0:n, SOC*100); ylim([para.SOCmin, para.SOCmax]*100); xlabel('时段'); ylabel('SOC / %'); grid on;

注意 SOC 初始值要单独设,SOC0 等于末端约束值。如果画出来的 SOC 曲线贴着上限或下限走,不是 bug,但往往说明储能容量偏大或目标里电价激励太极端,需要回到约束和目标函数里核对。

5. 避坑与常见问题:微电网多目标优化调度的5个血泪踩坑记录

5.1 约束处理与储能SOC相关的三个坑

坑一:功率平衡约束没留松弛量,迭代越跑越离谱。

现象:粒子群很难找到可行解,适应度曲线下降很慢,最后得到的调度计划里,负荷和出力差了好几十千瓦。

原因:等式约束要求严格等于 0,但在连续搜索空间里,正好等于 0 的概率极低,惩罚项一直在起作用,把搜索梯度带偏了。

解决:在 evaluate 里,把功率平衡违反对应的惩罚从“绝对值”改成“绝对值减去松弛量”,比如允许 0.01kW 的误差。实现时可以这样写:

powerBalanceViolation = abs(sum(P) - Pload); penalty = max(0, powerBalanceViolation - 0.01);

这样小于 0.01 的偏差不产生惩罚,粒子群不需要把精力浪费在无效的精度比拼上。

坑二:储能 SOC 只在上下限内,但末端 SOC 没有被约束。

现象:优化结果里最后时段 SOC 总是贴着 0.2 的下限,第二天调度没法继续,程序作者还以为这是正常结果。

原因:目标函数只关心成本,SOC 放空成本最低,算法自然利用这个漏洞。

解决:在约束函数里加上 SOC(n+1) >= SOC0,也就是末端 SOC 不低于初始 SOC。更严格可以固定相等,但固定相等会缩小可行域,我一般用“不小于”配上很小的惩罚。约束函数里加一行:

socFinal = SOC(end); penalty = penalty + max(0, para.SOC0 - socFinal) * 1e4;

惩罚系数 1e4 不是固定值,要看你目标函数的量级,但方向是确定的:让末端 SOC 不足变成不可行。

坑三:充放电同时发生。

现象:优化结果里同一时段充电和放电功率都大于 0,虽然 SOC 变化正常,但物理上是浪费能源,因为电池在自充自放。

原因:两个独立的决策变量没有约束彼此互斥。

解决:改成单一净功率变量,SOC 增加为正,减小为负,再通过充放电效率分段处理,这样从根上消灭同时充放电。若你坚持保留两个变量,则必须加互补约束:Pch * Pdis = 0,但这个约束非线性强,粒子群处理起来非常痛苦,不推荐。

5.2 算法参数与程序兼容性的两个坑

坑四:惩罚系数直接拍脑袋定,没有根据目标量级微调。

现象:程序跑出的调度计划功率平衡满足,但柴油机输出忽大忽小,成本反而比普通规则调度还高。

原因:惩罚系数过大,优化首先满足惩罚,导致可行解被“压”进可行域边界,而没有合理优化目标。系数过小,则约束失控,出现大量不满足功率平衡的解。

解决:第一次运行时把惩罚系数设小,比如 1,看目标值和违反量;然后逐步放大到违反量低于 0.01 且目标值不再异常波动。记录每个惩罚系数对应的最优解目标值,目标值开始回升的那一点就是系数上限。可以用循环跑 7~8 组系数,画一条“惩罚系数-目标值”曲线,比反复试更快。

坑五:MATLAB 版本差异导致的兼容性坑。

现象:代码在 MATLAB R2021b 上运行正常,换到新版报错,或者低版本读不了高版本的 .mat 文件。

原因:版本升级后部分函数行为有变化,比如 max/min 对空矩阵的处理、rng 种子设置方式、某些绘图属性默认值改变,以及字符串拼接规则的收紧。

解决:尽量不使用全局变量,用 struct para 统一传参;避免依赖隐式扩展,显式写 repmat 或 .*;如果跑的是老代码,优先把函数句柄和 eval 用法替换成现代写法。另外,中文注释在某些版本会出现乱码,建议主函数开头加 set(0,'DefaultAxesFontName','Times New Roman'),或干脆用英文注释,省得踩编码坑。

6. 验证与进阶:怎么判断优化结果可信,以及如何把程序扩展到实时调度

6.1 收敛性验证的基本功:多轮独立运行和统计指标

改进粒子群算法本质是随机算法,单次结果不能证明改进有效,尤其别只看一次的最好收敛曲线。我自己的习惯是至少跑 30 次,每次重新设置 rng 种子或直接用当前时间种子,记录每次的最优值、平均值和标准差。标准差大说明算法稳定性差,需要检查变异概率或惩罚系数;标准差很小且平均值与最优值接近,说明算法比较稳。把 30 次结果画成箱线图,比一张收敛曲线更能说服自己,也更容易发现参数是否合理。

6.2 把程序扩展成日内滚动调度的关键改动

日前调度和实时调度最大的区别是滚动窗口。把 24 小时维度改成 4 小时滚动窗口,每小时触发一次优化,只执行当前时段的调度指令,然后重新预测负荷并更新状态。程序上改动不算大:把 para.nHorizon 从 24 改成 4,预测负荷加载当前时刻的未来 4 小时值,SOC 初始值用实测量而不是固定值,最后只需要保留第一个时段的功率指令下发给设备。

这个方向很值得做,因为实时调度才是工程落地的刚需。做滚动调度时,把第 4 章的优化函数包在一个 for 循环里,每小时调用一次即可。别忘记在每次滚动前重新生成随机种子,否则连续滚动调度可能一直复现同一个随机序列,结果失去随机性意义。

我最大的教训是:一开始没有花时间做 30 次重复实验,直接拿一次运行结果对比标准 PSO,差点得出“改进无效”的错误结论,后来发现只是随机种子选得太差。从那以后,每次跑优化程序,第一件事就是把重复运行统计写进主程序,结果好坏都先看分布。希望这个习惯也能帮到你少走弯路。

本文还有配套的精品资源,点击获取