PID算法与PID自整定算法

2023-11-16

        本文是由于研发恒温槽项目故需要了解PID控制算法和PID自整定算法,为方便本人日后需要故作此记录。

        直接粘贴代码吧 !

        这是PID位置式控温算法

/***********************************************************************/
//*******函数名:void Pid_positional(float speed)
//*******用途:PID输出
//*******说明:
//*******参数:无
//*******返回值:无  
/***********************************************************************/
void Pid_positional(void)
{
	if(low_level_alarm_flag ==1||temp_error != 0||End_flag == 4)	//如果液位低 温度错误 定时时间到则停止加热工作停止 
	{
		percent_lv = 0;
		PID.voltage = 900;
	}
	else
	{
		//TemP_add();
		PID.Err = PID.SetSpeed - PID.ActualSpeed;//计算本次误差+ temp_need
		if(PID.Err > 3)		//当温度差值大于3  则全速加热
		{
			PID.voltage = (100 - Ar_Set)*10;
			percent_lv = Ar_Set;
		}
		else if (PID.Err < -3)//当温度值小于-3 必须停止加热
		{
			PID.voltage = 900;
			percent_lv = 0;
		}
		else				//当-3<PID.Err<3 进行PID调节
		{
			if(PID.Err <= 1&&PID.Err >= -1)		//当温度差值大于3  则全速加热
			{
				PID.Intergral += PID.Err; //计算累计误差
			}
			PID.voltage = PID.Kp*PID.Err + PID.Ki * PID.Intergral + PID.Kd * (PID.Err - PID.Err_last);//计算PID值
			PID.Err_last = PID.Err;//上一次误差值写入
			if(PID.voltage >Ar_Set)//控制由Ar决定最大功率
			{
				PID.voltage = Ar_Set;
				if(PID.Err >0)
				{
					if(PID.Err <= 1&&PID.Err >= -1)		//当温度差值大于3  则全速加热
					PID.Intergral -= PID.Err; 
				}
			}	
			if(PID.voltage <= 1)
			{
				PID.voltage = 1;
				if(PID.Err <0)
				{
					if(PID.Err <= 1&&PID.Err >= -1)		//当温度差值大于3  则全速加热
					PID.Intergral -= PID.Err; 
				}
			}
			percent_lv = PID.voltage;
			PID.voltage = PID.voltage*2/100 - 1;//真实值
			PID.voltage = acos(PID.voltage)/3.1415926*1000;
		}
	}
}

        下面是PID自整定算法,绝大多数是参考别人的,在最后计算出PID的时候有一些自己的理解和改动。具体的出处忘记了,没有商用,应该不算违规吧!

/***********************************************************************/
//*******函数名:void PID_Auto(void)
//*******用途:PID自整定
//*******说明:构建闭环回路 确定稳定极限   确定两个参数  极限值KP和震荡周期·
//*******参数:无
//*******返回值:无  
/***********************************************************************/
void PID_Auto(void)
{
	u8 save_buff[6] = {0}; //保存数据缓存
	u8 i = 0;
	float KC = 0;
	float TC = 0;
	float sum_temp = 0,min_temp = 0,max_temp = 0,aver_temp = 0;
	//第一步进入比较初始温度 确定此时温度处于哪种情况
	if(PID_read == 0)
	{
		if(PID.SetSpeed >=  PID.ActualSpeed)	//	如果初始温度小于设定值 
		{
			pid_self_first_status_flag = 1;
			Step_Auto = 0;
		}
		else//	如果初始温度大于设定值 
		{
			pid_self_first_status_flag = 0;
			Step_Auto = 1;
		}
		PID_read = 1;
	}
	if(PID_Auto_Deal == 1)	//自整定过程  修改成500ms 计算一次  如果需要精度很高 计算周期必须短 
	{
		PID_Auto_Deal = 0;	//清除标识
		PID_Auto_Time++;	//整定时间计数
		if(PID_Auto_Time >= 6000)//整定时间超过50分钟 整定失败数据回滚
		{
			PID_Auto_Time = 0;	//计数清零
		}
		//程序第一次进入 查看对比当前温度和设定温度
		//0 设定温度 低于 当前温度  //1设定温度 高于 或者 等于  当前温度  启动加热
		if(( pid_self_first_status_flag == 1) || ( pid_self_first_status_flag == 0))//0 设定温度 低于 当前温度  //1设定温度 高于 或者 等于  当前温度  启动加热
		{
			if(PID.SetSpeed >=  PID.ActualSpeed)//启动加热
			{
				PID_cool_cnt = 0;
				PID_heat_cnt++;
				if(PID_heat_cnt >= 3)//连续3次结果都大于大于实际温度
				{
					PID.voltage = 100;//全速加热
					percent_lv = Ar_Set;
					if(Step_Auto == 0)
					{
						Step_Auto = 1;
						zero_across_counter++;
						if(zero_across_counter == 3)
						{
							time_low = PID_Auto_Time - 3;//此时的时间不是最低温度对应的时间
						}
					}
				}
			}
			else//当前温度 大于 设定温度 停止加热
			{
				PID_cool_cnt++;
				PID_heat_cnt = 0;
				if(PID_cool_cnt > 3)
				{
					PID.voltage = 950;//不加热
					percent_lv = 0;
					if(Step_Auto == 1)
					{
						Step_Auto = 0;
						zero_across_counter++;
						if(zero_across_counter == 3)
						{
							time_low = PID_Auto_Time - 3;//此时的时间不是最低温度对应的时间
						}
					}
				}
			}
			//最低温度 出现在 zero_across_counter = 3 的阶段
			//最高温度 出现在 zero_across_counter = 4 的阶段
			if((zero_across_counter == 3 ) || (zero_across_counter == 4 ))
			{
				pid_self_calc_buffer[k_pid_self_counter] = PID.ActualSpeed;
				k_pid_self_counter++;
				if(k_pid_self_counter > 3)//0--3 共4个元素
				{
					k_pid_self_counter = 0;
					enable_calc_min_max_flag = 1;
				}
				if(enable_calc_min_max_flag == 1)//只要有4个值,就可以计算了 后面来的值覆盖了前面的值 
				{
					//去掉最小值 最大值 取剩下2个值的平均值 
					sum_temp = 0;  //先清0
					min_temp = 300.0;
					max_temp = -80.0;
					for(i = 0;i < 4;i++)
					{
						if(pid_self_calc_buffer[i] <= min_temp)
						{
							min_temp = pid_self_calc_buffer[i];
						}
						if(pid_self_calc_buffer[i] >= max_temp)
						{
							max_temp = pid_self_calc_buffer[i];
						}
						sum_temp += pid_self_calc_buffer[i];
					}
					sum_temp =  sum_temp - min_temp - max_temp ;
					//pid_self_first_status_flag = 1 时 最低温度出现在3阶段
					//pid_self_first_status_flag = 0 时 最低温度出现在4阶段
					if(pid_self_first_status_flag == 1)
					{
						if(zero_across_counter == 3 )//最低温度
						{
							aver_temp = (sum_temp/2.0);					
							if( aver_temp <= temp_low )
							{
								temp_low = aver_temp;
							}				
						}
						else if(zero_across_counter == 4 )//最高温度
						{
							aver_temp = (sum_temp/2.0);
							if( aver_temp >= temp_high )
							{
								temp_high = aver_temp;
							}
						}
					}
					else if(pid_self_first_status_flag == 0)
					{
						if(zero_across_counter == 4 )//最低温度
						{
							aver_temp = (sum_temp/2.0);					
							if( aver_temp <= temp_low )
							{
								temp_low = aver_temp;
							}				
						}
						else if(zero_across_counter == 3 )//最高温度
						{
							aver_temp = (sum_temp/2.0);
							if( aver_temp >= temp_high )
							{
								temp_high = aver_temp;
							}
						}
					}
				}
			}
			else if(zero_across_counter == 5 )//4次过0 则说明出现了振荡 整定成功
			{
				zero_across_counter = 0;				
				PID_Auto_Deal = 0;//退出pid阶段
				time_high = PID_Auto_Time - 3;//此时的时间不是最高温度对应的时间
				KC = 127/(temp_high - temp_low);
				TC = 1 * (time_high - time_low);//如果记录了 最低温度 与 最高温度对应的时间 那么沿用这个公式:TC = 2 * (TIME_Hight - TIME_LOW);	
				PID.Kp = 0.6*KC;		
				PID.Ki = (0.6*KC)/(0.5*TC)/10;
				PID.Kd = (0.6*KC)*(0.125*TC)/60;
				if(dp_Set == 0)
				{
					if(PID.Ki < 0.1)
					{
						PID.Ki = 0.1;
					}
				}
				else
				{
					if(PID.Ki < 0.01)
					{
						PID.Ki = 0.01;
					}
				}
				if(dp_Set == 1)
				{
					P_Set[cool_open_flag] = PID.Kp*100;
					I_Set[cool_open_flag] = PID.Ki*100;
				}
				else
				{
					P_Set[cool_open_flag] = PID.Kp*10;
					I_Set[cool_open_flag] = PID.Ki*10;
				}
				D_Set[cool_open_flag] = PID.Kd;
				save_buff[0] = P_Set[cool_open_flag]>>8;
				save_buff[1] = P_Set[cool_open_flag];
				save_buff[2] = I_Set[cool_open_flag]>>8;
				save_buff[3] = I_Set[cool_open_flag];
				save_buff[4] = D_Set[cool_open_flag]>>8;
				save_buff[5] = D_Set[cool_open_flag];
				W25QXX_Write(save_buff,4 + 12*cool_open_flag,6);
				PID_Auto_flag = 0;
				temp_high = -80.0;		 //得到最高温度
				temp_low = 300;		 	 //得到最低温度
				time_high = 0;		 //得到最高温度
				time_low = 0;		 	 //得到最低温度
				PID_Auto_Time = 0;
				Status_show(3,0);//符号不显示
			}
		}		
	}
}	

       有不正确的地方,也希望看到这篇文章的读者指出,真诚的!

(1条消息) PID算法与PID自整定算法_Like_机械师的博客-CSDN博客_pid自整定算法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PID算法与PID自整定算法 的相关文章

随机推荐

  • 面试题更新之-使用 base64 编码的优缺点

    文章目录 base64 编码是什么 使用 base64 编码的优缺点 base64 编码是什么 Base64编码是一种将二进制数据转换为ASCII字符的编码方式 它将三个字节的二进制数据分割成四组 每组6个比特 然后将这些6个比特转换为可打
  • IP有效性检查(C language)

    STATUS ip valid check const char v p Str int i int tmp char p NULL if strlen v p Str gt 15 return ERROR p char v p Str t
  • 基于Logistic回归和Sigmoid函数的分类【机器学习】

    一 认识Logistic回归 LR 分类器 首先 Logistic回归虽然名字里带 回归 但是它实际上是一种分类方法 主要用于两分类问题 利用Logistic函数 或称为Sigmoid函数 自变量取值范围为 INF INF 自变量的取值范围
  • poll方法01

    p select poll 功能 创建poll对象 返回值 poll对象 p register fd event 功能 注册关注的io事件 参数 fd 要关注的IO event 要关注的io事件类型 通用类型 POLLIN 读io事件 po
  • iphone邮箱看不到已发送_不看不知道 教你如何设置iPhone邮箱

    电子邮件是我们日常生活中必不可少的实用工具 尤其是在商务发面发挥着重要的作用 所以 这次我要教大家怎样设置与使用iPhone的电子邮箱功能 电子邮件是我们日常生活中必不可少的实用工具 尤其是在商务发面发挥着重要的作用 所以 这次我要教大家怎
  • Linux Cobbler自动部署装机

    Cobbler自动部署装机 一 实验准备 二 Cobbler自动装机服务搭建步骤 1 导入epel源 2 安装Cobbler以及其相关服务软件包 3 修改cobbler主配置文件 4 使用cobbler check 命令对Cobbler做检
  • ztree实现异步加载(点击节点,请求后台数据,添加数据到对应节点)真正实现了异步树加载数据

    ztree实现异步加载 首先说一下这篇文章和我写的上一篇异步树的区别 上一篇的我实现的是其实是个伪异步加载 因为我实际是把异步的操作写在了节点上面 点击节点时 获取当前节点的ID 取回子节点的数据 然后手动拼接到当前节点下面 真正的异步其实
  • Linux中挖矿病毒清理通用思路

    目录 前言 清理流程 检查修复DNS 停止计划任务 取消tmp目录的可执行权限 服务排查 进程排查 高CPU占用进程查杀 计划任务清理 预加载劫持清理 系统命令变动排查 中毒前后可执行文件排查 系统配置文件排查 小结 前言 在被植入挖矿病毒
  • 制作USB多系统启动盘

    制作USB多系统启动盘 背景 现在的操作系统更新越来越频繁了 如果用刻录光盘来安装系统的话 会导致大量的浪费 而且光盘寿命太短 一旦划伤 基本上就用不了了 所以想办法使用USB来做为启动盘 利用ISO直接安装系统 这样方便 而且更为灵活 想
  • MySQL--彻底删除数据, 修改/设置密码

    目录 MySQL彻底卸载的方法 修改 设置密码 1 使用 SET PASSWORD 命令 2 使用mysqladmin修改密码 3 UPDATE直接编辑user表 4 忘记密码 此文的背景是 昨天反复安装了几次 刚开始一直无法正常启动使用
  • 语义分割python教学_语义分割:基于openCV和深度学习(二)

    语义分割 基于openCV和深度学习 二 Semantic segmentation in images with OpenCV 开始吧 打开segment py归档并插入以下代码 Semantic segmentation with Op
  • VMware虚拟机禁止防火墙启动

    每次打开虚拟机时候 都会启动防火墙 使用起来很不方便 可以做到永久关闭防火墙 查看firewall状态 systemctl status firewalld service 停止firewall systemctl stop firewal
  • 线段树(单点修改+区间查询)(区间修改+区间查询)

    什么是线段树 线段树 是一种二叉搜索树 它将一段区间划分为若干单位区间 每一个节点都储存着一个区间 它功能强大 支持区间求和 区间最大值 区间修改 单点修改等操作 线段树的思想和分治思想很相像 线段树的每一个节点都储存着一段区间 L R 的
  • (三)Fabric2.0启动网络脚本配置剖析

    总目录 0 如何利用区块链保护知识产权 一 HyperLedger Fabric 2 0 release测试网络部署 二 Fabric2 0 first network 生成配置说明 三 Fabric2 0启动网络脚本配置剖析 四 Fabr
  • 初识MySQL(一)

    目录 一 初识MySQL数据库 Database 1 1 为什么要有数据库 1 2 关于数据库的大体分类 二 数据库的操作 2 1 如何创建一个库 2 1 1 SQL方式 2 1 2 图形化界面方式 My SQL Workbench 2 2
  • python socket基于TCP/IP协议实现多人聊天室

    文章目录 前言 一 实现原理 二 queue队列 三 代码实现 四 需要注意的地方 五 总结 前言 所谓套接字 Socket 就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象 一个套接字就是网络上进程通信的一端 提供了应用层进程
  • Vue简单示例——weex跨平台解决方案

    简单介绍 Weex的出现主要解决了Web开发的应用频繁发布版本和多端研发两个问题 同时解决了前端语言性能差异和显示效果受限的问题 什么是weex Weex是使用流行的Web开发体验来开发高性能原生应用框架 使开发者可以用JS语言和前端开发经
  • H264/AVC-帧内预测

    I宏块使用帧内预测编码压缩数据 根据相邻宏块数据恢复当前宏块信息 值得注意的一点是 帧内预测所参考的相邻宏块数据是deblocking之前的像素值 因为上一宏块的deblocking依赖当前宏块像素值 但当前宏块数据还未重建 1 帧内预测类
  • Python 综合面试题(附参考答案)

    Python 综合面试题 第一部分 Python 基础 如何理解 python 中的深度拷贝和浅拷贝 浅拷贝旨在减少内存的占用 深拷贝可以在做数据的清洗 修改或者入库 的时候 对原数据进行复制一份 以防数据修改之后 找不到原数据 深浅拷 贝
  • PID算法与PID自整定算法

    本文是由于研发恒温槽项目故需要了解PID控制算法和PID自整定算法 为方便本人日后需要故作此记录 直接粘贴代码吧 这是PID位置式控温算法 函数名 void Pid positional float speed 用途 PID输出 说明 参数