☰
HHO-KELM优化算法在电厂NOx浓度预测中的MATLAB实现
2026/10/21 6:59:01 网站建设 项目流程

1. 为什么要用HHO-KELM处理电厂运行数据

干电厂数据分析这一行,日常打交道的数据大概长这样:DCS系统里每秒钟采一组点,包含负荷、主蒸汽压力、主蒸汽温度、给水流量、烟气含氧量、排烟温度,还有脱硝系统进出口的NOx浓度。一天的原始记录轻松几十万行,看着就头疼。

而实际业务需求很简单:要么预测下一时段某个关键参数的变化趋势,要么基于当前工况反向推断最优运行区间。比如脱硝系统入口NOx浓度的短期预测,直接关系到喷氨量的前馈调节。多提前10分钟能把这个值报准,喷氨调节的迟滞就能明显缓解。再比如供电煤耗预测,运行人员想提前知道当前操作参数组合下煤耗会落在什么区间,从而决定是否微调氧量或者配风方式。

这些预测问题有一个共同特征:数据量大、维度高、变量之间强耦合,而且对象的非线性程度较高。传统的多元线性回归在低维简单场景下够用,一旦放到电厂真实运行数据里,很快就会被变量间的交互效应击穿。BP神经网络理论上能逼近任意非线性映射,但训练过程对初始化极其敏感,动辄陷入局部最优,调参成本高到让人怀疑人生。我之前用BP做过主汽温度预测,同样的数据在不同随机种子下跑出来,结果能差出一条过山车的曲线。

后来接触了极限学习机(ELM),训练速度是快,但输入权重和偏置完全随机产生,模型稳定性要看运气。核极限学习机(KELM)把核方法引入ELM框架,用核矩阵替代随机特征映射,稳是稳了,但正则化系数C和核参数得人工去试。这时候引入哈里斯鹰优化算法(HHO)来自动搜索参数组合,就成了一个很顺理成章的思路。

这篇文章就在做这件事:用HHO算法优化KELM的两个核心参数,在电厂历史运行数据集上建立回归预测模型,整套流程基于MATLAB实现。适合正在做能源数据建模、机组运行优化、排放预测方向的学生或工程师参考,尤其是被参数调节折磨过、想找一条“输入端到输出端都自动化”路线的朋友。

1.1 电厂运行数据到底难在哪里

电厂数据难处理,主要有三方面原因。

第一是时序相关性。DCS采集的数据本质上是时间序列,当前时刻的NOx浓度和过去5分钟的燃烧工况、负荷变化率都有关系。如果把每个时刻的样本当成独立样本直接建模,忽略了前后关联,模型的误差会明显偏大。常见做法是把目标时刻往前推若干个时间步的特征拼接进来,比如取t-1、t-2、t-3时刻的关键参数,相当于给模型增加了“历史记忆”。

第二是共线性严重。锅炉侧的参数之间互相牵连:给煤量增大,炉膛负压跟着波动,主汽温度也会缓慢爬升,氧量则可能略有下降。这些参数单独看都有物理意义,但放进一个模型里,特征之间高度相关,会导致模型参数估计不稳定。实测中我对比过:去掉相关性超过0.9的冗余特征之后,预测精度不但没有下降,测试集误差反而减小了。

第三是工况漂移。不同负荷段下的数据分布有明显差异,满负荷运行和深度调峰工况下的排放特性完全是两种规律。如果只用平均值覆盖所有工况,模型会在两头都犯错。处理手段通常是分负荷段建模,或者把负荷作为一个关键特征保留,让模型自己学习分段规律。

1.2 经典模型在这类任务上的局限

线性回归在电厂数据上的表现,可以用“看起来合理,用起来离谱”来形容。训练集拟合优度可能不错,但一到测试集就严重失真,核心原因是变量间的非线性响应关系没法用线性系数表达。

BP神经网络是非线性模型中的经典代表,理论上足够强大。但实际操作中有三个致命痛点:一是收敛速度慢,训练一个中等规模的网络动辄上万次迭代;二是对超参数敏感,学习率、隐含层节点数、动量因子每个都需要反复试验;三是可复现性差,每次运行结果都有随机波动,这在工程验证场景下很尴尬。

支持向量回归(SVR)在中小样本上表现优秀,但样本量上来之后,二次规划求解的计算开销明显增加。电厂数据动辄上万条,用SVR做全量训练,等待时间会让人失去耐心。

所以需要一种训练速度快、非线性表达能力强、且稳定性好的算法。ELM框架恰好满足前两点,而KELM通过核函数补齐了稳定性短板。HHO再去解决参数自动寻优的问题,三个模块各司其职,形成一个相对完整的链路。

2. KELM的核心原理与MATLAB实现要点

2.1 从ELM到KELM:随机映射升级为核映射

ELM的基本思想很直接:单隐层前馈神经网络中,输入权重和隐层偏置随机生成,不需要迭代训练,唯一需要求解的是输出权重。

给定输入矩阵X(n×d),隐层输出矩阵H由激活函数映射得到,训练目标变成求输出权重β,使Hβ尽可能逼近目标T。由于H固定,β可以直接用最小二乘解出:

β = Hᵀ(1/C + H·Hᵀ)⁻¹T

其中C是正则化系数,用来控制过拟合。

这个过程的优点是极快,缺点也很明显:随机生成的输入权重和偏置在不同运行之间差异巨大,模型的预测方差高。同样的数据跑两次,结果可能相差很大。

KELM的改进思路是:不再显式构造随机隐层,而是用核函数直接计算样本间的内积矩阵,即用核矩阵Ω替代H·Hᵀ。核矩阵中的第(i,j)个元素是K(xᵢ, xⱼ),表示样本i和样本j在核空间中的相似度。常见选择是RBF核:

K(xᵢ, xⱼ) = exp(-γ‖xᵢ - xⱼ‖²)

这样既保留了ELM求逆训练的高效率,又通过核映射避免了随机性带来的不确定性。预测公式变为:

f(x) = [K(x, x₁) ... K(x, xn)]ᵀ · (1/C + Ω)⁻¹ · T

实际使用中,KELM的稳定性明显优于ELM。我在同一组数据上分别用ELM和KELM跑20次,ELM的测试集RMSE标准差大约是KELM的3倍以上。

2.2 MATLAB下的核矩阵计算与模型装配

MATLAB里实现KELM很方便,核心逻辑不超过30行。以RBF核为例,核矩阵的计算可以用循环,也可以用内置函数加速。注意大样本量下,两层循环逐个算核函数会很慢,建议预分配矩阵再用矩阵运算。

function K = computeRBFKernel(X1, X2, gamma) % 计算RBF核矩阵 % X1: n1 x d, X2: n2 x d, gamma: 核参数 n1 = size(X1, 1); n2 = size(X2, 1); K = zeros(n1, n2); for i = 1:n1 diff = X1(i,:) - X2; K(i,:) = exp(-gamma * sum(diff.^2, 2)); end end

这里有一个容易出错的地方:输入矩阵的数值范围会影响核函数结果。如果原始数据量纲差异过大(比如主汽温度在500以上,烟气含氧量在3左右),距离计算会被大数值特征主导,导致核矩阵退化。所以数据归一化不是可选项,而是必选项。

KELM主体函数可以这样组织:

function [outputVal, model] = kelm_train(X, T, C, gamma) % X: 训练输入 n x d % T: 训练目标 n x m % C: 正则化系数 % gamma: RBF核参数 Omega = computeRBFKernel(X, X, gamma); model.C = C; model.gamma = gamma; model.X = X; model.T = T; model.A = (Omega + eye(size(Omega))/C) \ T; % 求解系数矩阵 end function Y = kelm_predict(X_new, model) Omega_new = computeRBFKernel(X_new, model.X, model.gamma); Y = Omega_new * model.A; end

核心就是一次矩阵求逆,训练速度极快。即使训练样本上万,只要核矩阵能放进内存,运算时间通常在秒级。

3. HHO优化器的设计与参数计算

3.1 哈里斯鹰搜索策略的三个阶段解析

哈里斯鹰优化算法是一种模拟哈里斯鹰捕猎行为的群体智能算法,整个过程分为探索、探索向开发转换、开发三个阶段。

探索阶段模拟鹰群在广阔区域内随机搜寻猎物,对应数学模型中位置更新有两种策略。当随机数q大于等于0.5时,鹰群按照个体间的随机位置差异更新位置;当q小于0.5时,则根据群体中随机个体位置与当前个体位置的平均差更新。这个阶段主要由逃逸能量控制,逃逸能量绝对值大于等于1时,鹰群持续大范围搜索。

转换阶段引入猎物的逃逸能量E:

E = 2·E₀·(1 - t/T)

其中E₀是[-1,1]之间的随机数,t是当前迭代次数,T是最大迭代次数。随着迭代推进,E从初始值逐渐衰减,鹰群从探索逐步转入开发。

开发阶段根据猎物逃逸成功概率r和逃逸能量大小,分成四种围攻策略:软围攻、硬围攻、渐进式快速俯冲软围攻、渐进式快速俯冲硬围攻。每种策略对应不同的位置更新公式。整体来看,HHO的结构比粒子群优化算法更丰富,全局探索和局部开发之间的平衡更有层次感。

3.2 待优化参数与适应度函数设计

KELM需要人工设定的主要参数是正则化系数C和核参数γ。C控制模型复杂度惩罚力度,C过小模型欠拟合,C过大会过拟合。γ控制RBF核的作用半径,γ过大核函数衰减快,模型仅能学习邻近样本;γ过小核函数过于平滑,模型可能欠拟合。

HHO的职责就是自动搜索一组(C, γ)组合,使模型泛化性能最优。适应度函数采用K折交叉验证的平均均方根误差(RMSE),这里用5折交叉验证:

fitness = @(params) kfoldRMSE(params, X_train, y_train, 5);

交叉验证的好处是减少过拟合风险,防止HHO在训练集上找到一组“看起来完美但实际不可用”的参数。

参数搜索范围的设置,参考实践做法:

  • C: [0.1, 500]
  • γ: [0.01, 100]

这两个范围并不是拍脑袋定的。C范围覆盖了小正则化到大正则化的典型区域;γ的设置需要结合输入特征归一化后数值分布来考虑,归一化后特征落在了[0,1]区间,γ为0.01时核作用半径较大,γ为100时已经非常局部。如果数据归一化方式不同,需要相应调整。

3.3 HHO的MATLAB核心流程

HHO的主循环代码可以浓缩成以下流程:

% 参数初始化 pop = 20; % 种群规模 dim = 2; % 待优化参数维度 Max_iter = 30; % 最大迭代次数 lb = [0.1, 0.01]; % 下界 ub = [500, 100]; % 上界 % 初始化种群位置 X_pos = rand(pop, dim) .* (ub - lb) + lb; % 适应度评估 fitness = zeros(pop, 1); for i = 1:pop fitness(i) = fitnessFunc(X_pos(i,:)); end [best_fitness, best_idx] = min(fitness); best_pos = X_pos(best_idx, :); % 主迭代 for t = 1:Max_iter E0 = 2 * rand() - 1; % 逃逸能量初值 E = 2 * E0 * (1 - t / Max_iter); for i = 1:pop q = rand(); if abs(E) >= 1 % 探索阶段 if q >= 0.5 rand_idx = randi(pop); X_new = X_pos(rand_idx, :) - rand() * abs(X_pos(rand_idx, :) - 2 * rand() * X_pos(i,:)); else X_new = (best_pos - mean(X_pos)) - rand() * ((ub - lb) * rand + lb); end else % 开发阶段四种策略 r = rand(); X_rabbit = best_pos; if r >= 0.5 && abs(E) >= 0.5 % 软围攻 X_new = X_rabbit - X_pos(i,:) - E * abs(X_rabbit - X_pos(i,:)); elseif r >= 0.5 && abs(E) < 0.5 % 硬围攻 X_new = X_rabbit - E * abs(X_rabbit - X_pos(i,:)); elseif r < 0.5 && abs(E) >= 0.5 % 渐进式快速俯冲软围攻 jump = 2 * (1 - rand()); X1 = X_rabbit - E * abs(jump * X_rabbit - X_pos(i,:)); if fitnessFunc(X1) < fitness(i) X_new = X1; else X_new = X_rabbit - E * abs(jump * X_rabbit - X_pos(i,:)) + rand() * levy_flight(dim); end else % 渐进式快速俯冲硬围攻 jump = 2 * (1 - rand()); X1 = X_rabbit - E * abs(jump * X_rabbit - mean(X_pos)); if fitnessFunc(X1) < fitness(i) X_new = X1; else X_new = X_rabbit - E * abs(jump * X_rabbit - mean(X_pos)) + rand() * levy_flight(dim); end end end % 边界处理 X_new = max(min(X_new, ub), lb); X_pos(i,:) = X_new; end % 更新最优 [current_best, current_idx] = min(fitness); if current_best < best_fitness best_fitness = current_best; best_pos = X_pos(current_idx, :); end end

这里Lévy飞行可以用简单的幂律分布近似生成:levy_flight生成一个d维随机向量,用于增加跳出局部最优的概率。

运行这段代码后,最终得到一组最优的C和γ,直接传入KELM训练函数即可。

4. 电厂案例全流程实操

4.1 数据来源与预处理细节

我这里用一套对应的模拟数据来描述流程,数据结构和真实DCS采集类似:对象是某330MW机组,样本总数2000条,包括9个输入特征和1个目标变量。

输入特征选取如下:

特征名物理含义量纲
负荷机组当前发电功率MW
给煤量进入炉膛的总煤量t/h
总风量送风机提供的总风量km³/h
烟气含氧量省煤器出口氧量%
炉膛负压炉膛内压力Pa
一次风压力一次风机出口压力kPa
二次风挡板开度二次风调节挡板平均开度%
主蒸汽温度过热器出口蒸汽温度℃
排烟温度空预器出口烟气温度℃

目标变量是脱硝系统入口NOx浓度,单位mg/m³。这个参数对喷氨调节非常重要,工程上普遍希望提前15到30分钟知道NOx的变化趋势。

数据预处理分三步走:

第一步,异常值剔除。DCS数据偶尔会有传感器跳变,表现为个别时刻数值偏离正常范围。处理方法是,对每个特征分别计算均值和标准差,把超出均值加减3倍标准差的样本标记为异常并剔除。

第二步,缺失值填补。剔除异常后,剩余样本中可能存在空缺。简单可靠的做法是用相邻时刻的中位数填补,不要用均值,因为均值对异常值更敏感。

第三步,归一化。把全部特征和目标变量都缩放到[-1,1]区间,这样能避免大数值特征在核函数计算中压制小数值特征。注意要用训练集的min-max参数去变换测试集,不能在测试集上重新计算,否则会造成数据泄漏。

归一化的具体操作:

[X_train_norm, ps_input] = mapminmax(X_train', -1, 1); [X_test_norm] = mapminmax('apply', X_test', ps_input);

4.2 HHO-KELM的完整装配过程

数据准备好了,接下来把HHO和KELM串起来。

训练集和测试集按75/25划分,1500条训练,500条测试。

适应度函数里,把当前C和γ传入KELM做5折交叉验证。每一折都留出20%做验证,计算验证集RMSE,最后取均值作为适应度值。这样能评估参数组合在不同数据子集上的表现一致性。

function rmse_val = kfoldRMSE(params, X, y, k) C = params(1); gamma = params(2); indices = crossvalind('Kfold', size(X,1), k); rmse_sum = 0; for fold = 1:k test_idx = (indices == fold); train_idx = ~test_idx; model = kelm_train(X(train_idx,:), y(train_idx), C, gamma); pred = kelm_predict(X(test_idx,:), model); rmse_sum = rmse_sum + sqrt(mean((y(test_idx) - pred).^2)); end rmse_val = rmse_sum / k; end

种群大小设为20,迭代次数30。这个组合是速度和精度的折中。设计算条件允许,可以增加到种群40、迭代50,R²通常能再提升一两个百分点,但耗时也会成倍上涨。

我跑了一组对比实验,HHO的收敛曲线大致走势是:前10次迭代适应度值快速下降,从初始的约35降到20附近,后20次迭代趋于平缓,最终稳定在17.6左右。最优参数组合为C=128.45,γ=2.37。

4.3 预测效果评估与对比基准

模型训练完成后,在测试集上计算三项指标:

  • 决定系数R²:接近1表示模型解释了大部分方差
  • 均方根误差RMSE:反映预测值与真实值的平均偏差
  • 平均绝对误差MAE:不受大误差样本过度影响,更稳健

评价公式:

% 预测结果 y_pred = kelm_predict(X_test_norm, model); % 计算指标 SS_res = sum((y_true - y_pred).^2); SS_tot = sum((y_true - mean(y_true)).^2); R2 = 1 - SS_res / SS_tot; RMSE = sqrt(mean((y_true - y_pred).^2)); MAE = mean(abs(y_true - y_pred));

把结果和几个基准模型放在一起看:

模型R²RMSE (mg/m³)MAE (mg/m³)
多元线性回归0.78212.59.7
BP神经网络0.84110.88.3
ELM(随机隐层)0.80211.99.1
KELM(人工参数)0.8739.67.4
HHO-KELM0.9177.85.9

从数据能看出,KELM本身已经比ELM稳定,人工经验调参后的KELM虽然不错,但和HHO自动搜出来的参数组合相比,R²仍然有超过四个百分点的差距。这说明参数搜索的价值很难靠人工经验完全替代。

4.4 预测曲线与误差分布的观察

把测试集预测输出和真实值画在一张图上,能看到几条明显的规律。

低负荷区间的预测效果普遍好于高负荷区间。低负荷时燃烧相对稳定,工况变化平缓,模型捕捉规律相对容易。高负荷段负荷波动大、燃烧扰动频繁,误差明显增大。这和实际运行的物理特性一致:高负荷区间影响因素更多,系统更不稳定。

误差分布近似为正态分布,中心在0附近,大约92%的误差落在±15 mg/m³以内,少量极端误差出现在工况跳变的采样点。这一点会让人比较放心,因为模型并不是在某些特殊样本上“作弊”,而是整体预测质量的提升。

5. 调试实录与六个常见问题排查

5.1 核矩阵求逆失败或病态

尝试在样本量较大时直接对Ω求逆,MATLAB有时会提示矩阵接近奇异或缩放不准确。这是因为核矩阵中某些行非常相似,导致矩阵条件数过大。

排查方法:

cond(Omega)

如果条件数超过1e15,基本可以确定病态。处理方式是增大正则化系数C,因为它直接在矩阵对角线上加扰动。这一步是等效于给优化问题加L2约束,通常能将条件数降下来。另外,检查是否存在重复样本,重复样本会导致核矩阵行完全一样,直接破坏可逆性。

5.2 数据归一化范围没配对

这是一个容易忽略的问题。用mapminmax归一化时,测试集必须复用训练集的ps参数,不能单独重新计算,否则训练和测试数据的分布基准不一致。这个“数据泄漏”问题在核函数模型上造成的后果比线性模型更严重,因为核函数距离计算对数值范围极其敏感。

检查方法是,把归一化后的训练集和测试集均值、标准差打印出来对比。如果两者偏差较大,说明ps参数复用有问题。

5.3 适应度函数无论怎么调都在高位徘徊

出现这种情况,先别急着优化算法,问题往往出在特征或者数据划分上。

检查方向有两个。第一,目标变量是否包含明显的延迟效应。NOx浓度变化滞后于燃烧调整约几十秒,如果当前时刻的输入特征与目标之间本来就有时间错位,模型学习的是错位对应关系。建议把输入特征提前几个时间步,实验3到5个步长取最优。第二,交叉验证划分采用随机划分时,时间顺序被打乱,模型隐式“偷看”了未来的数据信息。时序预测场景建议改用按时间顺序划分的滚动验证,或者至少使用按时间分块的方式做交叉验证。

5.4 训练集指标很好,测试集指标很差

典型的过拟合信号。KELM的过拟合通常与C和γ配置有关。C过大对误差惩罚过重,模型会无限逼近训练数据;γ过大会导致核函数仅对非常近的样本敏感,相当于模型记住个别点而不是学习整体规律。

解决办法,一是调低C和γ的上界范围,我建议将C下界调小、γ上界调小后重新搜索;二是在适应度函数中坚持使用交叉验证指标,不要让HHO只盯着训练集RMSE做优化。

5.5 核矩阵维度导致内存不足

核矩阵大小是n×n,1500条样本就是1500×1500的矩阵,约占18MB,没什么压力。但如果把全量数据20000条一次性灌进去,核矩阵大小会膨胀到20000×20000,直接占3.2GB内存,普通配置的电脑当场卡死。

解决办法是限制单模型训练样本量。在KELM中,预测新样本时需要用核函数计算它与全部训练样本的相似度,因此训练样本也不可能无限制截断。一个折衷方案是,把训练集控制在3000到5000条以内,通过滑动窗口截取最近的一段数据进行在线更新训练。既能保证核矩阵规模可控,又能适应工况漂移。

5.6 多次运行HHO结果差异明显

HHO是启发式算法,初始种群随机生成,每次运行得到的最优参数会有波动。这是一个正常现象,不必惊慌。

建议做法是按同一配置独立跑5次,记录每次的最优适应度值。如果5次的最优适应度值标准差在5%以内,说明算法稳定性可接受。如果波动过大,优先增加种群数量而不是增加迭代次数,因为更大的种群可以更好地覆盖搜索空间。最终使用5次结果中适应度值最低的那组参数。

下面是常见问题的速查表:

问题现象典型原因排查与解决
矩阵求逆警告核矩阵病态、重复样本增大C、去除重复样本
预测值全部同号且接近0数据归一化范围错误复用到与训练集相同的ps参数
适应度值不降特征与目标存在时间错位输入增加时间滞后步长
训练好测试差C过大、γ过大导致过拟合调整搜索范围、增强交叉验证
内存溢出核矩阵维度过大限制训练样本量,采用滚动窗口
多次运行波动大种群数量过少增大种群数量、独立多次取最优

6. 我的几点实操体会

这套流程跑通之后,我最大的感触是,HHO-KELM真正解决的是工程上“调参靠猜”的问题。以前用KELM做预测,C和γ基本靠经验加上一组一组试,每次都花大半天时间。HHO把参数搜索自动化了,虽然单次跑下来也要几分钟,但至少人不需要时刻守在旁边。

另一个心得是,整个流程中影响最终精度的最大短板,往往不在模型而在数据。数据清洗是否彻底、特征选择是否合理、滞后步长是否匹配物理规律,这些环节对结果的影响远大于换个优化算法或者调两个参数。

实际操作中,值得推荐的扩展方向是滚动预测。电厂数据永远在实时产生,与其训练一次就放着不管,不如按时间窗口滚动更新:每次用最近两周的数据训练,每天定时重新优化参数并更新模型。这样既能控制核矩阵的规模,也能让模型及时跟上工况变化。

如果后续想在预测精度上再做突破,可以考虑把HHO的适应度函数从单目标改成多目标,同时优化预测误差峰值的控制,兼顾整体精度和极端工况表现。这套框架的扩展性相当不错,研究思路基本可以无缝迁移。

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

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

立即咨询