单神经元自适应 PID
1)一句话
经典 PID:
\(u(t)=K_p e(t)+K_i\int e(t)dt+K_d\frac{de}{dt}\)
单神经元 PID:
把 \([e,\ \int e,\ \dot e]\) 当作“输入”,把 \([w_p,w_i,w_d]\) 当作“可调权重”,用监督学习式的增量更新去逼近“让误差更快变小”,同时用工程约束避免权重飞掉。
它不是什么神秘智能,本质是一个带约束的在线梯度/δ规则在 PID 基函数上的投影。
2)离散形式(最常用:增量式写法)
离散误差:
\(e(k)=r(k)-y(k)\)
\(\sum e(k)=\sum e(k-1)+e(k)\cdot T_s\)
\(\dot e(k)=\frac{e(k)-e(k-1)}{T_s}\)
构造神经元输入向量(三个“突触”):
\(x_1(k)=e(k),\quad x_2(k)=\sum e(k),\quad x_3(k)=\dot e(k)\)
神经元输出(即 PID 的输出增量):
\(\Delta u(k)=K\cdot\big(w_1(k)x_1(k)+w_2(k)x_2(k)+w_3(k)x_3(k)\big)\)
\(u(k)=u(k-1)+\Delta u(k)\)
其中:
- (K>0) 是统一的学习/增益缩放因子(常取 0.01~1,取决于你对象有多“猛”)
- (\(w_i\)) 就是你要自适应的东西(对应“Kp/Ki/Kd”的趋势)
3)权重更新怎么来
用最常用的性能指标:
\(J=\frac12 e^2(k)\)
假设我们沿着“让 J 下降”的方向去改权重(梯度下降),会得到:
\(w_i(k+1)=w_i(k)-\eta_i\frac{\partial J}{\partial w_i}\)
而
\(\frac{\partial J}{\partial w_i}=e(k)\cdot\frac{\partial e(k)}{\partial u(k)}\cdot\frac{\partial u(k)}{\partial w_i}\)
工程上最关键的一步来了:
(\(\frac{\partial e}{\partial u}=-1\)),但 (\(\frac{\partial u}{\partial w_i}=K x_i\)),而且被控对象的 Jacobian (\partial y/\partial u)通常是未知的。
于是工程写法:用一个“符号/估计”代替它:
\(\hat s(k)\approx -\text{sgn}\!\left(\frac{\partial y}{\partial u}\right)\)
或者直接把性能灵敏度近似为:
\(\frac{\partial J}{\partial w_i}\approx e(k)\,(-1)\,K\,x_i(k)\)
再吸收常数进学习率,得到最实用的单神经元 PID 更新律:
\(\boxed{w_i(k+1)=w_i(k)+\eta_i\;K\;e(k)\;x_i(k)}\)
这就是你能在很多教材里看到的“单神经元 PID 规则”的来源——它不是瞎凑,是梯度下降 + Jacobian 符号近似。
4)把更新律写得更稳
4.1 加限幅(防发散)
\(w_i^{\min}\le w_i\le w_i^{\max}\)
4.2 加动量/阻尼
\(w_i(k+1)=w_i(k)+\eta_i K e(k)x_i(k)+\alpha\big(w_i(k)-w_i(k-1)\big)\)
- (\(\alpha\in(0,0.2)\)) 通常就够(阻尼振荡、抑制权重抖)
4.3 用误差变化方向做粗略 Jacobian 估计
\(\hat J_{yu}(k)=\text{sign}\big(y(k)-y(k-1)\big)\cdot\text{sign}\big(u(k-1)-u(k-2)\big)\)
若 (\(\hat J_{yu}(k)>0\)) 表示同方向,(\(\approx 1\));反向时你通常冻结/衰减更新。
更保守的写法:
if (dy_sign == du_sign) g = 1.0f; else g = 0.0f; /* or decay */
w[i] += eta[i] * K * e * x[i] * g;
5)C 代码
#include <stdint.h>
#include <string.h>
#include <float.h>
#define N_NEURON 3
typedef struct {
float Ts; /* 采样周期(s) */
float K; /* 统一增益缩放(0.01~1) */
float eta[N_NEURON]; /* 学习率 [p,i,d] */
float w[N_NEURON]; /* 权重 */
float w_prev[N_NEURON]; /* 上次权重(动量) */
float alpha; /* 动量阻尼[0,0.2] */
float w_min, w_max;
float u; /* 当前输出 */
float u_min, u_max;
float e; /* e(k) */
float e_prev; /* e(k-1) */
float sum_e; /* ∫e */
float y_prev; /* y(k-1) */
uint8_t reset;
} SN_PID_t;
void SN_PID_Reset(SN_PID_t *sp, float u0)
{
memset(sp->w, 0, sizeof(sp->w));
memset(sp->w_prev, 0, sizeof(sp->w_prev));
sp->e = sp->e_prev = 0.0f;
sp->sum_e = 0.0f;
sp->y_prev = 0.0f;
sp->u = u0;
sp->reset = 0;
}
/* r:设定值, y:反馈值, u0_hold:若reset用u0 */
float SN_PID_Step(SN_PID_t *sp, float r, float y, float u0_hold)
{
if (sp->reset) {
SN_PID_Reset(sp, u0_hold);
}
sp->e = r - y;
/* 积分(简单矩形) */
sp->sum_e += sp->e * sp->Ts;
/* 微分(可用不完全微分,这里给最简) */
float de = (sp->e - sp->e_prev) / sp->Ts;
/* 神经元输入 */
float x[3] = { sp->e, sp->sum_e, de };
/* 简单 Jacobian 符号估计(可选但推荐) */
float dy = y - sp->y_prev;
float du = sp->u - u0_hold; /* 注意:这里只用于 sign,不是严格 du(k-1) */
float j_sign = 1.0f;
if (sp->Ts > 1e-9f && fabsf(dy) > 1e-9f)
j_sign = (dy*(r-y) >= 0.0f) ? 1.0f : 0.3f; /* 你可按需冻结 */
/* —— 权重更新 —— */
for (int i = 0; i < 3; i++) {
float dw = sp->eta[i] * sp->K * sp->e * x[i] * j_sign;
/* 动量/阻尼 */
dw += sp->alpha * (sp->w[i] - sp->w_prev[i]);
sp->w_prev[i] = sp->w[i];
sp->w[i] += dw;
/* 限幅 */
if (sp->w[i] > sp->w_max) sp->w[i] = sp->w_max;
if (sp->w[i] < sp->w_min) sp->w[i] = sp->w_min;
}
/* 输出增量 -> 绝对输出 */
float du_out = sp->K *
(sp->w[0]*x[0] + sp->w[1]*x[1] + sp->w[2]*x[2]);
sp->u += du_out;
/* 饱和 + 抗windup(积分钳位思想:若饱和则别让∫e继续推) */
if (sp->u > sp->u_max) { sp->u = sp->u_max; sp->sum_e -= sp->e * sp->Ts; }
if (sp->u < sp->u_min) { sp->u = sp->u_min; sp->sum_e -= sp->e * sp->Ts; }
sp->e_prev = sp->e;
sp->y_prev = y;
return sp->u;
}
初始化示例(你要按对象量纲调)
SN_PID_t spid = {
.Ts = 0.0005f, /* 500us */
.K = 0.05f, /* 先小,后慢慢加大 */
.eta = {0.12f, 0.002f, 0.08f}, /* p i d 学习率:i通常最小 */
.alpha = 0.05f,
.w_min = -5.0f, .w_max = 5.0f,
.u_min = 0.0f, .u_max = 3.3f, /* DA/占空比范围 */
};
SN_PID_Reset(&spid, 0.0f);
参考代码 基于单神经的一种自适应PID控制算法 www.youwenfan.com/contentcnv/72630.html
6)怎么解释它“自适应”
你可以运行时打印:
w[0]≈随 “比例效应”w[1]≈随 “积分积累”w[2]≈随 “微分阻尼”
当工况变化(负载突变/输入阶跃/参数漂移),权重会自行重新分布,表现为:
- 稳态误差大 → w[1] 会被推上去
- 过冲严重 → w[2] 变大抑制振荡
- 响应太慢 → w[0] 拉大

浙公网安备 33010602011771号