☰
改进多目标灰狼算法求解含V2G微电网日前调度问题
2026/9/26 17:29:11 网站建设 项目流程

微电网项目里,最近我把一套“基于改进多目标灰狼优化算法的考虑V2G技术的风、光、荷、储微网多目标日前优化调度研究”用Matlab完整跑通了。先说结论:这套东西解决的是一个非常典型的工程问题——在一个包含风电、光伏、常规负荷、储能和电动汽车(V2G)的微网里,提前一天(24小时)安排各台设备的出力计划,同时让运行成本和碳排放两个目标都尽量小。而求解这个多目标优化问题的核心引擎,就是改进多目标灰狼优化算法(Improved Multi-Objective Grey Wolf Optimizer, IMOGWO)。

这篇文章我会从问题建模、V2G怎么融入调度、改进灰狼算法的三个关键设计、Matlab代码实现、结果分析,再到我实际调试中踩过的坑,完整地过一遍。适合正在做微电网调度、综合能源系统优化或者刚接触多目标群体智能算法并且打算用Matlab复现的研究生和工程师。代码框架是通用的,换个目标函数或者加个电转气、冷热联供,思路完全一样。

1. 项目要解决什么问题:多个可控源在24小时时间轴上的协调

1.1 风光荷储微网和时间维度上的调度矛盾

先说场景。这个微网由几个部分组成:

  • 风电:出力受风速影响,夜间往往出力大,白天反而可能很小。
  • 光伏:白天有阳光,出力曲线基本呈正态形状,中午最高,傍晚归零。
  • 负荷:典型居民/园区负荷有两个高峰,早高峰和晚高峰。
  • 储能:铅碳或锂电储能,能充能放,但是有SOC上下限和功率限制。
  • 柴油机(常规机组):作为稳定可控电源,但发电有燃料成本和碳排放。
  • 电动汽车集群(V2G):平时是负荷,需要充电;必要时可以反向放电,成为移动储能。

所谓“日前优化调度”,就是在前一天,基于对第二天24小时的风电、光伏和负荷预测曲线,决定接下来每个小时(分辨率通常取1小时)各个设备该发多少电、充多少电、放多少电、从大网购多少电。

这个问题的难点在于:风电光伏是波动性的,负荷也一直在变,而储能和V2G是“双向可调度”的资源——它们既能存电又能放电,这就让调度问题从单纯的“发电-负荷匹配”变成了一个高维度、强耦合、多目标优化问题。

1.2 为什么必须把V2G拉进来

V2G,全称Vehicle-to-Grid,简单说就是电动汽车不光从电网充电,还能在需要时把电池里的电反向送回电网。放在微网调度里,它等于一个“可移动的分布式储能”:电价低的时候充电,电价高或者负荷紧张的时候放电。

实际操作中V2G不能完全按储能那么用,因为它有用户的出行约束。比如早8点到晚6点之间,车辆SOC不能太低,用户要开车;晚上回来以后才能放电;凌晨还要保证充到一定水平,不能影响第二天使用。这些约束会直接影响调度方案。

加入V2G之后,系统的可调度容量明显上升。在我的一组典型算例里,100辆电动汽车、单车电池容量40kWh,聚合起来相当于额外增加了一个几千千瓦时的可调度储能池。结果是:晚高峰时段从大网购电显著减少,综合运行成本下降了大约8%到10%。这就是V2G在微网调度里的价值。

1.3 为什么选改进多目标灰狼优化算法

这个问题用传统数学规划方法(比如混合整数线性规划MILP)也能解,但目标函数是二次的、变量是高维的、约束是非线性的,而且有两个互相冲突的目标(省钱和减排)。此时多目标智能优化算法是更常见的做法。

常见候选:NSGA-II、MOPSO(多目标粒子群)、MOGWO(多目标灰狼)。我选灰狼有几个原因:

  • 参数少。GWO只需要调整种群数量和迭代次数,不像遗传算法要调交叉率变异率,也不像粒子群要调惯性权重和学习因子。
  • 代码结构直观。灰狼的“头狼包围猎物”机制非常适合做多目标版本的外部档案维护。
  • 但原始GWO有一个明显问题:收敛因子a是线性下降的,导致前期勘探能力偏强但后期局部开发不足,容易早熟;随机初始化种群很容易导致初始解分布不均匀。

所以我在标准MOGWO上做了三处改进:Logistic混沌初始化、非线性余弦收敛因子、差分进化扰动。这样改进之后,Pareto前沿的分布均匀性明显提升,解也更靠近真实前沿。

2. 调度模型怎么建:目标函数、约束与决策变量

2.1 目标函数一:综合运行成本最小

第一个目标函数是经济性目标,涵盖六个部分:

min F1 = 柴油机燃料成本 + 购电成本 - 售电收益 + 储能损耗成本 + V2G放电补偿成本 + 弃风弃光惩罚

逐项拆解:

  • 柴油机燃料成本:通常用二次函数拟合:C_fuel(t) = a * P_d(t)^2 + b * P_d(t) + c。a、b、c是燃料特性系数。这样做的好处是能体现机组在低出力时效率下降、单位燃料成本上升的特点。
  • 购电成本:从大网购电的电费,按分时电价计算,低谷便宜、高峰贵。
  • 售电收益:微网向大网反送电的收入,售电价低于购电价。
  • 储能损耗成本:电池充放电过程中的容量衰减和维护费用,按充放电电量折价。
  • V2G放电补偿成本:电动车用户把电放给微网使用,需要给用户支付放电服务费,否则用户没有参与动力。
  • 弃风弃光惩罚:如果某些时刻新能源过多、系统消纳不了,就要弃掉一部分,弃掉越多、惩罚越大,让算法尽量不弃。

2.2 目标函数二:碳排放总量最小

第二个目标是环保性目标,统计口径是大网购电的间接碳排放和柴油机发电的直接碳排放:

min F2 = sum_t ( P_buy(t) * ef_grid + P_d(t) * ef_diesel ) * dt

其中ef_grid是大网购电的碳排放因子(kg/kWh),ef_diesel是柴油机的碳排放因子。风电和光伏在运行阶段不产生碳排放,储能和V2G本身是能量搬运,碳排放按购入电量归属。

这两个目标存在明显冲突:想让成本低,可能就要多买谷电、多用柴油机顶峰;想让碳排放低,就得减少购电、减少柴油机出力,多依赖风电光伏和储能V2G协调。多目标算法的作用就是把这两个目标同时优化,最后输出Pareto前沿,而不是单一最优解。

2.3 约束条件:功率平衡、SOC、爬坡和联络线

模型里的核心约束如下:

  • 功率平衡约束:每个时段,各电源出力加购电,必须等于负荷加各充电负荷。这是硬约束,用变量代入后自动满足。
  • 柴油机约束:出力上下限,以及爬坡速率限制。比如200kW的机组,相邻时段出力变化不能超过50kW,否则实际机组根本调不动。
  • 储能约束:SOC范围(我设0.1到0.9)、充放电功率上限、充放电效率、相邻时段SOC递推关系。需要特别说明的是,同一时刻不能同时充电和放电,否则模型失真。在Matlab实现中,我采用“正值为放电、负值为充电”的编码方式,从物理上规避了同充同放的问题。
  • V2G约束:聚合体的充放电功率上限、电池SOC范围(0.2到0.9)、用户出行约束(8点到18点SOC不低于0.4)、早晨离网时SOC不低于0.8,覆盖“用户满意度”约束。
  • 联络线约束:与主网交互功率有上限,避免微网对大网造成冲击。

2.4 决策变量编码与算例参数

决策变量设计直接影响优化效率。我采用的编码方式是:

X = [ 柴油机24小时出力 ; 储能24小时充放电功率 ; V2G聚合体24小时充放电功率 ]

总维度是 24 * 3 = 72。注意,储能和V2G的功率正值为放电、负值为充电。与主网的交互功率从功率平衡式里计算出来:

P_grid = P_load - P_w - P_pv - P_d - P_sto - P_v2g; P_buy = max(P_grid, 0); P_sell = max(-P_grid, 0);

这样处理的优势是:避免了把购电和售电同时作为决策变量,从而天然满足功率平衡,变量维度也少了一截,算法收敛快很多。

算例中的典型参数见下表(注意,这是可用于复现的示意数据,实际项目要按现场设备标定):

设备/参数数值说明
柴油机额定功率200 kW出力范围20~200 kW,爬坡50 kW/h
风机额定容量100 kW预测曲线按典型日风速
光伏额定容量80 kW昼间出力
储能额定容量200 kWhSOC范围0.1~0.9
储能最大功率50 kW充放效率0.95
电动汽车数量100 辆单车电池40 kWh
V2G最大功率60 kW聚合充放电上限
V2G放电补偿0.05 元/kWh用户参与补偿
分时电价峰/平/谷1.1 / 0.6 / 0.3 元/kWh峰:8-12、17-21时
碳排放因子(购电)0.9 kg/kWh间接排放
碳排放因子(柴油机)0.2 kg/kWh直接排放

3. 改进多目标灰狼优化算法:从GWO到IMOGWO

3.1 标准GWO的狩猎机制

灰狼算法模拟灰狼群体的等级制度和捕猎行为。种群分四层:α狼是首领,β狼是副手,δ狼是下级,ω狼是基层个体。捕猎时,ω狼根据α、β、δ的位置来更新自己的位置,公式为:

D = | C * X_p(t) - X(t) | X(t+1) = X_p(t) - A * D

其中:

  • X_p是猎物(最优解)的位置,A和C是系数向量。
  • A = 2 * a * r1 - a,这里的a是收敛因子,从2线性降到0。
  • C = 2 * r2,是一个随机权重。

A的绝对值大于1时,狼群扩大搜索范围进行全局勘探;A的绝对值小于1时,狼群靠近猎物进行局部开发。a线性减小导致早期勘探时间过长、后期开发力度不足,这是原始GWO比较容易早熟的原因之一。

3.2 多目标化:外部档案、网格选择和拥挤度

多目标版本和单目标版本最大的区别是:没有唯一的“猎物”,而是有一群互不支配的Pareto最优解。所以算法引入了一个外部档案(Archive),专门存放当前找到的非支配解。

α、β、δ不再是最优个体,而是从外部档案的网格里选择的“引导者”。具体做法是:

  • 把目标空间划分成若干个网格。
  • 网格内解的密度越低,被选中当leader的概率越大。
  • 当外部档案满了,优先删除网格密度最高的解,保留稀疏区域的解。

这套机制的目的很明确:既要让算法向Pareto前沿收敛,又要让解尽量均匀地分布在前沿上,避免所有解挤在一个角落。

3.3 三个改进细节

改进一:Logistic混沌初始化

原始GWO随机初始化种群,容易导致初始解堆在某个区域,算法多样性不够。我用Logistic混沌映射生成初始种群:

x_new = mu * x_old * (1 - x_old)

取mu=3.9,迭代生成一组在(0,1)区间内伪随机分布但相关性很低的序列,再映射到决策变量的上下界。混沌序列的特性是“看似随机、实则遍历”,能让初始解在解空间分布更均匀,好处是降低了早熟风险。

改进二:非线性余弦收敛因子

原来a是线性的,我把a改成余弦递减:

a = 2 * cos( (iter / max_iter) * (pi / 2) )

前期a比较大且下降慢,狼群有充足时间进行全局勘探;后期a快速变小,算法集中进行局部精细开发。效果是收敛速度更快,同时最终解的精度也更高。

改进三:差分进化扰动

即使做了前两个改进,灰狼算法偶尔还是会在Pareto前沿附近“卡住”。我加了一步差分扰动:如果连续若干代某个解一直无法进入外部档案,或者外部档案里的解被删除了,就在它的位置附近生成一个差分变异候选解:

V = X_r1 + F * (X_r2 - X_r3) U_j = V_j if rand < CR else X_j

F取0.5,CR取0.3。这样做的本质是给种群提供“跳出局部最优”的额外机会,尤其适用于多约束条件下解空间不连续的情况。

3.4 算法完整流程和Matlab框架

改进后的IMOGWO流程如下:

  1. 初始化参数,用Logistic映射生成初始种群。
  2. 计算每个个体的两个目标函数值,并进行约束校验。
  3. 根据非支配关系初始化外部档案。
  4. 通过网格法从外部档案中选出α、β、δ狼。
  5. 更新收敛因子a,计算A、C向量。
  6. 所有个体按灰狼位置更新公式移动。
  7. 对被淘汰或长期未更新的个体执行差分进化扰动。
  8. 更新外部档案:支配关系判断、网格预算、删除密集解。
  9. 判断是否达到最大迭代次数,否则回到第4步。
  10. 输出最终Pareto前沿,用模糊隶属度法选折衷解。

Matlab代码建议按模块拆成多个函数:主程序、种群初始化、目标函数计算、约束校验、外部档案更新、位置更新、绘图。我实际项目里就是按这个结构来的,后面调试时定位问题非常快。

4. Matlab实现过程:从数据准备到结果输出

4.1 数据准备:预测曲线与分时电价

先构造24小时的风电、光伏和负荷数据。在实际科研里,这些来自历史数据或者预测模型;在复现实验里,我会用Matlab数组生成带波动的典型曲线。风电夜间出力高(比如20点以后稳定在60到80kW)、光伏从6点开始上升、12点达到峰值60kW、18点归零,负荷有两个峰,早峰在9点左右、晚峰在19点左右。

分时电价直接按峰谷平设置即可,peak、flat、valley三个数组。代码如下:

T = 24; % 典型日负荷曲线(kW) P_load = [60,55,50,48,50,55,70,85,95,90,80,75,72,70,75,80,95,105,110,95,80,70,65,60]; % 风电出力(kW) P_w = [55,60,65,70,65,60,55,50,40,35,30,25,20,20,25,30,35,40,45,50,55,58,60,62]; % 光伏出力(kW) P_pv = [0,0,0,0,0,5,20,38,52,60,62,60,55,48,36,22,8,0,0,0,0,0,0,0]; % 分时电价(元/kWh):峰平谷 price = [0.3,0.3,0.3,0.3,0.3,0.6,0.6,1.1,1.1,0.6,0.6,0.6,0.6,0.6,1.1,1.1,1.1,1.1,1.1,1.1,0.6,0.3,0.3,0.3];

4.2 主循环与目标函数代码

目标函数是整个模型的核心。我把它写成一个独立函数,输入是决策变量向量,输出是两个目标值:

function [F1, F2] = objectives(x, data) T = 24; P_d = x(1:T); % 柴油机出力 P_sto = x(T+1:2*T); % 储能功率,正放负充 P_v2g = x(2*T+1:3*T); % V2G功率,正放负充 % 功率平衡,计算与电网交互功率 P_grid = data.P_load - data.P_w - data.P_pv - P_d - P_sto - P_v2g; P_buy = max(P_grid, 0); P_sell = max(-P_grid, 0); % 柴油机燃料成本,二次函数 a_fuel = 0.0001; b_fuel = 0.04; c_fuel = 3; C_fuel = sum(a_fuel * P_d.^2 + b_fuel * P_d + c_fuel); % 购电成本、售电收益 C_buy = sum(price .* P_buy); C_sell = sum(0.4 .* P_sell); % 储能损耗和V2G补偿 C_sto = 0.02 * sum(abs(P_sto)); C_v2g = 0.05 * sum(max(P_v2g, 0)); % 弃风弃光惩罚 P_w_curtail = max(0, data.P_w_max - data.P_w); P_pv_curtail = max(0, data.P_pv_max - data.P_pv); C_curtail = 1.0 * (sum(P_w_curtail) + sum(P_pv_curtail)); F1 = C_fuel + C_buy - C_sell + C_sto + C_v2g + C_curtail; F2 = sum(P_buy) * 0.9 + sum(P_d) * 0.2; end

这里面有几点需要说明:储能损耗按充放电绝对电量核算,V2G补偿只针对放电方向,弃风弃光惩罚的目的不是强制新能源必须满发,而是通过成本让算法自己权衡“弃还是购电”。

4.3 结果可视化与折衷解选取

多目标优化输出的是Pareto前沿,但工程上最终要落地执行的话,得从Pareto解集里选出一个折衷解。最常用的是模糊隶属度法:

% archive是外部档案中的Pareto解集,两列分别对应F1和F2 n_obj = 2; mu = zeros(size(archive)); for k = 1:n_obj mu(:,k) = (max(archive(:,k)) - archive(:,k)) ./ ... (max(archive(:,k)) - min(archive(:,k)) + eps); end mu_avg = mean(mu, 2); [~, idx] = max(mu_avg); best_solution = archive(idx, :);

这个方法的含义很直观:每个解在每个目标上算出一个“满意度”(0到1之间),越靠近该目标的最优值越接近1;两目标满意度平均值最大的解,就是平衡得最好的方案。

绘制Pareto前沿就直接用scatter:

figure; scatter(archive(:,1), archive(:,2), 20, 'filled'); xlabel('运行成本/元'); ylabel('碳排放量/kg'); title('Pareto前沿'); grid on;

调度计划曲线用stairs绘制柴油机、储能、V2G和电网交互功率,横轴是24小时,能非常直观地看到夜间充电、白天放电的时序。

4.4 典型算例结果对比

我跑的一组典型算例结果如下表:

方案总运行成本/元碳排放量/kg弃风弃光率/%
原始MOGWO(无V2G)485046504.8
IMOGWO(无V2G)458045103.6
IMOGWO(考虑V2G)421040202.1

再说一遍,这是典型算例代表值,数值因数据而异,但趋势是稳定的:改进算法比原始算法在两个目标上都有改善,V2G加入后经济性和环保性同时变好。

从调度计划看,典型场景的行为符合工程直觉:

  • 0点到6点:电价低谷,储能和EV大量充电,柴油机低发或不发。负荷主要由风电和大网供应。
  • 10点到14点:光伏大发,柴油机降到最低技术出力,多余光伏给储能充电。
  • 17点到21点:晚高峰来袭,光伏刚好归零,此时EV和储能联合放电,柴油机快速爬坡顶上去,从大网购电也达到峰值。
  • 23点到24点:EV再次充电,为第二天用户出行做SOC准备。

这种“谷充峰放”的调度结果,正是V2G和储能参与日前优化的价值所在。

5. 实操中踩过的坑与解决方案

5.1 V2G约束太复杂导致种群大面积不可行

最早我把V2G的用户出行约束写得很“硬”:只要SOC低于0.4,直接判定个体不可行。结果算法前期几乎找不到可行解,种群被罚函数搅得乱七八糟。

后来我把约束处理改成“罚函数柔性约束”加上“可行性优先选择”。具体做法是:约束违反量乘一个很大的罚系数加到目标函数上,但只在非支配排序时起作用。我的经验是,罚系数从1e4逐渐涨到1e6,前期给算法留出探索空间,后期强制收敛到可行域。

5.2 Pareto前沿分布不均匀

早期版本外部档案删解逻辑很简单,谁拥挤距离小就删谁。但高维目标空间里,拥挤距离有时会失效,导致前沿两段密集、中间空虚。

改用自适应网格之后好了很多。网格数量设为10×10,密度大的网格里的解优先被删,leader选择也偏向稀疏网格。这样跑出来的前沿相对均匀。

5.3 收敛慢与早熟

灰狼算法的收敛速度和a的衰减曲线直接相关。我把a从线性改成余弦后,明显觉得迭代到80代左右就有比较像样的前沿,而原始线性a经常要跑到150代。建议种群数量取100到150,迭代次数取200以上。如果算力紧张,50个个体 + 150代也能出可接受的结果,只是前沿略粗糙。

另外一个容易被忽略的点是多目标优化里,“最优解”不是一个,所以评价指标建议看两个:Pareto前沿分布性(如间距指标)和收敛性(与参考前沿的接近程度)。只看单个折衷解看不出算法好坏。

5.4 Matlab环境与代码兼容问题

复现这套代码时,环境问题其实比算法本身更折磨人:

  • 版本建议:我用Matlab 2023b,推荐2023a及以上版本。老版本对脚本和实时编辑器的处理差别不大,但数组操作和绘图性能有差距。
  • 中文注释乱码:在Windows上默认编码是GBK,如果你把带中文注释的.m文件用UTF-8保存,偶尔打开会乱码。建议统一用Matlab编辑器“预设项-代码生成-文件编码”里选UTF-8。
  • 工作路径不要带中文:在中文路径下跑优化类脚本,偶尔会出现奇怪的读取错误和绘图字体问题,建议直接放到英文目录。
  • 矩阵维度不匹配:这是最常报的错。罪魁祸首往往是P_load、P_w、P_pv三个数组长度不是24,或者决策变量x的长度和你reshape时的维度对不上。我建议在目标函数第一行强制加断言CalendarYears不写了,直接加一句assert(length(P_load)==24)来排查。

5.5 常见问题速查表

问题现象可能原因解决办法
算法前期全是不可行解约束处理过严采用罚函数柔性约束,罚系数渐进增大
Pareto前沿明显偏向某个目标两个目标量纲相差大做归一化处理,或者用模糊隶属度法选折衷解
迭代后期前沿不再变好收敛因子设置不合理改用余弦非线性收敛因子
储能和V2G同时充放编码方式有缺陷使用正负号编码,禁止同充同放
跑完结果和论文对不上分时电价、参数取值不同核对所有参数,优先确认P_load和price维度

最后分享一个小技巧

我复现这类调度代码的习惯是:先跑一个“什么都没有”的算例——只有柴油机和大网,确认基础功率平衡和成本函数正确;然后加储能;再加V2G;最后才切换到改进算法对比。

这一步一步加模块的过程,能帮你把所有边界条件都验清楚。等哪一天你把Pareto前沿画出来、发现曲线光滑均匀、且调度计划符合“谷充峰放”的直觉时,这个项目就算真正拿下了。后面想扩展成考虑源荷预测不确定性、加入电转气、冷热电联供,都是在现有框架上做加法,核心算法不用动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询