PID笔记

news2025/1/13 13:16:39

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.
在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mongo集群入门

一、前言 MongoDB 有三种集群架构模式,分别为主从复制(Master-Slaver)、副本集(Replica Set)和分片(Sharding)模式。 Master-Slaver 是一种主从复制的模式,目前已经不推荐使用。 Re…

vue.js js 雪花算法ID生成 vue.js之snowFlake算法

随着前端业务越来越复杂,自定义表单数据量比较大,每条数据的id生成则至关重要。想到前期IOS中实现的雪花算法ID,照着其实现JS版本,供大家学习参考。 一、库的建立引入 在你项目中创建一个snowFlake.js的文件:拷贝以下…

《Windows核心编程》若干知识点应用实战分享

目录 1、进程的虚拟内存分区与小于0x10000的小地址内存区 1.1、进程的虚拟内存分区 1.2、小于0x10000的小地址内存区 2、保存线程上下文的CONTEXT结构体 3、从汇编代码角度去理解多线程运行过程的典型实例 4、调用TerminateThread强制结束线程会导致线程中的资源没有释放…

大数据关联规则挖掘:Apriori算法的深度探讨

文章目录 大数据关联规则挖掘:Apriori算法的深度探讨一、简介什么是关联规则挖掘?什么是频繁项集?什么是支持度与置信度?Apriori算法的重要性应用场景 二、理论基础项和项集支持度(Support)置信度&#xff…

vue3相比vue2的效率提升

1、静态提升 2、预字符串化 3、缓存事件处理函数 4、Block Tree 5、PatchFlag 一、静态提升 在vue3中的app.vue文件如下: 在服务器中,template中的内容会变异成render渲染函数。 最终编译后的文件: 1.静态节点优化 那么这里为什么是两部分…

[SwiftUI]自定义滚动菜单栏进行PageView页面切换

如图,自定义一个菜单栏,要求点击菜单按钮和滚动翻页步调统一。 首先有个分类模型 import Foundationstruct CategoryModel: Hashable {var categoryID: Int 0var categoryName: String ""} 基础实现代码如下,点击菜单和滚动页面…

C++(14)——string的模拟实现

前几篇文章中介绍了关于以及其相关函数的使用,为了更清楚的了解这些函数的作用,本篇文章通过模拟实现的方式来加深对于函数作用原理的理解。 目录 1. String的整体框架: 1.1 成员变量: 1.2 构造函数: 1.3 析构函数…

2023年总结我所经历的技术大变革

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅…

快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践

作者:熊兮、贺弘、临在 Mixtral 8x7B大模型是Mixtral AI推出的基于decoder-only架构的稀疏专家混合网络(Mixture-Of-Experts,MOE)开源大语言模型。这一模型具有46.7B的总参数量,对于每个token,路由器网络选…

Acwing 138 周赛 解题报告 | 珂学家 | 偏序 + DP构造

前言 整体评价 很久没做acwing周赛了, 之前vp过一些周赛,感觉风格变了。 这次感觉还可以,都是些眼熟的套路题。 A. 5458. 进水排水问题 思路: 签到题 按题意描述编写 import java.io.*; import java.util.*;public class Main {public static void …

解决 conda新建虚拟环境只有一个conda-meta文件&conda新建虚拟环境不干净

像以前一样通过conda 新建虚拟环境时发现环境一团糟,首先新建虚拟环境 conda create -n newenv这时候activate newenv,通过pip list,会发现有很多很多的包,都是我在其他环境用到的。但诡异的是,来到anaconda下env的目…

openEuler安装KVM

1、关闭防火墙和selinux [rootlocalhost ~]# systemctl stop firewalld[rootlocalhost ~]# setenforce 0 2、下载软件包 libvirt:用于管理虚拟化平台的开源的 API,后台程序和管理工具。 qemu:开源(模拟)软件&#…

【51单片机】IO 扩展(串转并)--74HC595

0、前言 参考: 普中 51 单片机开发攻略 第12章 【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】 https://www.bilibili.com/video/BV1Mb411e7re/?p21&share_sourcecopy_web&vd_source77e36f24add8dc77c362748ffb980148 nop()是什么语句&#…

算法常用思路总结

思路 1. 求数组中最大最小值思路代码 2. 计算阶乘思路:代码: 3. 得到数字的每一位思路代码 4. 计算时间类型5. 最大公约数、最小公倍数6. 循环数组的思想题目:猴子选大王代码 补充经典例题1. 复试四则运算题目内容题解 2. 数列求和题目内容题…

8.1 Java与数据库连接_XML(❤)

8.1 Java与数据库连接_XML 1. XML介绍与用途2. XML语法规则3. XML语义约束3.1 DTD语法3.2 创建DTD文件3.3 XML Schema语法1. XML介绍与用途 2. XML语法规则

常见的代码生成器使用

常见的代码生成器使用 目录概述需求: 设计思路实现思路分析1.第一部分2.第二部分 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for cha…

Django随笔

关于Django的admin 1. 在url中把 from django.contrib import admin 重新解开 把path(admin/,admin.site.urls), 解开 2. 注册app,在配置文件中写 django.contrib.admin, 3.输入命令进行数据库迁移 Django国际化 配置文件中(改成中文) LA…

【STM32F103】DMA直接存储器访问游戏摇杆模块(ADCDMAEXTI)

前言(可忽略) 当初下定决心要走嵌入式的时候买了一堆传感器,但是因为懒和忙所以闲置了一堆,今天考完了最后一门,所以打算一个个都玩一遍,今天先从这个摇杆开始,当初买这个是想着以后做个遥控小…

指标异常检测和诊断

检测 是发现问题 诊断 是找到原因 误差的分类 系统误差:系统误差是由于仪器本身不精确,或实验方法粗略,或实验原理不完善而产生的。随机误差:随机误差是由各种偶然因素对实验者、测量仪器、被测物理量的影响而产生的。粗大误差&…

动态规划——数字金字塔【集训笔记】

题目描述 观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。 在上面的样例中,从13到8到26到15到24的路径产生了最大的和86。 输入 第一个行包含R(1≤ R≤…