PID调优——样本时间

本文探讨了PID控制器设计中因无规则调用导致的问题,并提出了一种优化方案,即确保PID控制器在固定时间间隔内被调用。该方案不仅简化了微分和积分运算,还提高了计算效率。
部署运行你感兴趣的模型镜像

 

问题

PID设计为无规则调用,存在2个问题:

  • 你不能从PID得到确定的行为,因为调用时可能是频繁的也可能不是。
  • 你需要做额外的微分和积分数学计算,因为它们都依赖于时间变化。

方案

确保PID在规律的时间间隔调用。通过指定每个调用PID循环,基于预定义的一个样本时间,PID决定计算还是立即返回。

当我们知道PID在固定的间隔被调用,微分和积分运算就可以简化。

代码

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
double kp, ki, kd;
int SampleTime = 1000; //1 sec
void Compute()
{
   unsigned long now = millis();
   int timeChange = (now - lastTime);
   if(timeChange>=SampleTime)
   {
      /*Compute all the working error variables*/
      double error = Setpoint - Input;
      errSum += error;
      double dErr = (error - lastErr);
 
      /*Compute PID Output*/
      Output = kp * error + ki * errSum + kd * dErr;
 
      /*Remember some variables for next time*/
      lastErr = error;
      lastTime = now;
   }
}
 
void SetTunings(double Kp, double Ki, double Kd)
{
  double SampleTimeInSec = ((double)SampleTime)/1000;
   kp = Kp;
   ki = Ki * SampleTimeInSec;
   kd = Kd / SampleTimeInSec;
}
 
void SetSampleTime(int NewSampleTime)
{
   if (NewSampleTime > 0)
   {
      double ratio  = (double)NewSampleTime
                      / (double)SampleTime;
      ki *= ratio;
      kd /= ratio;
      SampleTime = (unsigned long)NewSampleTime;
   }
}
 

算法可以判断是否是计算的时间了。同样,我们现在知道算法使用相同的样本时间,我们不需要常常乘以时间变化。我们仅仅适当调整Ki和Kd,哪样在数学上是相等的,而且更加有效。

一个小缺陷是。如果用户决定修改样本时间,Ki和Kd需要重新调整以反应新的修改,SetSampleTimp就是做这个事的。

需要注意,我把样本时间的单位换算成秒。严格来说这不是必须的,但是这让用户可以输入Ki和Kd的单位是1/秒和秒,而不是1/毫秒和毫秒。

结果

上面的修改为我们做了三件事

  1. 不管Compute()的调用频率是多少,PID算法始终是固定的间隔调用。
  2. millis()为0时,时间相减不再是问题。
  3. 我们再也不需要去乘除时间变化。因为这是个常数,我们将它从计算代码中移除,整合进调整常数中。从数学上来说是等价的,但是节约了每一次乘除带来的成本。

Side note about interrupts

如果这个PID运行在单片机中,一个非常好的想法是使用一个中断。SetSampleTime设置中断频率,然后到时调用Compute。在这种情况下时间计算和判断就不会有需要。
这里有三个原因我没有使用中断:

  1. 不是每个人都能用中断。
  2. 同一时间实现多个PID控制器将变得棘手。
  3. 我将在以后的PID实现中使用终端。

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

### PID控制步进电机速度的实现思路及方法 PID(比例-积分-微分)控制器是一种广泛应用于工业自动化中的反馈控制系统,能够有效减少误差并提升系统的响应性能。对于步进电机的速度控制而言,PID算法可以根据目标速度与实际速度之间的偏差整输出量,从而实现精准的速度节。 #### 实现原理 在步进电机速度控制场景下,PID控制器接收来自传感器的实际速度数据作为反馈信号,并将其与预设的目标速度相比较得出误差值e(t)。接着依据此误差以及历史累积误差Σe(τ)dτ和变化率de/dt分别乘以三个系数Kp、Ki、Kd得到最终输出u(t),即: \[ u(t)= K_p e(t)+ K_i \int_{0}^{t} e(\tau)\mathrm{d}\tau + K_d\frac{\mathrm{d}e}{\mathrm{d}t} \] 其中\( K_p\)代表比例增益;\( K_i\)表示积分时间常数倒数;而\( K_d\)则是微分时间参数[^1]。 #### 软件架构设计 为了简化说明过程这里给出一个基于Arduino平台的例子: 1. **初始化阶段**: 配置好硬件接口之后要先定义几个全局变量用来存储关键数值如目标速度(setpoint), 当前测量到的真实速度(measuredSpeed)还有pid对象实例化等等. 2. **循环执行部分**: 在主函数loop里持续不断地做三件事——采集最新的速度样本更新measuredSpeed, 计算新的PWM占空比并通过analogWrite设置给H桥驱动模块最后再稍作短暂延时让整个流程稳定下来. 下面展示了一段伪代码样例供参考: ```cpp #include <PID_v1.h> double Setpoint, Input, Output; PID myPID(&Input, &Output, &Setpoint, 2, 5, 1, DIRECT); void setup(){ Serial.begin(9600); Setpoint = 100; // 设定期望转速为100RPM myPID.SetMode(AUTOMATIC); } void loop(){ Input = readEncoder(); // 获取当前转速 myPID.Compute(); // 运行PID运算 analogWrite(motorPin, Output);// 将结果映射成合适的PWM值送给马达 } ``` 在这个例子当中我们采用了第三方库PID_V1来进行封装好的操作大大降低了自己手动编写公式的难度同时也提高了可维护性和扩展性[^3]. #### 参数技巧 找到一组理想的kp ki kd组合往往需要经过多次试验才能达成理想的效果。一般推荐采用Ziegler–Nichols法则或者其他自动整定工具辅助完成初始值选取然后再根据实际情况逐步精细化整直至满足需求为止[^4]. ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值