ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于PSO的风能制氢系统优化与Matlab实现

基于PSO的风能制氢系统优化与Matlab实现 风能制氢这两年确实是个热门方向但不少人一上来就急着跑仿真结果卡在“系统怎么搭建”和“优化目标怎么定”上。我前段时间刚好把一个基于粒子群算法PSO的风能制氢系统优化项目完整梳理了一遍用Matlab从风速模拟一路做到PSO寻优最终得到了一套还能用的功率分配方案。这篇文章就把整个设计思路、建模过程、关键代码和踩过的坑整理出来给准备入坑这个方向的同学做参考。1. 项目的核心问题风能制氢系统里到底要优化什么1.1 系统架构拆解风能制氢系统不是“风机插个电”那么简单。一套完整的系统通常包含风力发电机组、整流变换装置、电解水制氢设备、氢气储运单元以及配套的能量管理模块。风电输出的电能经过AC/DC变换后供应给电解槽电解槽将水分解为氢气和氧气氢气再经压缩储存或直接输送。我做的这个项目里风机额定功率选了50 kW这个等级不是很大但做算法验证已经足够。电解槽额定功率定在30 kW采用PEM电解槽模型效率特性曲线按实测数据做了简化拟合。系统里还加了一个小容量的蓄电池作为缓冲用来吸收风机出力短时波动。这里要强调的是优化不是说要把风机功率“调大调小”就能解决的真正的问题是风能天生随机电解槽又对输入功率范围有硬性要求两者之间需要一个动态的功率分配策略来解决。1.2 优化目标和数学表达我在项目中把优化目标定成“在满足系统运行约束的前提下最大化系统在单位时间内的氢气产量”。听起来很简单但展开后涉及三部分风机可用功率、电解槽运行状态、储能单元的充放电决策。形式化地写目标函数可以表达为max f Σ H₂产量其中 H₂(k) η_elec * P_elec(k) * Δt / LHV这里的 P_elec(k) 就是我真正要寻优的变量——每个调度时段内分配给电解槽的电功率。P_elec 不能随便取它受限于风机当前实际出力、电解槽上下限功率约束、蓄电池SOC范围约束以及系统功率平衡方程。这意味着决策变量本身不是单个数值而是一组时间序列。我用的是长度为96的决策向量对应一天96个调度时段每15分钟一个每个元素代表该时段电解槽的输入功率。PSO算法要做的就是在一个96维的空间里搜索找到一组P_elec序列让总产氢量最大。1.3 为什么要选粒子群算法这个问题的目标函数是非线性的而且伴随大量约束电网侧的常规数学规划方法做起来很容易出现“维度爆炸”或者初始化困难。而PSO的逻辑特别直观不需要求梯度对目标函数的连续性没有硬性要求甚至不用写出精确解析表达式只要有一个能算适应度值的函数就可以直接开始寻优。这对于我们这种“先有工程模型再找最优解”的场景非常合适。我后面也试过遗传算法对比收敛精度其实差不多但PSO的参数少代码量小调参与收敛速度快这在实际项目里省了不少时间。2. PSO算法原理与在风能制氢场景里的落地思路2.1 粒子群算法的核心逻辑粒子群算法模拟的是鸟群觅食行为。一群鸟在空间里搜寻食物每只鸟知道自己的当前位置和已经发现的最好位置同时通过群体协作知道整个群体目前发现的最好位置然后依靠这两个信息调整自己的飞行方向和速度。在算法中的数学表达是v_i(t1) w * v_i(t) c1 * r1 * (pbest_i - x_i(t)) c2 * r2 * (gbest - x_i(t))x_i(t1) x_i(t) v_i(t1)这里的惯性权重w控制全局与局部搜索的平衡c1和c2是学习因子r1和r2是0到1的随机数。我实际编码时采用线性递减w的操作从0.9逐步降到0.4前期保持全局探索能力后期加强收敛这一点对于高维决策空间特别重要。2.2 决策变量编码和适应度函数设计在风能制氢这个项目里粒子位置x_i就是一组“候选的P_elec时间序列”维度是96维。每个粒子代表一套完整的当日功率分配方案。粒子的速度v_i则对应每个维度的调整步长。适应度函数fitness function是整个算法的灵魂。我设计了三个核心步骤读取粒子给出的P_elec序列逐时段计算风机可提供功率、电解槽实际运行功率、蓄电池SOC变化累加整个调度周期内的氢气产量作为适应度值返回。这里有一个容易被忽略的技术细节粒子群算法本身是做最小化的通常题目都写成 min f但我们要最大化氢产量。最简单粗暴的做法是取负值——用 -H₂总产量 作为适应度函数寻优结果一致且省事。2.3 约束处理的工程化做法96维变量直接搜很容易撞出不可行解比如电解槽功率超出额定范围或蓄电池SOC超出0.2~0.9区间。约束处理我用了两个办法叠加第一是边界吸收boundary absorption也就是粒子位置更新后如果超出变量的上下限就直接拉回边界值。这对电解槽这种有明确运行范围限制的设备非常合适——功率低于下限会停机高于上限会过载损坏。第二是罚函数法。蓄电池SOC约束和系统功率平衡约束我在适应度函数里加了惩罚项。当SOC越界或功率不平衡的程度越大惩罚值越大粒子的适应度越差。我实测下来罚函数系数设置成适应度正常量级的2~3倍收敛效果最好。太小了约束形同虚设太大了粒子会被“罚死”多样性不足。3. 基于Matlab的系统建模与PSO优化实现3.1 风速模型与风机出力模拟风速的随机性我用Weibull分布模拟。Matlab里创建风速时间序列可以直接用自带函数wblrnd给定尺度参数和形状参数。以国内某风资源中等水平地区为例可取尺度参数8形状参数2再用实际数据的均值校验一下。风速模拟出来后要让风速转成风机输出功率。标准的风力机功率特性曲线分为三个区间低于切入风速时输出为零切入风速到额定风速之间输出随风速按三次方关系增长风速超过额定值后输出维持在额定功率再往上达到切出风速时停机保护。具体的Matlab函数我写成这样function P_wt wind_turbine_power(v, v_in, v_rated, v_out, P_rated) % v_in: 切入风速 m/s % v_rated: 额定风速 m/s % v_out: 切出风速 m/s % P_rated: 额定功率 kW P_wt zeros(size(v)); for i 1:length(v) if v(i) v_in || v(i) v_out P_wt(i) 0; elseif v(i) v_rated P_wt(i) P_rated; else P_wt(i) P_rated * (v(i)^3 - v_in^3) / (v_rated^3 - v_in^3); end end P_wt(P_wt P_rated) P_rated; end我在整个96时段系统中逐时段调用这个函数加上尾流损耗系数和机械效率因素最终得到一条风机可用功率曲线。这个曲线就是后面所有优化分配的能量来源边界。3.2 电解槽模型与效率拟合电解槽的效率不是固定值它随输入功率不同而不同。实际工程中PEM电解槽在额定功率附近效率最高低功率运行时效率明显下降。简化建模时我采用了二次函数拟合效率曲线的方式η_elec(P_elec) -0.0002 * P_elec^2 0.02 * P_elec 0.45这个函数在30 kW额定功率附近算出的效率约在70%左右低功率时会掉到50%以下符合文献里的趋势。电解槽制氢量计算用氢气的低位热值LHV取33.33 kWh/kg换算n_H2 (P_elec * eta_elec) / LHV; % kg/h需要注意的是这里的n_H2是每个时段的氢产量。对96时段模型来说每个时段时长是0.25小时15分钟所以最终累加时要乘上0.25。3.3 PSO主循环实现PSO的核心循环我用Matlab写了一份结构大概如下function [gbest, gbest_fitness, convergence_curve] PSO_optimize(fitness_func, dim, lb, ub) n_particles 40; max_iter 200; w_max 0.9; w_min 0.4; c1 2.0; c2 2.0; % 初始化粒子位置和速度 x rand(n_particles, dim) .* (ub - lb) lb; v zeros(n_particles, dim); % 初始化个体最优和全局最优 pbest x; pbest_fitness inf(n_particles, 1); gbest zeros(1, dim); gbest_fitness inf; convergence_curve zeros(max_iter, 1); for iter 1:max_iter % 线性递减惯性权重 w w_max - (w_max - w_min) * (iter / max_iter); for i 1:n_particles fitness fitness_func(x(i, :)); if fitness pbest_fitness(i) pbest_fitness(i) fitness; pbest(i, :) x(i, :); end end [min_pbest, idx] min(pbest_fitness); if min_pbest gbest_fitness gbest_fitness min_pbest; gbest pbest(idx, :); end % 更新速度和位置 for i 1:n_particles r1 rand(1, dim); r2 rand(1, dim); v(i, :) w * v(i, :) ... c1 * r1 .* (pbest(i, :) - x(i, :)) ... c2 * r2 .* (gbest - x(i, :)); x(i, :) x(i, :) v(i, :); % 边界吸收 x(i, :) max(x(i, :), lb); x(i, :) min(x(i, :), ub); end convergence_curve(iter) gbest_fitness; end end这个代码的精髓在于注释里的几个小点尤其是边界吸收的处理不是用“边界重生成随机数”而是用“拉回边界值”。原因很简单重生成会破坏粒子当前位置与历史最优之间的连续性导致收敛震荡而拉回边界能保证粒子始终处于可行域边缘对电解槽这类设备来说贴着上限运行往往是更优解。3.4 主程序串联与仿真流程主程序的流程我是按“初始化-预测-优化-回代”来组织的。因为风机功率是随机序列所以我在优化开始前就固定生成了当天的风速曲线和风机出力序列。如果不固定每次适应度计算都会重新生成风速导致同一个粒子的适应度每次不一样PSO根本没法收敛。主程序关键步骤% 1. 生成风速曲线 t 0:15:(96*15-1); % 15分钟间隔 v_wind wblrnd(8, 2, 96, 1); v_wind max(v_wind, 0); % 2. 计算风机出力 P_wt wind_turbine_power(v_wind, 3, 12, 25, 50); % 3. 定义适应度函数句柄 fitness_func (x) obj_fun(x, P_wt, P_elec_min, P_elec_max, SOC_min, SOC_max, LHV); % 4. PSO优化 lb 0 * ones(1, 96); ub 30 * ones(1, 96); % 电解槽最大功率30kW [gbest, gbest_fit, curve] PSO_optimize(fitness_func, 96, lb, ub); % 5. 结果提取 P_opt reshape(gbest, 96, 1); total_H2 -gbest_fit;这里要特别留意的就是适应度函数obj_fun内部的状态约束判断。电池的SOC是逐时段累加更新出来的如果后续某一时刻越界整条粒子路径作废。我之前就因为把SOC判断写错在循环里面导致算法跑出来全都是不可行解适应度曲线看着在下降实际上算法在瞎找。后面我把SOC约束放在每个时段更新结束后即时判断、即时惩罚问题就解决了。4. 仿真结果与关键性能分析4.1 收敛过程与寻优性能PSO跑完之后我观察了几组重要输出。常规情况下40个粒子、200次迭代大概在40~60代就会出现明显的收敛趋势。迭代初期的全局搜索阶段适应度下降很快后期逐步平缓最终稳定在一个最优值附近。收敛曲线的样子大概是前20代急剧下降中间30~80代缓慢爬坡下降80代后基本水平。这个形态代表算法运行正常没有出现“早熟”也没有出现“发散”。我尝试过把粒子数量提升到80个收敛精度只提升了不到0.5%但单次运行时间几乎翻倍。考虑到工程实际中对“够用就好”的追求40个粒子已经完全够用。4.2 优化结果的核心收益与普通“满额分配”策略即风机来多少功率就全给电解槽不管电解槽是否处于最优效率区间相比PSO优化后的方案在氢气总产量上的提升幅度约在6%~11%之间。具体数值取决于当天的风速波动情况风速波动越大优化带来的收益越明显。原因是显然的电解槽在低功率段的效率衰减非常严重把有限的电能优先分配给电解槽的高效运行区间整体产氢收益更大。而PSO本质上就是为每个时段找到一个“是否开启电解槽、开多高功率”的开关策略。此外蓄电池的有效利用也带来了额外收益。优化方案会在风速高峰时段给电池充电在风速低谷时段释放电量供电解槽运行相当于把时间维度上的能量做了重新平滑分配。这个调度逻辑靠传统经验规则做很费劲但在PSO框架里只是多了一组约束而已成本几乎为零。4.3 极端风速条件的鲁棒性我还特意测试了一个高波动风速场景一小时内的风速从6 m/s迅速升到14 m/s再回落到4 m/s。结果显示PSO优化方案依然能维持蓄电池SOC在安全范围内电解槽功率也始终保持在允许区间内没有出现越限停机。这一点对于风电接入的实际工程特别关键因为并网考核对于功率波动有明确要求越限次数多了会影响整个系统的并网许可。不过要说明的一点是PSO属于元启发式算法每次运行结果有一定随机性。我用同一组风速数据跑了10次最优目标值的标准差大约在1.2%左右基本稳定可以接受。如果要求更高重复性建议固定随机数种子或者采用多种群并行PSO。5. 常见问题与实操心法5.1 粒子群“早熟收敛”怎么办早熟收敛是PSO最常见的毛病具体表现是适应度曲线过早进入平台期且最终结果明显偏离理论最优。我的排查顺序是先看决策变量初始范围是否过窄如果初始解覆盖不到较优区域后续搜索很难飞出去。建议先用随机生成的解集合做一次预筛看看目标函数分布。再看惯性权重是否下降太快如果线性递减的斜率太陡后期粒子速度趋于零就失去了探索能力。可以改用正弦波动或自适应调整。最后考虑引入“变异算子”每迭代一定次数后随机重置少量粒子的位置增加种群多样性。5.2 约束惩罚项怎么设计才好调罚函数系数设置很有讲究。我试验过固定大惩罚和随迭代递增的惩罚最后发现随迭代递增的效果更好。前期惩罚系数小让粒子尽量探索可行域之外的空间找到潜在的优良区域后期惩罚系数大把粒子逼回可行解空间内。具体的实现方法是在适应度函数里加一个scale系数它随时间逐步增大penalty_scale 1 iter / max_iter * 10; fitness -total_H2 penalty_scale * (soc_penalty balance_penalty);这个做法在文献里叫“动态惩罚函数”原理不会太复杂但对解决高维约束问题非常有效大家可以直接照抄。5.3 算得慢、跑不动的原因排查如果你的Matlab代码跑一次PSO要十分钟以上多半不是算法复杂度问题而是目标函数里有重复计算。常见的坑有两个第一个是在适应度函数内部又去重新生成随机风速。这个我之前提到过一定要在PSO外面固定风速序列否则每次适应度不同算法白跑。第二个是在循环里用了太慢的矩阵复制或全局变量传递。Matlab对循环内的动态数组扩展优化不好建议所有数组在循环前预先分配好尺寸比如zeros(n_particles, dim)。这个小小的改动能带来好几倍的加速。5.4 氢气产量结果不太理想时先检查边界有两次我发现优化后的总产氢量还不如简单策略数据一查是电解槽功率上下限设置错了。电解槽最低运行功率我写成了0但实际设备在功率低于额定功率的20%时已经无法维持稳定电解反应强制运行反而会缩短寿命。把下限从0改成6 kW后结果立刻恢复正常粒子也不会再浪费算力在大片不可行区域上搜索了。真实的设备边界条件一定要在建模阶段核实清楚建议直接向设备厂家要运行范围数据不要自己拍脑袋写数字。6. 这套方案可以怎么继续扩展风能制氢系统的优化方向远不止“产氢量最大化”这一个目标。我把这套PSO框架跑通之后很快发现只要调整目标函数和决策变量就能适应更多场景。思路一把目标换成成本最小化。在目标函数里加入电解槽启停损耗、蓄电池循环老化成本、购电成本每个时段的电费价格不同PSO依旧能自动找出“低谷期多储氢、高峰期少运行”的时序策略。思路二把单一风电场扩展成风氢储联合系统。决策变量增加储能SOC和制氢储能双通道的分配比例PSO的维度从96升到192计算时间虽然上去不少但框架不需要重新设计。思路三引入风电功率预测数据。将预测的置信区间作为约束条件让优化结果对风速预测误差更有鲁棒性。这个方向在工程落地时会越来越重要因为电网对制氢系统调度接口的要求是“提前申报曲线”不是事后追补。我个人的体会是PSO在这个项目里最大的优势不是“算得快”而是“改得起”。目标函数一变、约束条件一换只要适应度函数的接口写好粒子群算法本身的逻辑几乎不用动。这比传统的动态规划或者混合整数规划在工程迭代中灵活得多。如果你后续打算做更复杂的综合能源系统优化从PSO这个框架起步绝对是个性价比很高的选择。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进