PID算法与PID自整定算法

2023-11-06

                    PID算法与PID自整定算法


        本文是由于研发恒温槽项目故需要了解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);//符号不显示
			}
		}		
	}
}	

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

PID算法与PID自整定算法_Like_机械师的博客-CSDN博客_pid自整定算法

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

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

随机推荐

  • 使用Otsu算法实现图像的前景和背景分离

    使用Otsu算法实现图像的前景和背景分离 在数字图像处理中 图像前景和背景的分离是一项重要且常见的任务 Otsu算法是一种常用的图像分割算法 它能够自动选择最优阈值将图像分为前景和背景 下面我们以ITK库为例 介绍如何使用Otsu算法实现图
  • Leetcode剑指Offer学习计划第二天题目

    剑指 Offer 06 从尾到头打印链表 输入一个链表的头节点 从尾到头反过来返回每个节点的值 用数组返回 示例 1 输入 head 1 3 2 输出 2 3 1 限制 0 lt 链表长度 lt 10000 所给代码如下 1 Definit
  • Charm-crypto搭建CP-ABE密码系统

    在做毕业设计 所以顺便把做的实验总结成文章 CP ABE原理 另一篇文章总结了 搭建CP ABE系统 注意必须先确保正确安装了Charm crypto环境 安装比较坑 可以根据我的文章安装 https blog csdn net qq 33
  • Visual studio系统找不到指定文件的解决办法

    前言 系统找不到指定文件是新手常见的问题 鉴于笔者是rookie dog也花了好长时间 所以我也就只给我的解决方法啦 这个行不通的师傅可以去网上再搜索一下 或者咨询一下身边的大师傅们问问他们的经验 心态别崩 能解决的 一 问题概述 具体情形
  • [Unity教程]unity 鼠标点击目的地生成特效

    像 很多游戏 点击 目的地 就会在目的地 生成一个 特效 让玩家能够 明白自己点击的地方是哪里 怎么做呢 Unity 的官方 标准 示例 或许可以解决 这个问题 在Unity 的安装中 勾选 如下图所示的2个 选项 进行安装 安装完毕后 打
  • 怎么去除百度网盟推广广告

    1 浏览器 工具 Internet选项 2 安全 受限制的站点 站点 3 把 cpro baidustatic com cpro baidu com 两个域名添加到受限制的站点里 4 添加好了之后 点击确定 关闭浏览器 这样再次搜索就不会出
  • 探亲问题(无向图任意两点是否可连通)——C语言

    下提供队列实现的代码 include
  • Microsoft Dynamics的五种关键能力

    1 集成通信与协作 您需要在工程部门 制造部门和分包商间进行同步通信 例如 如果工程部门改变了设计 运营部门应该立即知道有关的详细情况 您的通信解决方案需要同 ERP 系统相集成 以确保分包商能够支持工程部门在敏捷性方面的提高 产品数据管理
  • 集成开发环境:IDE

    集成开发环境 IDE IDE Integrated Development Environment 是用于提供程序开发环境的应用程序 一般包括代码编辑器 编译器 调试器和图形用户界面等工具 集成了代码编写功能 分析功能 编译功能 调试功能等
  • 机器学习(2)——鸢尾花数据集

    在上次房价数据集中做出一些改进 对鸢尾花数据集进行预测 需要导入的库 from sklearn datasets import load iris 导入鸢尾花数据集 from sklearn linear model import Logi
  • spark安装运行在webUI界面不显示worker

    spark conf spark env sh 文件中需要显式地设置一些环境变量 不用系统默认值 亲测 ubuntu16 04系统 spark env sh中手动配置 export JAVA HOME lt gt jdk1 8export
  • 33. 实战:实现某网站店铺信息的查询与批量抓取(附源码)

    目录 前言 目的 思路 代码实现 1 请求URL 获取源代码 2 解析源代码 获取数据 3 完善保存数据的函数save data 4 理清main函数逻辑 循环传递每一页有效信息的参数 完整代码 运行效果 总结 前言 近日 我们每周四都能刷
  • C#类与结构体的区别

    C 中类 class 与结构体 stract 的区别 1 类是引用类型 结构体是值类型 2 结构体不支持继承 但可以实现接口 类即支持继承也能实现接口 3 结构体中不可以声明无参的构造函数 4 结构体不能定义析构函数 5 结构体不可用作其他
  • 关于json数据的写入(write())必须为str类型及写入后双引号“变为‘号问题

    1 原始json数据 text 黎城县东崖底中心校学生用床购置项目成交公告 label 1 duoyu 0 text 淮南师范学院采购2017年智库项目 科研建设项目 学科及科技创新平台项目 1包 中标公示 label 1 duoyu 0
  • SpringBoot对接微信小程序支付功能开发(二,支付回调功能)

    接着上一篇 SpringBoot对接微信小程序支付功能开发 一 下单功能 在上一篇下单功能中我们有传支付结果回调地址 下面是回调接口实现 package com office miniapp controller import cn hut
  • Blender材质贴图入门图文教程

    推荐 将 NSDT场景编辑器 加入你的3D开发工具链 大家好 今天跟大家分享Blender材质贴图入门图文教程 一套blender的PBR材质包 和HDRI环境纹理贴图 在文末领取 希望能助到大家更高效完成场景练习 据我了解 越来越多人开始
  • Redis、Redission实现分布式锁

    Redis实现 使用spring data redis提供的接口实现redis分布式锁
  • kali使用aircrack无线攻击wifi超详细步骤(包含监听网卡启动,获得握手包,密码本生成)

    平台及工具 linux kali平台 aircrack ng 工具 免驱监听网卡 详细操作 1 首先启动kali 插入网卡 输入ifconfig查看kali是否检测到监听网卡 注意监听网卡要免驱动的 ifconfig 查看自身网卡信息 如图
  • React lazyLoad懒加载

    在React中使用lazy懒加载 效果图 目录结构 index js import React from react import ReactDOM from react dom import App from App import Bro
  • PID算法与PID自整定算法

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