☰
数据驱动的GRNN-RBFNN-ILC轨迹跟踪控制算法
2026/10/22 14:17:39 网站建设 项目流程

做控制这行的人应该都有体会,凡是碰到“重复运动”的场景——机械臂来回搬运、机床重复走刀、无人机绕固定航迹飞——绕不开的一个问题是:系统模型拿不准,怎么把轨迹跟踪误差压下去。经典迭代学习控制(ILC)的思路很简单:既然每次干的活儿都一样,那我就把上一次的误差留下来,叠加到下一次的控制量里,跑几轮之后误差自然会变小。这个思路在模型已知的线性系统上很好用,但一旦遇到“未知SISO非线性系统”,纯靠数学推导去设计学习增益就很被动了。

标题里的这个项目——GRNN-RBFNN-ILC算法——就是冲着这个痛点去的。它用广义回归神经网络(GRNN)和径向基函数神经网络(RBFNN)去替代传统ILC里那些需要“知道模型”才能算出来的东西,一个负责对系统动态做局部建模和预测,一个负责在线补偿未知非线性项,让迭代学习控制不再依赖精确模型,直接靠数据驱动把轨迹跟踪任务跑出来。整篇博文会围绕这套架构的拆解思路、Matlab仿真实现、以及我实际调参时踩过的坑展开,适合正在做智能控制方向研究、或者搞运动控制平台想提升重复跟踪精度的人参考。

1. 整体设计与思路拆解:为什么非要把神经网络塞进ILC里

先聊清楚一个问题:传统ILC到底哪里不够用,值得把神经网络请进来?

1.1 经典迭代学习控制的核心机制与短板

ILC的基本思想可以浓缩成一句话:在一段固定时间区间内,系统重复执行同一个轨迹跟踪任务,每次运行结束后利用误差序列修正下一轮的控制输入,使跟踪误差沿迭代轴收敛。P型ILC的更新律是最常见的形式:

u_{k+1}(t) = u_k(t) + K_p * e_k(t)

其中 k 是迭代次数,t 是时间采样点,e_k(t) = y_d(t) - y_k(t) 是第 k 轮的跟踪误差,K_p 是学习增益。从公式上看,这个更新律完全不需要模型,但问题在于 K_p 的选取并不是“拍脑袋”就能拍对的。对于线性系统,K_p 要满足幅值条件 |1 - K_p * P(s)| < 1 才能保证误差收敛;对于非线性系统,这个条件往往需要知道系统的相对阶、输入输出增益范围甚至Lyapunov函数的构造方式。系统模型未知的时候,K_p 取大了振荡甚至发散,取小了收敛速度慢得让人失去耐心。

再加上实际被控对象里普遍存在的摩擦、饱和、死区这类非光滑非线性,纯靠固定增益的ILC很难在未知环境下保持稳定收敛。

1.2 GRNN和RBFNN在这个架构里各自扮演什么角色

要补上ILC对模型的依赖,最直接的思路是用万能逼近器——也就是神经网络——去在线估计系统动态。但单用一个网络并不稳妥,因为系统辨识和跟踪补偿对网络特性的要求并不完全一样,于是才有了GRNN和RBFNN的“双网络”配合设计。

GRNN是广义回归神经网络,它的核心是一个概率密度估计框架,输出值是对训练样本的加权平均。训练过程不需要迭代计算权重,只需要把样本存下来、设置一个平滑参数,因此建模速度极快,适合用于生成系统前馈量的初步预测。在ILC框架里,GRNN可以先用前几轮的数据快速建立“输入-输出”映射,给出下一轮控制量的基准预测值,跳过传统ILC里依赖初值猜测的漫长热身过程。

RBFNN则是典型的局部逼近网络,它的激活函数是径向基函数,对非线性项的拟合能力强,并且支持输出权重的在线更新。在这个架构中,RBFNN的主要任务是对未知非线性项(比如模型中无法描述的摩擦力和高阶动态)进行在线补偿,一边运行一边修正,把GRNN预测剩下的残差再往小压一压。

简单来说:GRNN负责“快”,先把大方向定住;RBFNN负责“稳”,把细节修到位。这样搭配,比直接用单一网络更符合迭代学习控制“逐轮改进”的工作节奏。

1.3 相比传统方案的性能提升点

这套组合的价值体现在三个维度:

  • 建模门槛下降。传统ILC设计需要系统的线性化模型或至少相对阶信息;GRNN-RBFNN方案只需要输入输出数据,模型结构可以完全未知。
  • 收敛速度提升。GRNN的前馈预测能力让第一轮控制量就处在比较合理的水平,不需要像纯ILC那样前几轮只能在原地打转。
  • 适应性增强。系统参数随时间小幅漂移时,RBFNN的在线更新能持续跟踪这种变化,这种能力是固定学习增益的ILC不具备的。

2. 核心原理细拆:GRNN、RBFNN和ILC是怎么拧在一起的

这一节把三个模块的内部结构逐一讲透,重点说清楚每一项的输入输出到底是什么,环节之间靠什么信号衔接。

2.1 ILC框架下问题怎么描述

考虑一类单输入单输出(SISO)非线性系统:

dx/dt = f(x, t) + g(x, t) * u y = x

其中 f(x, t) 是非线性动态项,g(x, t) 是输入增益。这个模型的特点是:结构形式上知道一点,但 f 和 g 的具体表达式未知,甚至连大致范围都不确定。

要求系统在固定时间区间 [0, T] 内跟踪期望轨迹 y_d(t)。将时间离散化为 N 个采样点,第 k 次迭代中,系统在采样时刻 t_i 的输出记为 y_k(t_i),误差为 e_k(t_i) = y_d(t_i) - y_k(t_i)。ILC的目标是设计更新律,让误差随迭代次数 k 增大而趋于零。

2.2 GRNN的工作机制与参数含义

GRNN的理论基础是回归分析中的非参数估计,核心公式是对每个查询点输出附近样本的加权平均:

ŷ(x_q) = Σ y_i * exp(-(x_q - x_i)^T (x_q - x_i) / (2σ^2)) / Σ exp(...)

离查询点近的样本权重高,远的权重低,权重的衰减快慢由平滑因子 σ 控制。σ 越大,预测结果越平滑,适合噪声大的数据;σ 越小,预测结果越贴近最邻近样本,容易过拟合。

实际使用中,GRNN不需要训练迭代,Matlab一句net = newgrnn(X, Y, spread);就完成建模,速度是很大的优势。代价是它对样本库的覆盖质量很敏感——训练数据的密度和分布范围直接决定预测可靠性,这是后面实操部分要重点处理的事项。

2.3 RBFNN的结构设计与在线更新方式

RBFNN是三层结构:输入层、隐含层和输出层。隐含层激活函数一般为高斯基函数:

φ_j(x) = exp(-||x - c_j||^2 / (2b_j^2))

其中 c_j 是第 j 个径向基函数中心,b_j 是宽度参数,通常也简化为一个标量。网络输出是隐含层输出的线性组合:

u_net = Σ w_j * φ_j(x) + b

这里 w_j 是输出层权重,b 是偏置。在线更新时,用误差的负梯度方向修正权重:

w_j(k+1) = w_j(k) + η * e_k * φ_j(x)

其中 η 是学习率。这个式子决定了RBFNN的补偿信号会沿着误差减少的方向持续微调,正好契合ILC逐轮优化的特性。

2.4 双网络合成:GRNN预测+RBFNN补偿+ILC迭代学习

整体控制信号输出为:

u_k(t) = u_grnn(t) + u_rbf(t) + u_ilc(t)
  • u_grnn 由GRNN根据当前状态和期望输出预测,提供基准控制量;
  • u_rbf 由RBFNN输出,补偿未知非线性项引起的偏差;
  • u_ilc 是传统ILC更新量,负责残余误差的逐轮消除。

三者通过加法合成,结构清晰,且每个模块可以单独调试。我实际测试时感受比较深的一点是:GRNN把初轮误差压到一个较低水平之后,RBFNN和ILC的负担都会大幅减轻,整体收敛曲线明显更平缓。

3. Matlab仿真实现:从零搭一套GRNN-RBFNN-ILC轨迹跟踪系统

下面给出我调试过程中确认可运行的实现方案,全部基于脚本编写,不必依赖Simulink,方便逐段检查中间结果。

3.1 仿真模型与期望轨迹设定

系统模型取如下二阶SISO非线性系统(示例):

dx1/dt = x2 dx2/dt = -x1^3 - 0.3*x2 + (1 + 0.2*sin(0.8*t)) * u y = x1

期望轨迹取一条平滑变化的曲线,避免突然跳变:

yd(t) = 0.5*sqrt(t^2 + 1) + 0.3*sin(1.5*t)

这里选非等幅纯正弦而用带趋势的曲线,是为了考察控制器对非周期轨迹段的跟随能力,防止网络“背题”。

3.2 主循环代码架构

主线逻辑分三层:外层是迭代次数循环,中层是时间采样循环,内层是模型数值积分和控制器计算。核心流程如下:

% 参数初始化 T = 2; % 时间总长 dt = 0.01; % 采样周期 time = 0:dt:T; N_iter = 20; % 迭代次数 Kp = 0.8; % IL C比例增益 Kd = 0.15; % ILC微分增益 spread = 0.2; % GRNN平滑因子 eta = 0.05; % RBFNN学习率 % 训练数据存储 trainX = []; trainY = []; for iter = 1:N_iter y = zeros(size(time)); x1 = 0; x2 = 0; u_prev = 0; for i = 1:length(time) % 控制器计算 e = yd(i) - x1; edot = (yd_i_prev - x1_prev)/dt; % 误差变化率(简化处理) u_grnn = grnn_predict(...); % 从训练好的GRNN获取 u_rbf = rbf_online_update(e, x1, x2, time(i)); u_ilc = u_prev + Kp*e + Kd*edot; % 简化的P-D型ILC u_total = u_grnn + u_rbf + u_ilc; % 数值积分(欧拉法) dx1 = x2; dx2 = -x1^3 - 0.3*x2 + (1 + 0.2*sin(0.8*time(i))) * u_total; x1 = x1 + dt*dx1; x2 = x2 + dt*dx2; y(i) = x1; % 存储ILC更新需要的数据 u_prev = u_total; end % 计算本轮误差并更新训练样本 e_seq = yd - y; trainX = [trainX; [time', e_seq']]; trainY = [trainY; u_total_sequence']; % 用当前轮次训练/更新GRNN net_grnn = newgrnn(trainX', trainY', spread); % 记录本轮最大误差和均方根误差 err_max(iter) = max(abs(e_seq)); err_rms(iter) = sqrt(mean(e_seq.^2)); disp(['迭代次数: ', num2str(iter), ', 最大误差: ', num2str(err_max(iter))]); end

这个代码是主流程示意,实际运行时要根据数据维度做一些转置和索引修正。关键点在于:每一轮结束后,GRNN的训练样本集都在扩充,也就是说GRNN对系统的“理解”是逐轮加深的,这是整套算法能越跑越好的一个关键原因。

3.3 GRNN与RBFNN的Matlab封装函数

GRNN预测可以用Matlab自带的神经网络工具箱,简单可靠:

function y_pred = grnn_predict(net, x_query) % x_query需要转置为列向量形式 y_pred = net(x_query'); end

RBFNN在线更新部分我建议自己写,灵活度更高,也方便观察权重变化。一个精简版本如下:

% 初始化RBF网络参数 num_hidden = 10; centers = linspace(-2, 2, num_hidden)'; % 中心点均匀分布在输入范围 widths = ones(num_hidden, 1) * 0.5; % 宽度参数 weights = zeros(num_hidden, 1); % 输出权重 function u_rbf = rbf_online_update(e, x, tau, centers, widths, weights, eta) % 输入: 误差e, 状态x, 时间tau, 网络参数 input_vec = [x; tau]; % 示例输入组合 phi = exp(-sum((input_vec - centers).^2, 2) ./ (2*widths.^2)); u_rbf = weights' * phi; % 梯度更新权重 weights = weights + eta * e * phi; end

实际使用时要注意输入向量的量纲差异——位置、速度、时间混合在一起时,量级相差过大容易导致径向基函数输出饱和。合理做法是先归一化,或者对每个维度单独设置宽度参数。

3.4 仿真结果怎么看:收敛性验证三指标

跑完20轮迭代之后,重点看三个指标:

  • 最大绝对误差曲线(err_max):应该随迭代次数整体下降,允许前几轮波动但趋势向下。
  • 均方根误差曲线(err_rms):相比最大误差更稳定,反映整体跟踪质量。
  • 第1轮与第20轮误差对比图:直观展示轨迹跟踪的“逼近”过程。

我个人习惯把第1轮、第5轮、第10轮、第20轮的跟踪轨迹画在同一张图上,这样能肉眼看出控制器把期望轨迹“越咬越紧”的过程,评审或者汇报时也很有说服力。

4. 常见问题与排查技巧实录

调这套系统踩过的坑比预想的多,这里整理几条高频问题,每条都是实际调试中的经验沉淀。

4.1 ILC不收敛或误差反弹

表现:误差曲线前几轮下降,后面突然反弹或者振荡不降。

排查顺序:

  • 采样周期 dt 是否过大。ILC的时间分辨率不足时,误差序列本身存在较大离散化误差,学习增益再合适也很难收敛。建议先加密采样看趋势变化。
  • 学习增益 Kp/Kd 是否超界。遇到误差高频振荡时,优先减小Kp,观察振荡是否平缓;若振荡依旧,再减小Kd。
  • 控制量是否饱和。如果 u_total 长时间顶在饱和边界,ILC学习到的信息是失真的。建议在仿真模型里加饱和环节,同时控制器输出也限幅,保持一致性。

4.2 GRNN预测效果差:过平滑与欠平滑

GRNN只有一个超参数spread(即σ),但它对预测质量影响极大。实际测试发现:spread设成0.05时,预测曲线跟随噪声剧烈波动,基本没有泛化能力;spread设成0.5时,预测结果过于平滑,连基本的轨迹趋势都跟不上。要找到合适的中间值,一个可操作的办法是观察预测结果与真实输出的残差,从0.1起步,每次翻倍尝试,看残差的均方根值变化趋势,取最小值对应的spread。

4.3 RBFNN在线更新发散

表现:某轮之后控制量突然变成巨大正负交替值,误差曲线瞬间冲天。

原因分析:RBFNN的权重更新是梯度下降,学习率 η 过大时超调明显;另外径向基函数中心点如果覆盖不到实际输入范围,φ 输出接近0,梯度更新基本失效,之后某次输入偶然进入有效区域时权重又剧烈跳变。

解决办法:将 η 初始值控制在0.01到0.05之间;中心点范围覆盖仿真中可能出现的所有输入组合,最简单的方式是先用几轮开环仿真的数据确定输入边界,再在边界内均匀布置中心点。代码实现时可以加一个简单判断:如果权重绝对值超过阈值就重置为0,避免彻底发散。

4.4 时间序列长度不一致导致Matlab报错

ILC迭代学习有个天然要求:每轮运行的时间区间和采样点数量必须完全一致。实际调试中经常因为改了仿真时长忘记改控制器的输入缓存,导致矩阵拼接报错。建议在代码开头设一个全局变量numSamples = length(time);,所有向量都用这个长度初始化,从根上避免维度不匹配的问题。

5. 调参经验与总结性体会

整套系统跑通之后,再回头梳理设计过程,有很多值得沉淀的经验。

5.1 模块调试顺序有讲究

不要一上来就把GRNN、RBFNN、ILC三部分全部接好再调试,否则出错时根本不知道问题出在哪个模块。我推荐的调试顺序是:

  1. 先单独验证RBFNN的记录器,断开GRNN前馈和ILC更新,只保留基础的反馈控制,确认网络不会被误差信号干扰到发散。
  2. 加入ILC更新,用固定增益验证迭代收敛基线。
  3. 再加入GRNN前馈,观察收敛速度是否提升,误差基线平移是否出现。

每加一层就画一次误差曲线对比,问题定位成本会低很多。

5.2 关于网络复杂度与实际收益的平衡

很多时候,RBFNN隐含层节点数设成10到15就足够应对常见的SISO非线性系统。节点数一多,训练速度下降且过拟合风险升高,并不划算。GRNN的样本库也不是越多越好——样本太多时每次预测都要遍历全部样本,计算量线性增长,而且对于时间敏感的ILC实时性会有压力。实际项目中可以把训练样本按“最近几轮+代表性历史点”的规则做剪枝,既保留经验又不让计算量失控。

5.3 个人实操体会

跑这套GRNN-RBFNN-ILC算法,我最直观的一个感受是:神经网络部分给传统ILC带来了一种“手感”。传统ILC的第一轮通常是盲目的,控制量根据初始猜测生成,误差大得离谱。但有了GRNN的前馈预测之后,第一轮的跟踪误差直接控制在可接受范围内,后续的迭代学习变成了在小偏差基础上的精修,而不是从零开始的摸索。

另一个深刻的体会是:GRNN和RBFNN的配合依赖信号的时间对齐。GRNN预测用的是上一轮的历史数据,RBFNN补偿用的是当前瞬间的实时误差,如果两个信号在时间上错位,控制量会出现明显的高频抖动。调试时我踩过这个坑:当时误差曲线震荡不止,排查了半天,最后发现是GRNN训练样本里存的是上上轮的数据,经过一轮错误传递之后,前馈信号和反馈信号相位错开了约一个采样周期,修正后才恢复正常。遇到类似情况时,建议先检查各个输入信号的维度和时间戳是否严格同步。

最后分享一个很实用的小技巧:如果觉得误差收敛曲线不好判断改进空间,把每轮控制量的变化量 Δu = u_{k+1} - u_k 的范数也画出来。模型未充分学习时Δu较大,学习到后期Δu应该趋向平稳。如果Δu持续大幅波动,说明网络结构和学习率大概率还有调整空间。用这个量辅助判断,比只盯误差曲线要直观得多。

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

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

立即咨询