PID笔记

Improving the Beginner’s PID

参考资料

Improving the Beginner’s PID – Introduction

The Beginner’s PID

以下是每个人第一次学习的PID方程:

在这里插入图片描述
这导致几乎每个人都编写了以下PID控制器:

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
double kp, ki, kd;
void Compute()
{
   /*How long since we last calculated*/
   unsigned long now = millis();
   double timeChange = (double)(now - lastTime);
  
   /*Compute all the working error variables*/
   double error = Setpoint - Input;
   errSum += (error * timeChange);
   double dErr = (error - lastErr) / timeChange;
  
   /*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)
{
   kp = Kp;
   ki = Ki;
   kd = Kd;
}

Compute()可以定期调用,也可以不定期调用,而且它运行得很好。不过,这个系列并不是关于“效果很好”的。如果我们要将此代码转化为与工业PID控制器相当的代码,我们必须解决以下几点:

  1. Sample Time
    如果以规则的间隔对PID算法进行评估,则PID算法的功能最佳。如果算法知道这个区间,我们也可以简化一些内部数学。

  2. Derivative Kick
    这不是最大的交易,但很容易摆脱,所以我们将这么做。

  3. On-The-Fly Tuning Changes
    一个好的PID算法是可以在不影响内部工作的情况下更改调整参数的算法。

  4. Reset Windup Mitigation
    我们将深入了解什么是Reset Windup,并实施一个具有副作用的解决方案

  5. On/Off (Auto/Manual)
    在大多数应用中,有时需要关闭PID控制器并手动调整输出,而不会受到控制器的干扰.

  6. Initialization
    当控制器第一次打开时,我们想要一个“无颠簸的传输”。也就是说,我们不希望输出突然急动到某个新值。

  7. Controller Direction
    最后一个并不是健壮性本身的名称的改变。它旨在确保用户输入的调整参数具有正确的符号。

  8. NEW: Proportional on Measurement
    添加此功能可以更容易地控制某些类型的进程。

Improving the Beginner’s PID – Sample Time

初学者PID被设计为不规则调用。这导致2个问题:

  • 您无法从PID获得一致的行为,因为有时它被频繁调用,有时它不被调用。
  • 你需要做额外的数学计算导数和积分,因为它们都取决于时间的变化。

确保定期调用PID。我决定这样做的方式是指定在每个周期调用计算函数。PID根据预先确定的采样时间决定是否应该立即计算或返回。

一旦我们知道PID以恒定的间隔进行评估,导数和积分计算也可以简化。

在这里插入图片描述

在第10行和第11行,算法现在自行决定是否该进行计算。此外,因为我们现在知道样本之间的时间是相同的,所以我们不需要不断地乘以时间变化。我们只能适当地调整Ki和Kd(第31和32行),结果在数学上是等效的,但更有效。

不过,这样做有点麻烦。如果用户决定在操作期间更改采样时间,则Ki和Kd将需要重新调整以反映这一新变化。这就是第39-42行的全部内容。

另外请注意,我在第29行将采样时间转换为秒。严格来说,这是不必要的,但允许用户以1秒和s为单位输入Ki和Kd,而不是以1/mS和mS为单位。

上面的变化为我们做了3件事

  1. 无论调用Compute()的频率有多高,PID算法都将以一定的间隔进行评估[第11行]
  2. 由于时间相减[第10行],当millis()返回到0时不会出现问题。这种情况每55天才会发生一次
  3. 我们再也不需要用时间变化来乘和除了。由于它是一个常数,我们可以将其从计算代码中移出[第15+16]行],并将其与调整常数[第31+32]行]合并。从数学上讲,它的结果是一样的,但每次评估PID时都会节省一次乘法和除法.

关于中断的旁注:如果这个PID进入微控制器,那么可以为使用中断提供一个很好的论据。SetSampleTime设置中断频率,然后在该时间调用Compute。在这种情况下,不需要第9-12、23和24行。如果你打算用你的PID实现来做这件事,那就去做吧!请继续阅读本系列。希望您仍能从接下来的修改中获得一些好处。

Improving the Beginner’s PID – Derivative Kick

在这里插入图片描述

上图说明了这个问题。由于误差=设定点-输入,设定点的任何变化都会导致误差的瞬时变化。这种变化的导数是无穷大的(在实践中,由于dt不是0,它最终会成为一个非常大的数字。)这个数字被输入到pid方程中,这会导致输出出现不希望的峰值。幸运的是,有一种简单的方法可以消除这种情况。

在这里插入图片描述
事实证明,误差的导数等于输入的负导数,除非设定值发生变化。这最终成为一个完美的解决方案。我们不加(Kd误差导数),而是减去(KdInput导数)。这被称为使用“测量导数”.

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastInput;
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 dInput = (Input - lastInput);
 
      /*Compute PID Output*/
      Output = kp * error + ki * errSum - kd * dInput;
 
      /*Remember some variables for next time*/
      lastInput = Input;
      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;
   }
}

在这里插入图片描述

这里的修改非常容易。我们将+dError替换为-dInput。我们现在记住的不是lastError,而是lastInput.
在这里插入图片描述

以下是这些修改给我们带来的结果。请注意,输入看起来仍然大致相同。因此,我们获得了相同的性能,但并不是每次设定值发生变化时都会发出巨大的输出峰值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338375.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【c++函数重载】

文章目录 一. 命名空间二 .全缺省参数和半缺省参数三 . 函数重载 一. 命名空间 1.不指定域:先在局部找,再全局。 2. 指定域:到指定的命名空间去找。 3. 当把指定命名空间放开时,即using namespace std;例如放开标准c库…

聊聊Java虚拟机(一)—— 类加载子系统

1. 前言 ​ 虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上,虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑,里面可以安装操作系统;程序虚拟机是为了执行单个计算机程序而设计出来…

imgaug库图像增强指南(32):塑造【雪景】效果的视觉魔法

引言 在深度学习和计算机视觉的世界里,数据是模型训练的基石,其质量与数量直接影响着模型的性能。然而,获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此,数据增强技术应运而生,成为了解决这一问题的…

蓝桥杯练习题(十二)

📑前言 本文主要是【算法】——蓝桥杯练习题(十二)的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他…

【蓝桥杯日记】复盘篇一:深入浅出顺序结构

🚀前言 本期是一篇关于顺序结构的题目的复盘,通过复盘基础知识,进而把基础知识学习牢固!通过例题而进行复习基础知识。 🚩目录 前言 1.字符三角形 分析: 知识点: 代码如下 2. 字母转换 题目分析: 知…

加固密码安全:保护您的个人信息

一、引言 在数字化时代,密码安全是保护个人信息和数据的重要环节。然而,许多人在创建和管理密码时存在一些常见的安全漏洞,如使用弱密码、重复使用密码等。本文将详细介绍密码安全的重要性,并提供一些有效的方法和技巧&#xff0…

使用DALL-E 3模型模拟AI女友的一天 |【人人都是算法专家】

Rocky Ding 公众号:WeThinkIn 知乎:Rocky Ding 写在前面 【人人都是算法专家】栏目专注于分享AI行业中业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习💪 大家好,我是Rocky。 我们都知道DALL-E 3是和Stable Diffusio…

Windows ssh登录eNSP交换机

目录 1. Cloud IO配置1.1 创建UDP端口1.2 创建本地连接1.3 端口映射设置 2. 交换机配置2.1 配置vlanif2.2 配置vty2.3 配置ssh用户2.4 配置aaa2.5 使用Xshell工具登录2.6 用户和密码2.7 登录成功 3. 使用cmd 登录报错提示3.1 手动指定加密算法,提示密码长度无效3.2 …

自定义注解与拦截器实现不规范sql拦截(拦截器实现篇)

最近考虑myBatis中sql语句使用规范的问题,如果漏下条件或者写一些不规范语句会对程序性能造成很大影响。最好的方法就是利用代码进行限制,通过拦截器进行sql格式的判断在自测环节就能找到问题。写了个简单情景下的demo,并通过idea插件来将myB…

Twisted Circuit洛谷绿题题解

Twisted Circuit 题面翻译 读入四个整数 0 0 0 或者 1 1 1,作为如图所示的电路图的输入。请输出按照电路图运算后的结果。 感谢PC_DOS 提供的翻译 题目描述 输入格式 The input consists of four lines, each line containing a single digit 0 or 1. 输出格…

编译和链接详解

文章目录 前言翻译环境和运行环境翻译环境和运行环境图解 翻译环境编译预处理(预编译)阶段编译汇编 链接 运行环境总结 前言 提示:这里可以添加本文要记录的大概内容: 在软件开发的世界中,编译和链接是构建程序的两个…

【GitHub项目推荐-开源的任务管理工具】【转载】

推荐一个开源的任务管理工具,该工具会提供各类文档协作功能、在线思维导图、在线流程图、项目管理、任务分发、即时 IM,文件管理等等。该开源项目使用到 Vue、Element-UI、ECharts 等技术栈。 开源地址:www.github.com/kuaifan/dootask 预览地…

5G_系统同步机制(八)

BBU和RRU的同步机制 为什么要做到系统同步 在TDD模式下工作时,为了避免相邻小区之间的干扰,近距离的所有gNB在任何时间点都必须具有相同的传输方向(DL或UL)。这样做的必要条件是在BTS之间同步SFN (System Frame number)和time Slot。此外,由…

meshgrid contour contourf

meshgrid contour contourf 参考video: https://www.bilibili.com/video/BV1qW411A775/?spm_id_from333.337.search-card.all.click&vd_sourced171c31a396363b8ea8c0e92a59cee6b 官方文档: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contourf.html#ma…

嵌入式-C语言-江科大-数据类型宏定义#define关键字typedef结构体

这是C语言中高级相关知识,在单片机中实战的一些用法 参考C语言江科大视频的学习笔记,详细举例子并且完整记录up的想法,包括内容有c语言数据类型&宏定义#define&关键字typedef&结构体&预处理指令 文章目录 一:C语言数据类型二…

idea 折叠某段代码 这段特定某段代码

如何折叠IntelliJ IDEA代码片段_w3cschool ctrlALTT

HNU-数据挖掘-作业1

数据挖掘课程作业作业1 计科210X 甘晴void 202108010XXX 第一题 假设所分析的数据包括属性 age,它在数据元组中的值(以递增序)为13 ,15 ,16 ,16 ,19 ,20 ,20 ,21 ,22 ,22 ,25 ,25 ,25 ,25 ,30 ,33 ,33 ,35 ,35 ,35 ,35 ,36 ,40 ,45 ,46 ,52,70。 a.…

从零开始的OpenGL光栅化渲染器构建5-阴影

前言 阴影是光线被阻挡的结果;当一个光源的光线由于其他物体的阻挡不能够达到一个物体的表面的时候,那么这个物体就在阴影中了。阴影能够使场景看起来真实得多,并且可以让观察者获得物体之间的空间位置关系。 直接阴影 阴影映射(Shadow Ma…

C语言/c++指针详细讲解【超详细】【由浅入深】

指针用法简单介绍 指针,是内存单元的编号。 内存条分好多好多小单元,一个小单元有 8 位,可以存放 8 个 0 或 1;也就是说,内存的编号不是以位算的,而是以字节算的,不是一个 0 或 1 是一个编号&…

【题目】2023年国赛信息安全管理与评估正式赛任务书-模块3 CTF

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 任务书 模块三 网络安全渗透、理论技能与职业素养 竞赛相关资源资料可在文末关注公众号获得 比赛时间及注意事项 本阶段比赛时长为180分钟,时间为9:00-12:00。 【注意事项】 (1&#xf…