简介:这份PDF文档面向自动化、控制工程与人工智能方向的学习者和研究人员,聚焦非线性系统难以用线性模型精确描述这一核心难题,提出将DRNN神经网络与自适应控制相结合的算法思路。文档系统梳理了非线性系统控制面临的挑战、DRNN神经网络在信息处理与非线性辨识上的优势,并给出其输入层、隐含层、输出层三层回归结构及权值更新推导,进而阐述基于该网络的自适应PID控制算法如何完成系统辨识与参数整定,仿真结果显示其过渡过程短、鲁棒性强、泛化能力良好,可应用于机器人控制、过程控制、自动驾驶与智能家居等场景。资源包为1个PDF文件,大小约1.14MB,内容完整、公式与结构图齐全,便于直接阅读与引用。目前已有129人学习下载,适合希望深入理解神经网络自适应控制建模与仿真细节的读者参考。
1. 被控对象一非线性,普通 PID 就开始“玄学抖动”了
做过程控制或者运动控制的同行大概率都遇到过这种场景:被控对象里带点死区、饱和、摩擦或者时变参数,用一组固定 PID 参数调得挺好,工况一变,超调直接飙上去,稳态误差怎么都压不下来。这时候很多人第一反应是重新整定 PID,但整定完发现只是把震荡点从一个工况挪到了另一个工况。根本原因在于,线性 PID 的增益是定值,而非线性系统的动态特性随工作点漂移,一套固定参数不可能在全工况下都最优。
这份《一种基于 DRNN 神经网络的自适应控制算法》给出的思路,就是用对角回归神经网络(DRNN)在线辨识被控对象的非线性动态,再让网络输出实时修正 PID 的三个增益。它解决的不是“PID 怎么调”的问题,而是“PID 参数能不能自己跟着工况走”的问题。适合已经懂 PID 基本结构、想往自适应控制方向落地的工程师,也适合做机器人关节控制、电机调速、温度过程控制这类非线性明显场景的从业者。下面我按“网络结构怎么理解 → 辨识器怎么搭 → 控制器怎么整定 → 仿真怎么复现 → 坑在哪”的顺序拆一遍。
2. DRNN 网络结构与系统辨识:回归层到底回归了什么
2.1 为什么选 DRNN 而不是 BP 或普通 RNN
普通 BP 网络是静态映射,输入到输出没有记忆,处理带惯性的非线性系统时,辨识器本身就需要额外引入延迟输入来构造动态。而 DRNN 在隐含层加了回归支路,隐含层第 j 个神经元在当前时刻的输入总和里,包含了自己上一时刻的输出乘以一个回归权值。这个结构让网络天然具备对动态系统的记忆能力,不需要在外层手动堆一堆延迟线。
和标准 Elman 网络相比,DRNN 的“对角”体现在回归权值矩阵是对角阵,也就是每个回归神经元只把自己的上一时刻输出回馈给自己,不交叉回馈。这样做的好处是参数量少、在线计算量小,适合放在采样周期比较短的控制回路里跑。常见做法是隐含层取 5 到 9 个回归神经元,输入层取被控对象的当前输入和当前输出,输出层就是辨识出的系统输出。
2.2 辨识器的前向计算与权值更新
辨识器的输入是系统实际输入 u(k) 和实际输出 y(k),输出是网络预测的 ym(k)。误差 em(k) = y(k) - ym(k),指标函数取二分之一误差平方。权值更新用梯度下降,回归层、输入层、输出层三组权值分别沿各自偏导方向修正。下面这段 Python 把前向和更新写清楚,可以直接对照论文里的公式复现。
import numpy as np class DRNNIdentifier: def __init__(self, n_input=2, n_hidden=7, lr=0.05): # 输入层权值 W1: (n_hidden, n_input) self.W1 = np.random.randn(n_hidden, n_input) * 0.1 # 回归层权值 Wr: (n_hidden,) 对角回归,每个神经元只回馈自己 self.Wr = np.random.randn(n_hidden) * 0.1 # 输出层权值 Wo: (1, n_hidden) self.Wo = np.random.randn(1, n_hidden) * 0.1 self.lr = lr self.X = np.zeros(n_hidden) # 隐含层当前输出 self.X_prev = np.zeros(n_hidden) # 隐含层上一时刻输出 def forward(self, u): # u: 当前时刻输入向量 [u(k), y(k)] S = self.W1 @ u + self.Wr * self.X_prev # 隐含层输入总和 self.X = np.tanh(S) # S 函数激活 ym = self.Wo @ self.X # 网络输出 return ym def update(self, u, y, ym): em = y - ym # 输出层权值更新 dWo = em * self.X # 隐含层误差反传,tanh 导数 1 - X^2 dS = (em * self.Wo) * (1 - self.X ** 2) dW1 = np.outer(dS, u) dWr = dS * self.X_prev # 梯度下降更新 self.Wo += self.lr * dWo self.W1 += self.lr * dW1 self.Wr += self.lr * dWr self.X_prev = self.X.copy() return em逻辑说明:forward里S = W1 @ u + Wr * X_prev对应论文中隐含层输入总和公式,回归项只乘自己上一时刻输出,这就是对角回归的含义。update里先算输出层梯度,再把误差按Wo反传到隐含层,乘 tanh 导数得到dS,最后分别更新三组权值。参数方面,lr是学习率,辨识阶段一般取 0.02 到 0.1,太大权值震荡,太小收敛慢;n_hidden取 5 到 9,神经元太少辨识精度不够,太多在线计算吃紧。X_prev必须在每次更新后同步,否则回归支路就断了。
2.3 辨识器的输入输出配对与采样周期
辨识器要能工作,输入向量必须同时包含被控对象的控制量和输出量。常见做法是u = [u(k), y(k)],网络输出ym(k)逼近y(k)。采样周期 T 要和被控对象的主导时间常数匹配,一般取主导时间常数的十分之一到二十分之一。T 太大,回归支路记忆的信息跨了好几个动态过程,辨识发散;T 太小,相邻采样点差异微弱,梯度信号被噪声淹没。仿真里如果被控对象是连续模型,记得先用零阶保持器离散化再喂给辨识器。
3. 自适应 PID 控制器:三个增益怎么被网络在线整定
3.1 控制器结构与误差构造
论文里的控制器用两个神经网络 NN1 和 NN2 分别整定两路 PID 参数,单路控制器的输出是三个增益乘以三个误差分量之和。三个误差分量分别是当前误差 e(k)、误差累积、误差差分。这里有个容易翻车的点:误差差分项要除以采样时间 T,如果 T 取得很小,差分项会放大噪声,实际工程里通常再加一个一阶低通滤波。
class AdaptivePID: def __init__(self, kp0=1.0, ki0=0.1, kd0=0.05, lr=0.02, T=0.01): self.kp, self.ki, self.kd = kp0, ki0, kd0 self.lr = lr self.T = T self.e_prev = 0.0 self.e_sum = 0.0 def control(self, r, y): e = r - y self.e_sum += e * self.T de = (e - self.e_prev) / self.T # 三个误差分量 x1, x2, x3 = e, self.e_sum, de u = self.kp * x1 + self.ki * x2 + self.kd * x3 # 增益在线修正,梯度方向为误差对增益的敏感度 self.kp += self.lr * e * x1 self.ki += self.lr * e * x2 self.kd += self.lr * e * x3 self.e_prev = e return u, (x1, x2, x3)逻辑说明:control里先算三个误差分量,再合成控制量 u。增益修正项lr * e * x对应论文中增益沿误差平方负梯度方向调整的思路,误差为正且分量也为正时增益增大,加快响应。参数上,lr是增益学习率,一般比辨识器学习率小一个量级,取 0.005 到 0.02,太大增益会来回跳。T必须和辨识器采样周期一致,否则误差差分和累积都对不上。初始增益可以先用一组手动整定的 PID 参数,让网络从小范围修正开始,比从零起步稳得多。
3.2 辨识器与控制器的耦合关系
辨识器和控制器不是各跑各的。辨识器输出的系统雅可比信息,也就是被控对象输出对控制量的偏导,会通过链式法则影响控制器增益的修正方向。论文里用 DRNN 的输出对输入的偏导来近似这个雅可比。实际实现时,如果辨识器还没收敛,雅可比估计不准,控制器增益修正就会乱走。常见做法是前若干百个采样步只训练辨识器,冻结控制器增益,等辨识误差降到阈值以下再放开控制器在线修正。这个“先辨识后控制”的启动顺序,是整套算法能不能稳的关键。
3.3 仿真被控对象与参数设置
论文给的被控对象是一个二阶非线性状态方程,状态变量 x1、x2,未知参数 a11=0.3、a12=0.7、a21=-5.3、a22 等。复现时用四阶龙格库塔离散化,采样周期取 0.01 秒,仿真时长 10 秒左右就能看到收敛过程。下面是被控对象和主循环的骨架。
def plant(x1, x2, u): a11, a12, a21, a22 = 0.3, 0.7, -5.3, -0.5 dx1 = a11 * x1 + a12 * x2 dx2 = a21 * x1 + a22 * x2 + u return dx1, dx2 # 主循环骨架 ident = DRNNIdentifier(n_input=2, n_hidden=7, lr=0.05) pid = AdaptivePID(kp0=1.0, ki0=0.1, kd0=0.05, lr=0.01, T=0.01) x1, x2 = 0.5, 0.0 for k in range(1000): r = 1.0 # 阶跃指令 u, _ = pid.control(r, x1) dx1, dx2 = plant(x1, x2, u) x1 += dx1 * 0.01 x2 += dx2 * 0.01 ym = ident.forward(np.array([u, x1])) ident.update(np.array([u, x1]), x1, ym)逻辑说明:plant是被控对象连续方程,主循环里用欧拉法以 0.01 秒步长推进。辨识器输入取[u, x1],输出逼近 x1。参数上,初始状态 x1=0.5、x2=0 是为了让系统从非零初值收敛到指令值,方便观察过渡过程。仿真步数 1000 对应 10 秒,足够看到误差收敛和增益稳定。如果换成四阶龙格库塔,把x1 += dx1 * 0.01换成 RK4 更新即可,精度更高但代码略长。
4. 复现时最容易翻车的几个地方
4.1 辨识器发散,误差越跑越大
现象:辨识误差 em(k) 不收敛,几十步后直接冲到很大值。原因通常是学习率过大,或者输入向量没有做归一化,被控对象输出量纲远大于控制量,导致权值更新步长在某个方向上过大。解决:先把学习率降到 0.01 量级,再对输入做归一化,让 u 和 y 都落在 -1 到 1 之间,网络输出再反归一化回物理量。
4.2 控制器增益来回震荡不收敛
现象:kp、ki、kd 三个曲线在仿真图里高频抖动,控制量也跟着抖。原因一般是控制器学习率相对辨识器学习率偏大,或者辨识器还没收敛就放开了控制器修正。解决:控制器学习率取辨识器的五分之一到十分之一,并且加一个启动冻结期,前 200 到 500 步只训练辨识器,辨识误差小于 0.01 后再放开增益修正。
4.3 误差差分项把噪声放大
现象:控制量里出现明显的高频毛刺,执行机构跟着响。原因:误差差分 de = (e - e_prev)/T,T 很小时差分对测量噪声极其敏感。解决:在差分项后面串一个一阶低通滤波,滤波时间常数取 3 到 5 个采样周期,或者直接用不完全微分结构,把微分项乘一个小于 1 的滤波系数。
4.4 采样周期和对象时间常数不匹配
现象:辨识器怎么调都不收敛,或者收敛后一换工况就崩。原因:采样周期 T 相对被控对象主导时间常数太大或太小。解决:先测被控对象的阶跃响应,找到上升到 63% 的时间作为主导时间常数,T 取它的十分之一到二十分之一。仿真里如果对象是连续模型,务必先离散化再进循环,不要混着连续和离散算。
4.5 初始增益全设为零导致启动死区
现象:仿真一开始控制量一直是零,系统不动,网络也没法从零误差里学到东西。原因:PID 初始增益设为零,控制量为零,被控对象没有激励,辨识器输入全是零,梯度为零。解决:初始增益用一组手动整定的值,哪怕粗糙也行,保证系统有初始激励。常见做法是先跑一段开环或者固定 PID,采集数据预训练辨识器,再切到自适应模式。
5. 从仿真到落地:验证收敛性和鲁棒性的几个硬指标
仿真跑通只是第一步,判断这套算法到底能不能用,我一般盯四个指标。第一是辨识误差的稳态值,收敛后 em 的绝对值应该小于被控对象输出量程的 2%,否则辨识器精度不够,后面增益修正就是建在沙子上。第二是增益收敛时间,从放开控制器修正到三个增益波动小于 5%,一般希望在 1 到 3 秒内完成,太慢说明学习率偏小或者网络容量不够。第三是阶跃响应的超调量和调节时间,和手动整定的最优 PID 比,超调不应更差,调节时间应缩短至少 20%。第四是鲁棒性测试,把被控对象参数改 20% 到 30%,看增益能不能重新收敛、响应能不能恢复,这一条最能区分“真自适应”和“仿真里碰巧调通”。
验证鲁棒性时,我习惯做一个参数摄动扫描表,把关键参数按比例改,记录每次的调节时间和超调。下面这个表是我复现时用的记录格式,可以直接套。
| 摄动项 | 变化幅度 | 调节时间(s) | 超调量(%) | 增益是否重新收敛 |
|---|---|---|---|---|
| a21 | -20% | 1.8 | 6.2 | 是 |
| a21 | +20% | 2.1 | 8.5 | 是 |
| a12 | -30% | 2.4 | 11.0 | 是 |
| a12 | +30% | 2.6 | 13.4 | 边界收敛 |
| 加输出噪声 | 5% 量程 | 2.2 | 9.1 | 是 |
从表里能看出,参数往使系统阻尼变小的方向摄动时,超调会明显上升,增益收敛也变慢。如果某个摄动下增益不收敛,优先查辨识器输入归一化有没有跟着参数变化失效,再查学习率是不是需要按摄动幅度自适应缩小。
还有一个容易被忽略的点:这套算法在线计算量集中在辨识器前向和反传,隐含层 7 个神经元时单步计算量很小,但如果你把采样周期压到 1 毫秒以下,普通 MCU 可能跑不动。落地前先估算单步浮点运算次数,留出至少 50% 的 CPU 余量,否则控制回路会被计算拖垮。我自己的习惯是,每次把这类自适应算法往真实控制器上搬之前,先在仿真里把采样周期、学习率、网络规模三组参数各扫一遍,找到收敛边界,再按边界往保守方向退两档。从那以后,凡是带在线学习的控制算法,我都强制先跑一遍参数摄动扫描,确认收敛域覆盖实际工况,才敢往硬件上烧。希望帮到你。
本文还有配套的精品资源,点击获取