ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于遗传算法的风电混合储能容量优化配置及MATLAB实现

基于遗传算法的风电混合储能容量优化配置及MATLAB实现 我做了几年风电功率预测和储能配置的项目接触过不少用 MATLAB 做容量优化的需求其中“基于遗传算法的风电混合储能容量优化配置”这个方向问的人最多。原因也简单风电出力天生波动光靠单一储能削峰填谷要么贵得离谱要么响应速度跟不上混合储能能把这事干得更划算而容量怎么配、配多大又是个多变量、非线性、带约束的优化问题遗传算法这种启发式搜索方法非常合适。这篇文章我会把整套思路和 MATLAB 代码实现从头到尾拆开讲适合刚接触混合储能建模、或者正在写相关论文和毕业设计的同学参考当然有点优化算法基础再来读会更轻松。1. 从“为什么”说起风电配储的矛盾为何偏偏用混合储能加遗传算法1.1 风电出力波动这个问题为什么会逼到储能这一步风电出力的最大特点是“看天吃饭”。风速一会儿大一会儿小风机出力就跟着一会儿高一会儿低这种波动直接砸到电网上会造成频率偏差、电压闪变甚至触发保护装置动作。要平滑这些波动最常见的办法就是给风电场配储能风大的时候把多余的电存起来风小的时候再放出来相当于给风电出力加了个“阻尼”。但这里有个现实问题风速波动其实是由不同频率的成分叠加出来的。一阵强风过来是秒级到分钟级的快速波动一个天气过程变化可能是小时级甚至更长时间的慢速波动。如果只用一种储能去扛所有的波动就会很别扭。锂电池能量密度高可以长时间充放电但频繁的快速充放会加速老化超级电容功率密度大、响应快能扛住瞬间冲击但存不了多少电。单独用哪一种都不是最优解。混合储能就是把这两个搭档放到一起超级电容负责高频波动锂电池负责低频波动各干各的活。这样既能平滑出力又能延长锂电池寿命、降低综合成本。这个思路本身并不复杂复杂的是——锂电配多大容量、超容配多大功率才能让整个系统在满足波动平抑要求的前提下年度综合费用最低。1.2 混合储能不是拍脑袋是锂电池和超级电容的取舍很多人第一次接触混合储能时会觉得“是不是储能配得越大越好”。从平滑效果上看确实是这样但从经济性上说绝对不是。储能系统的投资成本几乎和额定功率、额定容量线性相关配大了初始投资和后续运维成本都压不住配小了又达不到抑制波动的效果考核不通过。所以容量配置本质上是一个权衡问题目标函数是年综合费用最小变量是锂电池的额定功率和额定容量、超级电容的额定功率和额定容量约束条件是功率平衡、储能SOC不越限、出力波动率不超过允许值等。这是一个典型的多变量、非线性优化问题。为什么用遗传算法来解因为这类问题的目标函数往往不光滑、不连续甚至可能因为约束条件形成很多局部极值点。传统的梯度下降类算法在这种地形上很容易陷进去出不来而枚举法在变量多、粒度细的时候计算量又大到无法接受。遗传算法是群体搜索天生不容易陷在某个局部区域而且它对目标函数的要求很低——不需要可导不需要连续只需要能算出一个适应度值就能迭代下去。1.3 为什么优化算法选遗传算法而不是线性规划或枚举我经常被问到能不能用 fmincon 或者 linprog 直接求如果目标函数和约束都是线性的确实可以。但混合储能容量配置里储能寿命损耗、功率分配策略、SOC约束这些环节经常会引入非线性甚至离散的逻辑判断这种情况下线性规划就捉襟见肘了。fmincon 对初值敏感初值给不好容易收敛到局部最优。遗传算法在这种工程场景里有三个天然优势第一它不要求目标函数可导适应度函数里哪怕塞了一个查表逻辑也能跑第二它是种群并行搜索一次运行能同时探索解空间里的多个区域全局搜索能力强第三它对离散变量和连续变量的混合问题支持得很自然编码层面就能把额定功率、额定容量这些变量统一处理。当然遗传算法也有它的毛病收敛速度相对慢、参数敏感、早熟收敛。后面我会专门讲这些坑怎么排查。但总的来说在“维度不高、约束复杂、非线性强”的容量配置场景里遗传算法是一个非常稳妥的选择。2. 模型设计把“配置多少个电池”这件事翻译成数学语言2.1 风电出力数据怎么来从实测文件到可用曲线做容量优化之前第一步不是写遗传算法而是把风电出力数据准备好。数据来源一般有两种一是风电场SCADA系统导出的实际出力数据二是用风速数据加功率曲线仿真生成。数据的时间分辨率很关键如果目标是把秒级波动也压下去建议用秒级或分钟级数据如果是小时级能量管理层面的配置用15分钟或1小时分辨率的数据就够了。我习惯的做法是先把数据读进 MATLAB然后做一次滤波区分高低频这一步直接决定了后面功率分配的效果。实测数据往往带噪声要先做简单的数据清洗比如剔除停机时段、处理越限值再插值成统一的时间序列。data readmatrix(wind_power.csv); t data(:, 1); % 时间点单位 min P_wind data(:, 2); % 风电出力单位 kW % 简单清洗把负值、突刺替换为相邻均值 P_wind(P_wind 0) 0; for i 2 : length(P_wind) - 1 if abs(P_wind(i) - P_wind(i-1)) 0.5 * max(P_wind) P_wind(i) (P_wind(i-1) P_wind(i1)) / 2; end end清洗完数据后可以先用 plot 看一眼出力曲线确认波动的幅度和频率特征。如果数据本身的波动就不明显后面做平滑的效果会很难看这种情况要优先检查数据源。2.2 混合储能的运行策略谁负责峰谁负责谷功率分配策略是整个模型里最容易讲不清又最容易出错的一环。它要回答的问题是风电出力需要补偿的功率差额到底让锂电池出多少、超级电容出多少。常规做法是用低通滤波把“需要补偿的功率”拆成高频和低频两路。风电实际出力 P_wind 经过滤波后得到一个平滑目标值 P_target二者的差值就是需要储能补偿的功率 P_comp。把这个差值再过一次高通滤波器高频分量给超级电容剩下的低频分量给锂电池。% 低通滤波得到平滑后的目标出力 alpha 0.1; % 滤波系数决定了平滑程度 P_target zeros(size(P_wind)); P_target(1) P_wind(1); for i 2 : length(P_wind) P_target(i) alpha * P_wind(i) (1 - alpha) * P_target(i-1); end P_comp P_wind - P_target; % 储能总补偿功率 P_sc highpass(P_comp, 0.01, 1/60); % 超级电容承担高频分量 P_bat P_comp - P_sc; % 锂电池承担低频分量这里的滤波系数 alpha 是个很敏感的参数它直接决定了 P_target 的平滑程度。alpha 越小目标曲线越平滑储能需要补偿的功率就越大配置出来的容量也越大alpha 越大目标曲线越接近原始出力储能配置变小但波动平抑效果可能不达标。工程上一般结合并网波动率要求反推 alpha而不是拍脑袋取数。功率分配完以后还有一步不能漏要对 P_sc 和 P_bat 做 SOC 状态模拟。储能电池不是理想元件充进去多少电、放出多少电SOC都会变化而且有上下限。运行策略还要考虑 SOC 越限时的修正否则后面优化出来的容量会过于乐观。2.3 目标函数和约束条件怎么建模才算合理容量配置的目标函数在国内工程和学术文献里最常见的写法是“年综合费用最小”。我习惯把年综合费用拆成四项储能系统的等年值投资成本、年运行维护成本、缺电惩罚费用、弃风惩罚费用。投资成本这块要特别注意“功率成本”和“容量成本”是两笔钱。功率成本对应变流器、PCS这些设备单位是元/kW容量成本对应电池本体单位是元/kWh。锂电池和超级电容各自的功率成本、容量成本不一样寿命也不一样所以要做等年值折算。% 变量锂电额定功率、锂电额定容量、超容额定功率、超容额定容量 % x [P_bat_r, E_bat_r, P_sc_r, E_sc_r] C_inv (k_bat_p * x(1) k_bat_e * x(2)) * CRF_bat ... (k_sc_p * x(3) k_sc_e * x(4)) * CRF_sc; C_om k_om_bat * x(1) k_om_sc * x(3); C_penalty k_loss * sum(P_loss) k_curtail * sum(P_curtail); C_total C_inv C_om C_penalty;其中 CRF 是资金回收系数等于 rate * (1rate)^n / ((1rate)^n - 1)rate 是折现率n 是设备寿命。电池寿命一般按充放电循环次数折算成年限超级电容寿命更长所以要分开算。约束条件方面核心的几条是任意时刻功率平衡风电出力加储能放电等于负荷或并网功率、储能SOC在允许区间内、储能实际充放电功率不超过额定值、并网波动率不超过限值。处理这些约束的最实用方式是“罚函数法”把约束违反量放大后加进目标函数里。这样遗传算法在寻优时不满足约束的解会获得很差的适应度自然被淘汰。3. MATLAB 代码实现遗传算法主循环与核心模块编写3.1 主程序结构个体-适应度-进化遗传算法的 MATLAB 实现说难不难说简单也不简单。如果只是调 ga全局优化工具箱几条命令就能跑但这样你很难看清楚每一代到底发生了什么出了问题也没法调试。所以我建议自己写一遍主循环把选择、交叉、变异、约束处理都摆在明面上这样既方便改论文的算法细节也方便排查问题。我常用的主程序结构是这样的%% 初始化 pop_size 60; % 种群规模 max_gen 120; % 最大迭代代数 n_var 4; % 决策变量数量 lb [500, 1000, 200, 50]; % 下限锂电功率、锂电容量、超容功率、超容容量 ub [5000, 20000, 2000, 800]; % 随机生成初始种群 pop repmat(lb, pop_size, 1) rand(pop_size, n_var) .* repmat(ub - lb, pop_size, 1); %% 进化主循环 for gen 1 : max_gen % 计算适应度 fitness zeros(pop_size, 1); for i 1 : pop_size fitness(i) cal_fitness(pop(i, :)); end % 选择锦标赛 new_pop selection(pop, fitness, pop_size); % 交叉 new_pop crossover(new_pop, 0.85); % 变异 new_pop mutation(new_pop, 0.1, lb, ub); % 精英保留 [~, best_idx] min(fitness); new_pop(1, :) pop(best_idx, :); pop new_pop; % 记录最优值 [best_fit(gen), best_gen_idx] min(fitness); best_solution(gen, :) pop(best_gen_idx, :); end这个结构里最核心的函数是 cal_fitness它把决策变量解码成锂电和超容的功率、容量再跑一遍全时段的功率分配和SOC模拟最后返回总费用。这个函数每代要被调用几十次所以它的计算效率直接决定整个程序的运行时间。3.2 关键实现细节适应度函数和约束惩罚适应度函数是整个遗传算法的“裁判员”。如果裁判判得不合理算法再精巧也白搭。在我的实现里cal_fitness 做四件事解码变量根据滤波策略算 P_target逐时刻模拟储能充放电并统计SOC越限、缺电、弃风惩罚计算年综合费用并加上罚函数。function cost cal_fitness(x) % 解码 P_bat_r x(1); E_bat_r x(2); P_sc_r x(3); E_sc_r x(4); % 全局变量P_wind, alpha, 成本系数等 global P_wind alpha ... % 计算目标出力 P_target filter_lowpass(P_wind, alpha); P_comp P_wind - P_target; % 功率分配 P_sc highpass(P_comp, 0.01, 1/60); P_bat P_comp - P_sc; % 约束储能功率越限统计 P_bat_penalty sum(max(abs(P_bat) - P_bat_r, 0)); P_sc_penalty sum(max(abs(P_sc) - P_sc_r, 0)); % SOC模拟 [SOC_bat, SOC_sc] simulate_soc(P_bat, P_sc, E_bat_r, E_sc_r); SOC_penalty sum(max(SOC_bat - 0.9, 0)) sum(max(0.1 - SOC_bat, 0)) ... sum(max(SOC_sc - 0.95, 0)) sum(max(0.05 - SOC_sc, 0)); % 成本 C_inv ...; C_om ...; C_penalty ...; % 总目标费用 约束罚函数 M 1e6; % 惩罚系数 cost C_inv C_om C_penalty M * (P_bat_penalty P_sc_penalty SOC_penalty); end有一个很容易被忽略的细节SOC 模拟里电池的充放电效率不是 100%。充进去 1 kWh实际只能放出来大约 0.9 kWh剩下的变成热量损耗了。如果忽略这一条优化的结果会偏小实际运行时会发现储能不够用。所以仿真时我会把锂电池效率按 0.9、超级电容按 0.95 处理。3.3 参数怎么调种群规模、交叉率、变异率这些数字背后有门道遗传算法的参数设置没有万能公式但有一些经验范围可以参考。种群太小容易早熟我一般取 50~100迭代代数取决于问题的复杂度容量配置这种4变量问题100~200代基本能收敛交叉率太高会破坏优秀个体太低会搜索缓慢0.7~0.9 是比较常用的区间变异率一般取 0.05~0.2如果发现陷入局部最优可以适当调大变异率。这里有个实操技巧不要只关注收敛曲线是否下降还要关注种群多样性。最简单的方式是每一代存下所有个体的适应度然后看中位数和最小值的差。如果中位数和最小值越来越接近说明种群多样性在丢失这时候即使最优值没变也要警惕早熟收敛。自适应策略是我比较推荐的做法进化初期交叉率大、变异率大保证充分探索进化后期交叉率小、变异率小保证精细开发。用 MATLAB 写这个不复杂就是在每一代根据当前的代数比例动态更新一下参数。4. 常见问题与仿真排错实录我把能踩的坑都踩了一遍4.1 过早收敛种群里全是同一个解这个问题我一开始做遗传算法时几乎必踩。表现为进化不到20代适应度曲线就平了所有个体的目标函数值几乎相等但明显不是最优解随便换个初值跑结果都不一样。排查思路分三步。第一步看是不是选择压力太大锦标赛选择的竞争规模设得过大导致优秀个体迅速霸占整个种群。把 tournament_size 从 3 降到 2 通常有效。第二步看变异率变异率太低的时候新基因很难引入建议调高到 0.15 以上或者用自适应变异让变异率在停滞时自动升高。第三步也是最容易被忽略的精英保留策略如果直接把最优个体复制进下一代这个个体一直不被淘汰会让种群多样性快速下降。解决办法是精英保留只保留1~2个个体并且对精英个体做一次轻微的随机扰动相当于给最优解加一点“抖动”。4.2 约束条件老是违反解出来功率都不平衡适应度函数里加了罚函数但优化出来的结果依然在功率平衡上对不上这种问题大概率出在罚函数系数上。罚函数系数 M 如果取得太小约束违反的代价低于省钱带来的收益遗传算法就会理直气壮地给出一个功率越限但费用很低的“假最优解”M 取得太大又会让目标函数的值域变得特别大影响选择压力分布。我的做法是动态罚函数先把目标费用计算出来然后让惩罚量级等于目标费用量级的 10 到 100 倍。比如费用大概在 10^5 量级罚函数系数就取 10^6。这样约束违反几乎没有性价比同时适应度值的分布也不会被罚函数彻底压扁。还有一种情况是 SOC 模拟本身写错了。比如充放电时 SOC 更新方向搞反、效率没有参与运算导致模拟出来的 SOC 根本不对。这种 bug 用曲线对比最容易发现——把 SOC 曲线画出来跟功率曲线对照放电时段 SOC 应该下降充电时段 SOC 应该上升对不上就是程序的问题。4.3 运行时间太长一个工程算一整晚容量配置的仿真模型如果每小时段逐点计算一个含 8760 小时数据的算例每算一次适应度就要跑 8760 次循环种群 60 个个体、迭代 100 代就是 5000 多万次循环MATLAB 的 for 循环这么跑会非常慢。我做过的有效加速手段有三条。第一全局变量和子函数调用开销很大把核心的 SOC 模拟改成矩阵运算或向量化代码消掉内层 for 循环提速非常明显。第二如果只是做优化先用典型日数据代替全年数据比如每个季节选一个典型日、再乘上对应的天数权重计算量立刻降两个数量级结果和全年数据基本一致。第三把 parfor 用起来适应度函数计算天然是每个个体独立的适合并行。4.4 结果与预期不符容量配置出来数值离谱怎么定位有时候优化结果差得很离谱比如锂电池额定功率配出来等于上限或者超容容量配出来只有下限值。这时候先别急着调算法参数回头检查模型更重要。我碰到过一种情况是滤波系数 alpha 设得太小导致 P_comp 里高频分量占了大头于是优化器拼命堆超级电容锂电池几乎闲置另一种情况是数据里有大段连续零出力时段这些时段储能根本不需要动作导致优化的容量整体偏小。定位问题的一个很实用的做法是把最优解拿出来重跑一遍仿真画出“原始出力-目标出力-锂电功率-超容功率-SOC”这种多子图的对比图一眼就能看出功率分配是否合理、SOC有没有频繁触界。只要这个图是合理的再往下查遗传算法的参数才有意义。写在最后一些我个人的实操体会做这类容量配置项目最大的体会是不要把遗传算法当成一个“黑盒神器”它本质上只是一个搜索工具模型建得对不对、约束到位不到位才决定结果靠不靠谱。我通常会先假设储能容量给得足够大跑一遍功率分配和SOC模拟看看在“理想配置”下系统能不能满足波动率约束约束满足后再交给遗传算法去缩小容量、降低成本。这一步“验证上限”能省掉后面大量无意义的调参时间。另外一个建议是做室内仿真之前尽量找一组公开或实测的风电数据先固定所有成本系数和约束参数只改变滤波系数 alpha观察容量配置结果的变化趋势。这组灵敏度分析做出来基本就能确认模型行为是合理的再谈具体的最优解才踏实。这种配置问题后续还可以继续扩展比如加入蓄电池寿命衰减模型、考虑分时电价、或者用多目标遗传算法同时优化费用和波动率都是可以深入的方向。
返回列表