(完整word版)增量式PID控制C语言代码
- 格式:doc
- 大小:19.87 KB
- 文档页数:4
基于PID算法的温度控制系统89C51单片机,通过键盘输入预设值,与DS18B20测得的实际值做比较,然后驱动制冷或加热电路。
用keil C语言来实现PID的控制。
//PID算法温控C语言2008-08-17 18:58#include<reg51.h>#include<intrins.h>#include<math.h>#include<string.h>struct PID {unsigned int SetPoint; // 设定目标Desired Valueunsigned int Proportion; // 比例常数Proportional Constunsigned int Integral; // 积分常数Integral Constunsigned int Derivative; // 微分常数Derivative Constunsigned int LastError; // Error[-1]unsigned int PrevError; // Error[-2]unsigned int SumError; // Sums of Errors};struct PID spid; // PID Control Structureunsigned int rout; // PID Response (Output)unsigned int rin; // PID Feedback (Input)sbit data1=P1^0;sbit clk=P1^1;sbit plus=P2^0;sbit subs=P2^1;sbit stop=P2^2;sbit output=P3^4;sbit DQ=P3^3;unsigned char flag,flag_1=0;unsigned char high_time,low_time,count=0;//占空比调节参数unsigned char set_temper=35;unsigned char temper;unsigned char i;unsigned char j=0;unsigned int s;/***********************************************************延时子程序,延时时间以12M晶振为准,延时时间为30us×time***********************************************************/void delay(unsigned char time){unsigned char m,n;for(n=0;n<time;n++)for(m=0;m<2;m++){}}/*********************************************************** 写一位数据子程序***********************************************************/ void write_bit(unsigned char bitval){EA=0;DQ=0; /*拉低DQ以开始一个写时序*/if(bitval==1){_nop_();DQ=1; /*如要写1,则将总线置高*/}delay(5); /*延时90us供DA18B20采样*/DQ=1; /*释放DQ总线*/_nop_();_nop_();EA=1;}/*********************************************************** 写一字节数据子程序***********************************************************/ void write_byte(unsigned char val){unsigned char i;unsigned char temp;EA=0; /*关中断*/TR0=0;for(i=0;i<8;i++) /*写一字节数据,一次写一位*/{temp=val>>i; /*移位操作,将本次要写的位移到最低位*/temp=temp&1;write_bit(temp); /*向总线写该位*/}delay(7); /*延时120us后*/// TR0=1;EA=1; /*开中断*/}/*********************************************************** 读一位数据子程序***********************************************************/ unsigned char read_bit(){unsigned char i,value_bit;EA=0;DQ=0; /*拉低DQ,开始读时序*/_nop_();_nop_();DQ=1; /*释放总线*/for(i=0;i<2;i++){}value_bit=DQ;EA=1;return(value_bit);}/*********************************************************** 读一字节数据子程序***********************************************************/ unsigned char read_byte(){unsigned char i,value=0;EA=0;for(i=0;i<8;i++){if(read_bit()) /*读一字节数据,一个时序中读一次,并作移位处理*/ value|=0x01<<i;delay(4); /*延时80us以完成此次都时序,之后再读下一数据*/}EA=1;return(value);}/*********************************************************** 复位子程序***********************************************************/ unsigned char reset(){unsigned char presence;EA=0;DQ=0; /*拉低DQ总线开始复位*/delay(30); /*保持低电平480us*/DQ=1; /*释放总线*/delay(3);presence=DQ; /*获取应答信号*/delay(28); /*延时以完成整个时序*/EA=1;return(presence); /*返回应答信号,有芯片应答返回0,无芯片则返回1*/}/***********************************************************获取温度子程序***********************************************************/void get_temper(){unsigned char i,j;do{i=reset(); /*复位*/}while(i!=0); /*1为无反馈信号*/i=0xcc; /*发送设备定位命令*/write_byte(i);i=0x44; /*发送开始转换命令*/write_byte(i);delay(180); /*延时*/do{i=reset(); /*复位*/}while(i!=0);i=0xcc; /*设备定位*/write_byte(i);i=0xbe; /*读出缓冲区容*/write_byte(i);j=read_byte();i=read_byte();i=(i<<4)&0x7f;s=(unsigned int)(j&0x0f);s=(s*100)/16;j=j>>4;temper=i|j; /*获取的温度放在temper中*/}/*============================================================================= =======================Initialize PID Structure=============================================================================== ======================*/void PIDInit (struct PID *pp){memset ( pp,0,sizeof(struct PID));}/*============================================================================= =======================PID计算部分=============================================================================== ======================*/unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ){unsigned int dError,Error;Error = pp->SetPoint - NextPoint; // 偏差pp->SumError += Error; // 积分dError = pp->LastError - pp->PrevError; // 当前微分pp->PrevError = pp->LastError;pp->LastError = Error;return (pp->Proportion * Error//比例+ pp->Integral * pp->SumError //积分项+ pp->Derivative * dError); // 微分项}/***********************************************************温度比较处理子程序***********************************************************/pare_temper(){unsigned char i;if(set_temper>temper){if(set_temper-temper>1){high_time=100;low_time=0;}else{for(i=0;i<10;i++){ get_temper();rin = s; // Read Inputrout = PIDCalc ( &spid,rin ); // Perform PID Interation}if (high_time<=100)high_time=(unsigned char)(rout/800);elsehigh_time=100;low_time= (100-high_time);}}else if(set_temper<=temper){if(temper-set_temper>0){high_time=0;low_time=100;}else{for(i=0;i<10;i++){ get_temper();rin = s; // Read Inputrout = PIDCalc ( &spid,rin ); // Perform PID Interation}if (high_time<100)high_time=(unsigned char)(rout/10000);elsehigh_time=0;low_time= (100-high_time);}}// else// {}}/***************************************************** T0中断服务子程序,用于控制电平的翻转,40us*100=4ms周期******************************************************/ void serve_T0() interrupt 1 using 1{if(++count<=(high_time))output=1;else if(count<=100){output=0;}elsecount=0;TH0=0x2f;}/***************************************************** 串行口中断服务程序,用于上位机通讯******************************************************/ void serve_sio() interrupt 4 using 2{/* EA=0;RI=0;i=SBUF;if(i==2){while(RI==0){}RI=0;set_temper=SBUF;SBUF=0x02;while(TI==0){}TI=0;}else if(i==3){TI=0;SBUF=temper;while(TI==0){}TI=0;}EA=1; */}void disp_1(unsigned char disp_num1[6]){unsigned char n,a,m;for(n=0;n<6;n++){// k=disp_num1[n];for(a=0;a<8;a++){clk=0;m=(disp_num1[n]&1);disp_num1[n]=disp_num1[n]>>1;if(m==1)data1=1;else_nop_();clk=1;_nop_();}}}/*****************************************************显示子程序功能:将占空比温度转化为单个字符,显示占空比和测得到的温度******************************************************/void display(){unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6}; unsigned char disp_num[6];unsigned int k,k1;k=high_time;k=k%1000;k1=k/100;if(k1==0)disp_num[0]=0;elsedisp_num[0]=0x60;k=k%100;disp_num[1]=number[k/10];disp_num[2]=number[k%10];k=temper;k=k%100;disp_num[3]=number[k/10];disp_num[4]=number[k%10]+1;disp_num[5]=number[s/10];disp_1(disp_num);}/***********************************************************主程序***********************************************************/main(){unsigned char z;unsigned char a,b,flag_2=1,count1=0;unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};TMOD=0x21;TL0=0x40;SCON=0x50;PCON=0x00;TH1=0xfd;TL1=0xfd;PS=1;EA=1;EX1=0;ET0=1;ES=1;TR0=1;TR1=1;high_time=50;low_time=50;PIDInit ( &spid ); // Initialize Structure spid.Proportion = 10; // Set PID Coefficients spid.Integral = 8;spid.Derivative =6;spid.SetPoint = 100; // Set PID Setpoint while(1){if(plus==0){EA=0;for(a=0;a<5;a++)for(b=0;b<102;b++){}if(plus==0){set_temper++;flag=0;}}else if(subs==0){for(a=0;a<5;a++)for(b=0;a<102;b++){}if(subs==0){set_temper--;flag=0;}}else if(stop==0) {for(a=0;a<5;a++)for(b=0;b<102;b++){} if(stop==0){flag=0;break;}EA=1;}get_temper();b=temper;if(flag_2==1)a=b;if((abs(a-b))>5) temper=a;elsetemper=b;a=temper;flag_2=0;if(++count1>30) {display();count1=0;}pare_temper();}TR0=0;z=1;while(1){EA=0;if(stop==0){for(a=0;a<5;a++)for(b=0;b<102;b++){} if(stop==0)disp_1(phil);// break;}EA=1;}}//DS18b20 子程序#include <REG52.H>sbit DQ=P2^1; //定义端口typedef unsigned char byte;typedef unsigned int word;//延时void delay(word useconds){for(;useconds>0;useconds--);}//复位byte ow_reset(void){byte presence;DQ=0; //DQ低电平delay(29); //480usDQ=1; //DQ高电平delay(3); //等待presence=DQ; //presence信号delay(25);return(presence);} //0允许,1禁止//从1-wire 总线上读取一个字节byte read_byte(viod){byte i;byte value=0;for (i=8;i>0;i--){value>>=1;DQ=0;DQ=1;delay(1);if(DQ)value|=0x80;delay(6);}return(value);}//向1-wire总线上写一个字节void write_byte(char val){byte i;for (i=8;i>0;i--) //一次写一个字节{DQ=0;DQ=val&0x01;delay(5);DQ=1;val=val/2;}delay(5);}//读取温度char Read_Temperature(void){union{byte c[2];int x;}temp;ow_reset();write_byte(0xcc);write_byte(0xBE);temp.c[1]=read_byte();temp.c[0]=read_byte();ow_reset();write_byte(0xCC);write_byte(0x44);return temp.x/2;}参考资料:你把这两个程序组合就可以了PID算法PID算法是本程序中的核心部分。
1。
模拟PID 控制1.1 模拟PID 控制的原理常规的模拟PID 控制系统原理框图如图1所示,该系统由模拟PID 控制器和被控对象组成。
其中r(t )为系统给定值,c(t)为系统的实际输出值,给定值域实际输出值构成控制偏差e (t))()()(t c t r t e -= (1-1))(t e 作为PID 控制器的输入,)(t u 作为PID 控制器的输出和被控对象的输入.所以,模拟PID控制器的控制规律为⎥⎦⎤⎢⎣⎡++=⎰tdi p dt t de T dt t e T t e K t u 0)()(1)()( (1-2) 式中:p K ——比例系数; i T --积分时间常数;d T —-微分时间常数.对应的模拟PID 调节器的传递函数为:)11()()()(s T sT K s E s U s D d i p ++==(1—3)图1-1 模拟PID 控制结构框图1。
2 PID 控制器各部分的作用从式(1—2)看到,PID 控制器的控制输出由比例、积分、微分三部分组成。
这三部分分别是:(1)比例部分)(t e K P在比例部分,比例系数p K 的作用在于加快系统的响应速度,提高系统调节精度。
加大p K 值,可以提高系统的开环增益,加快系统的响应速度,减小系统稳态误差,从而提高系统的控制精度,但会降低系统的相对稳定性,甚至可能造成闭环系统不稳定,使系统动、静态特性变坏。
(2)积分部分⎰tip dt t e T K 0)(从积分部分的数学表达式可以知道,只要存在偏差,则它的控制作用就会不断积累。
由于积分作用,当输入e(t)消失后,输出信号的积分部分⎰tip dt t e T K 0)(有可能是一个不为零的常数。
可见,积分部分的作用可以消除系统的偏差。
在串联校正时,采用I 控制器可以提高系统的型别,以消除或减小系统的稳态误差,改善系统的稳态性能。
但积分控制使系统增加了一个位于原点的开环极点,使信号产生90°的相角滞后,于系统的稳定性不利。
位置式PID的C语言实现第一步:定义PID变量结构体,代码如下:struct _pid{float SetSpeed; //定义设定值float ActualSpeed; //定义实际值float err; //定义偏差值float err_last; //定义上一个偏差值float Kp,Ki,Kd; //定义比例、积分、微分系数float voltage; //定义电压值(控制执行器的变量)float integral; //定义积分值}pid;控制算法中所需要用到的参数在一个结构体中统一定义,方便后面的使用。
第二部:初始化变量,代码如下:void PID_init(){printf("PID_init begin \n");pid.SetSpeed=0.0;pid.ActualSpeed=0.0;pid.err=0.0;pid.err_last=0.0;pid.voltage=0.0;pid.integral=0.0;pid.Kp=0.2;pid.Ki=0.015;pid.Kd=0.2;printf("PID_init end \n");}统一初始化变量,尤其是Kp,Ki,Kd三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节。
第三步:编写控制算法,代码如下:float PID_realize(float speed){pid.SetSpeed=speed;pid.err=pid.SetSpeed-pid.ActualSpeed;pid.integral+=pid.err;pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);pid.err_last=pid.err;pid.ActualSpeed=pid.voltage*1.0;return pid.ActualSpeed;}注意:这里用了最基本的算法实现形式,没有考虑死区问题,没有设定上下限,只是对公式的一种直接的实现,后面的介绍当中还会逐渐的对此改进。
PID控制算法介绍与实现一、PID的数学模型在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设计与实现过程,对于一般的研发人员来讲,应该是足够应对一般研发问题了,而难能可贵的是,在很多控制算法当中,PID控制算法又是最简单,最能体现反馈思想的控制算法,可谓经典中的经典。
经典的未必是复杂的,经典的东西常常是简单的,而且是最简单的。
PID算法的一般形式:PID算法通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节的加和。
这里我们规定(在t时刻):1.输入量为i(t)2.输出量为o(t)3.偏差量为err(t)=i(t)− o(t)u(t)=k p(err(t)+1T i.∫err(t)d t+T D d err(t)d t)二、PID算法的数字离散化假设采样间隔为T,则在第K个T时刻:偏差err(k)=i(k) - o(k)积分环节用加和的形式表示,即err(k) + err(k+1) + …微分环节用斜率的形式表示,即[err(k)- err(k−1)]/T; PID算法离散化后的式子:u(k)=k p(err(k)+TT i.∑err(j)+T DT(err(k)−err(k−1)))则u(k)可表示成为:u(k)=k p(err(k)+k i∑err(j)+k d(err(k)−err(k−1)))其中式中:比例参数k p:控制器的输出与输入偏差值成比例关系。
系统一旦出现偏差,比例调节立即产生调节作用以减少偏差。
特点:过程简单快速、比例作用大,可以加快调节,减小误差;但是使系统稳定性下降,造成不稳定,有余差。
积分参数k i:积分环节主要是用来消除静差,所谓静差,就是系统稳定后输出值和设定值之间的差值,积分环节实际上就是偏差累计的过程,把累计的误差加到原有系统上以抵消系统造成的静差。
微分参数k d:微分信号则反应了偏差信号的变化规律,或者说是变化趋势,根据偏差信号的变化趋势来进行超前调节,从而增加了系统的快速性。
PID控制当今的自动控制技术都是基于反馈的概念。
反馈理论的要素包括三个部分:测量、比较和执行。
测量关心的变量,与期望值相比较,用这个误差纠正调节控制系统的响应。
这个理论和应用自动控制的关键是,做出正确的测量和比较后,如何才能更好地纠正系统。
比例控制(P):比例控制是最常用的控制手段之一,比方说我们控制一个加热器的恒温100度,当开始加热时,离目标温度相差比较远,这时我们通常会加大加热,使温度快速上升,当温度超过100度时,我们则关闭输出,通常我们会使用这样一个函数e(t) = SP –y(t);u(t) = e(t)*PSP——设定值、e(t)——误差值、y(t)——反馈值、u(t)——输出值、P——比例系数滞后性不是很大的控制对象使用比例控制方式就可以满足控制要求,但很多被控对象中因为有滞后性。
也就是如果设定温度是200度,当采用比例方式控制时,如果P选择比较大,则会出现当温度达到200度输出为0后,温度仍然会止不住的向上爬升,比方说升至230度,当温度超过200度太多后又开始回落,尽管这时输出开始出力加热,但温度仍然会向下跌落一定的温度才会止跌回升,比方说降至170度,最后整个系统会稳定在一定的范围内进行振荡。
如果这个振荡的幅度是允许的比方说家用电器的控制,那则可以选用比例控制.比例积分控制(PI):积分的存在是针对比例控制要不就是有差值要不就是振荡的这种特点提出的改进,它常与比例一块进行控制,也就是PI控制。
其公式有很多种,但大多差别不大,标准公式如下:u(t) = Kp*e(t) + Ki∑e(t) +u0u(t)——输出、Kp——比例放大系数、Ki——积分放大系数、e(t)——误差、u0——控制量基准值(基础偏差)大家可以看到积分项是一个历史误差的累积值,如果光用比例控制时,我们知道要不就是达不到设定值要不就是振荡,在使用了积分项后就可以解决达不到设定值的静态误差问题,比方说一个控制中使用了PI控制后,如果存在静态误差,输出始终达不到设定值,这时积分项的误差累积值会越来越大,这个累积值乘上Ki后会在输出的比重中越占越多,使输出u(t)越来越大,最终达到消除静态误差的目的。
PID控制算法的C语言实现一 PID算法原理最近两天在考虑一般控制算法的C语言实现问题,发现网络上尚没有一套完整的比较体系的讲解。
于是总结了几天,整理一套思路分享给大家。
在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设计与实现过程,对于一般的研发人员来讲,应该是足够应对一般研发问题了,而难能可贵的是,在我所接触的控制算法当中,PID控制算法又是最简单,最能体现反馈思想的控制算法,可谓经典中的经典。
经典的未必是复杂的,经典的东西常常是简单的,而且是最简单的,想想牛顿的力学三大定律吧,想想爱因斯坦的质能方程吧,何等的简单!简单的不是原始的,简单的也不是落后的,简单到了美的程度。
先看看PID算法的一般形式:PID的流程简单到了不能再简单的程度,通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节的加和。
这里我们规定(在t时刻):1.输入量为rin(t);2.输出量为rout(t);3.偏差量为err(t)=rin(t)-rout(t);pid的控制规律为理解一下这个公式,主要从下面几个问题着手,为了便于理解,把控制环境具体一下:1.规定这个流程是用来为直流电机调速的;2.输入量rin(t)为电机转速预定值;3.输出量rout(t)为电机转速实际值;4.执行器为直流电机;5.传感器为光电码盘,假设码盘为10线;6.直流电机采用PWM调速转速用单位转/min表示;不难看出以下结论:1.输入量rin(t)为电机转速预定值(转/min);2. 输出量rout(t)为电机转速实际值(转/min);3.偏差量为预定值和实际值之差(转/min);那么以下几个问题需要弄清楚:1.通过PID环节之后的U(t)是什么值呢?2.控制执行器(直流电机)转动转速应该为电压值(也就是PWM占空比)。
3.那么U(t)与PWM之间存在怎样的联系呢?/user1/3407/archives/2006/33541.html(见附录1)这篇文章上给出了一种方法,即,每个电压对应一个转速,电压和转速之间呈现线性关系。
51单片机PID算法程序(一)PID算法(原创文章,转载请注明出处/tengjingshu) 比例,积分,微分的线性组合,构成控制量u(t),称为:比例(Proportional)、积分(Integrating)、微分(Differentiation)控制,简称PID控制图1控制器公式在实际应用中,可以根据受控对象的特性和控制的性能要求,灵活地采用不同的控制组合,构成比例(P)控制器比例+积分(PI)控制器比例+积分+微分(PID)控制器式中或式中控制系统中的应用在单回路控制系统中,由于扰动作用使被控参数偏离给定值,从而产生偏差。
自动控制系统的调节单元将来自变送器的测量值与给定值相比较后产生的偏差进行比例、积分、微分(PID)运算,并输出统一标准信号,去控制执行机构的动作,以实现对温度、压力、流量、也为及其他工艺参数的自动控制。
比例作用P只与偏差成正比;积分作用I是偏差对时间的积累;微分作用D 是偏差的变化率;比例(P)控制比例控制能迅速反应误差,从而减少稳态误差。
除了系统控制输入为0和系统过程值等于期望值这两种情况,比例控制都能给出稳态误差。
当期望值有一个变化时,系统过程值将产生一个稳态误差。
但是,比例控制不能消除稳态误差。
比例放大系数的加大,会引起系统的不稳定。
图2比例(P)控制阶跃响应积分(I)控制在积分控制中,控制器的输出与输入误差信号的积分成正比关系。
为了减小稳态误差,在控制器中加入积分项,积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。
这样,即使误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减少,直到等于零。
积分(I)和比例(P)通常一起使用,称为比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
如果单独用积分(I)的话,由于积分输出随时间积累而逐渐增大,故调节动作缓慢,这样会造成调节不及时,使系统稳定裕度下降。
图3积分(I)控制和比例积分(PI)控制阶跃相应微分(D)控制在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。
51单片机PID算法程序(三)增量式PID控制算法前言在之前的两篇文章中,我们分别介绍了基础PID算法和位置式PID控制算法。
在本文中,我们将介绍另一种常见的PID算法——增量式PID控制算法,以及如何在51单片机上实现增量式PID控制算法。
增量式PID控制算法简介增量式PID控制算法与位置式PID控制算法最大的区别在于输出控制量的计算方式不同。
位置式PID算法的输出控制量是与目标值的误差和历史误差之和的积分和误差的比例和微分,而增量式PID算法的输出控制量只与误差和历史误差的差值有关。
在增量式PID控制算法中,输出控制量的计算方式如下:$$ OutPut=K_p \\cdot Err+K_i \\cdot \\Delta Err+K_d \\cdot \\Delta^2 Err $$ 其中,K p、K i和K d分别是比例、积分和微分系数。
增量式PID控制算法的优点在于可以避免积分饱和、能够快速响应控制量变化,因此在某些要求高响应速度的应用中,常选择使用增量式PID控制算法。
51单片机上的增量式PID控制算法相比较于位置式PID控制算法,增量式PID控制算法的实现更加复杂,需要考虑历史误差的存储、误差的差值计算等问题。
因此,在51单片机上实现增量式PID控制算法需要一些特殊的处理方式。
我们可以通过以下三个步骤来实现增量式PID控制算法:步骤一:初始化变量在增量式PID控制算法中,需要定义一些变量,如上一次的误差值和输出控制量等。
因此,在使用增量式PID控制算法之前,需要先初始化这些变量。
//定义变量double set_point=0; //目标值double process_pv=0; //实际值double Kp=1,Ki=1,Kd=1; //PID参数double last_error=0,prev_error=0; //历史误差double output=0, dInput=0; //输出控制量和误差的差值double output_max=100.0,output_min=-100.0; //控制量范围//初始化变量void PID_Init(){last_error = 0;prev_error = 0;dInput = 0;output = 0;}步骤二:控制量计算根据增量式PID控制算法的公式,我们可以计算控制量的值。
增量式pid算法
增量式 PID 控制算法是一种改进的 PID 控制算法,它避免了
每次更新 PID 控制器输出时重新计算所有的控制参数。
该算
法将 PID 控制器的输出信号视为增量(差量)信号,即在前
一次控制信号基础上作出新的调整。
实现增量式 PID 算法的关键是保存前一次控制器的输出信号
以及相应的误差。
在每次控制周期内,首先根据当前的误差计算出 PID 控制器的增量部分,然后用前一次的控制信号加上
增量部分得到新的控制信号。
增量式 PID 算法的公式为:
Output(n) = Output(n-1) + Kp * (Error(n) - Error(n-1)) + Ki *
Error(n) + Kd * (Error(n) - 2 * Error(n-1) + Error(n-2))
其中,Output(n) 表示第 n 次控制的输出信号,Output(n-1) 表
示第n-1 次控制的输出信号,Error(n) 表示第n 次控制的误差,Error(n-1) 表示第 n-1 次控制的误差,Error(n-2) 表示第 n-2 次
控制的误差,Kp、Ki 和Kd 分别表示比例、积分和微分增益。
增量式 PID 算法的优点是可以减少计算量,提高控制器的响
应速度。
然而,由于增量式 PID 算法使用误差的差值计算增
量部分,因此对于系统初始状态的响应较慢。
此外,如果系统具有较大的噪声干扰或非线性特性,增量式 PID 算法可能出
现较大的误差累积。
因此,在实际应用中需要根据具体情况选择适当的 PID 控制算法。
PID专题及C语⾔的实现注意:任何算法使⽤程序表⽰,都得将算法离散化,以下的算法公式及代码都是将连续函数离散化后的表⽰结果。
个⼈鄙见,请多多指导。
问题⼀:PID计算结果与实际信号的对应关系[5]?位置式PID计算结果表⽰信号量的多少,增量式PID计算结果表⽰信号量的增多或减少多少。
⼀般来说: 位置式PID计算结果⽤0~1来表⽰控制信号的绝对⼤⼩, ⽽增量式PID计算结果⽤-1~1来表⽰控制信号的相对⼤⼩。
例如:⼯业设备通常采⽤4mA~20mA控制信号,PID计算结果⽤0~1来表⽰。
对于位置式PID来说: 0来表⽰应该向设备输如4mA的控制信号, 0.5则表⽰向设备输如12mA的控制信号, 1则表⽰向设备输如20mA的控制信号。
对于增量式PID来说: 若当前控制信号⼤⼩为6mA,⽽增量式PID的计算结果为0.2, 则表⽰控制信号应该从6mA增⼤到6mA+(20mA-4mA)*20%=9.2mA; 若当前控制信号⼤⼩为16mA,⽽增量式PID的计算结果为-0.2, 则表⽰控制信号应该从16mA减⼩到16mA-(20mA-4mA)*20%=12.8mA。
问题⼆:位置式pid与增量式pid有何区别和联系?(1)位置式pid将误差累加,增量式pid与当前及前两次误差有关,增量式pid是位置式pid的微分。
(2)位置式pid计算结果直接作⽤于执⾏机构,增量式pid计算结果只是上次控制量的增量。
(3)位置式pid需要积分限幅和输出限幅,增量式pid只需要输出限幅。
(4)从计算公式来看,位置式pid的P参数对应增量式pid的I参数,位置式pid的D参数对应增量式pid的P参数。
(5) 位置式pid应⽤于不带记忆功能的执⾏机构,增量式pid应⽤于带记忆功能的执⾏机构。
//DC-DC数字电源可以设置成带记忆功能的执⾏机构,也可以设置成不带记忆功能的执⾏机构。
带PFC的Boost电路,好像是不带记忆功能的执⾏机构。
PID控制算法的C语言实现精修订一、算法的实现步骤1.初始化PID参数:设定比例系数Kp、积分系数Ki和微分系数Kd的初值。
一般情况下,可以根据系统的特性进行经验调整。
2.设置控制目标:设定系统需要达到的目标值。
3.读取当前系统的测量值:使用传感器或其他设备获取当前系统的实际测量值。
4.计算系统误差:将目标值减去实际测量值,得到系统的误差。
5.计算PID控制量:将控制量设为比例项、积分项和微分项的和。
比例项为误差乘以比例系数Kp,积分项为误差的累积乘以积分系数Ki,微分项为误差变化率乘以微分系数Kd。
6.更新PID参数:根据实际情况,可调整PID参数的值。
一般情况下,可以使用经验调整方法,如试探法或模拟法。
7.输出控制量:将PID控制量作为输出,在系统中执行相应的控制操作,如调节电机的转速或改变阀门的开度。
8.循环执行以上步骤,直到系统达到控制目标或终止算法。
二、参数调整方法1.经验调整法:根据系统的特性和控制要求,选择合适的PID参数初值,通过实验或仿真来逐步调整参数,使系统达到最佳控制效果。
2. Ziegler-Nichols法则:利用开环试验的响应特性,通过确定系统的临界增益和周期,计算出PID参数。
该方法相对简单,但对系统的稳定性要求较高。
3.自整定法:利用系统的模型参数,结合在线参数调整技术,通过试错调整来获取最佳PID参数。
方法复杂度较高,但能够适应系统动态性变化较大的情况。
4.基于优化算法的自适应调整法:利用遗传算法、粒子群算法等优化算法,通过迭代计算获得最佳PID参数。
该方法不需要系统模型,但需要大量的计算和优化算法的实现。
三、实际应用案例假设有一个加热器,需要将温度控制在一个设定值范围内。
可以使用PID控制算法实现温度的稳定控制。
1.初始化PID参数:设定比例系数Kp=1,积分系数Ki=0.5和微分系数Kd=0.22.设置控制目标:设定温度控制的目标范围为35℃到40℃。
3.读取当前系统的温度值:使用温度传感器读取当前系统的实际温度值。
PID控制原理和特点工程实际中,应用最为广泛调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。
PID 控制器问世至今已有近70年历史,它以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制主要技术之一.当被控对象结构和参数不能完全掌握,或不到精确数学模型时,控制理论其它技术难以采用时,系统控制器结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便.即当我们不完全了解一个系统和被控对象﹐或不能有效测量手段来获系统参数时,最适合用PID控制技术。
PID控制,实际中也有PI和PD控制.PID控制器就是系统误差,利用比例、积分、微分计算出控制量进行控制。
1、比例控制(P):比例控制是最常用的控制手段之一,比方说我们控制一个加热器的恒温100度,当开始加热时,离目标温度相差比较远,这时我们通常会加大加热,使温度快速上升,当温度超过100度时,我们则关闭输出,通常我们会使用这样一个函数e(t) = SP – y(t)-u(t) = e(t)*PSP——设定值e(t)——误差值y(t)——反馈值u(t)——输出值P——比例系数滞后性不是很大的控制对象使用比例控制方式就可以满足控制要求,但很多被控对象中因为有滞后性。
也就是如果设定温度是200度,当采用比例方式控制时,如果P选择比较大,则会出现当温度达到200度输出为0后,温度仍然会止不住的向上爬升,比方说升至230度,当温度超过200度太多后又开始回落,尽管这时输出开始出力加热,但温度仍然会向下跌落一定的温度才会止跌回升,比方说降至170度,最后整个系统会稳定在一定的范围内进行振荡。
如果这个振荡的幅度是允许的比方说家用电器的控制,那则可以选用比例控制2、比例积分控制(PI):积分的存在是针对比例控制要不就是有差值要不就是振荡的这种特点提出的改进,它常与比例一块进行控制,也就是PI控制。
其公式有很多种,但大多差别不大,标准公式如下:u(t) = Kp*e(t) + Ki∑e(t) +u0u(t)—-输出Kp--比例放大系数Ki——积分放大系数e(t)——误差u0——控制量基准值(基础偏差)大家可以看到积分项是一个历史误差的累积值,如果光用比例控制时,我们知道要不就是达不到设定值要不就是振荡,在使用了积分项后就可以解决达不到设定值的静态误差问题,比方说一个控制中使用了PI控制后,如果存在静态误差,输出始终达不到设定值,这时积分项的误差累积值会越来越大,这个累积值乘上Ki 后会在输出的比重中越占越多,使输出u(t)越来越大,最终达到消除静态误差的目的PI两个结合使用的情况下,我们的调整方式如下:1、先将I值设为0,将P值放至比较大,当出现稳定振荡时,我们再减小P值直到P值不振荡或者振荡很小为止(术语叫临界振荡状态),在有些情况下,我们还可以在些P值的基础上再加大一点。
c语言增量式 pid 积分分离抗积分饱和并级C语言增量式PID控制器与积分分离、抗积分饱和、并级控制的应用【导语】在控制系统中,PID控制器是一种广泛使用的经典控制算法。
然而,传统的PID控制器在某些特定情况下可能会遇到饱和和抖动等问题。
为了解决这些问题,增量式PID控制器应运而生。
本文将深入探讨C 语言增量式PID控制器的原理和应用,特别关注积分分离、抗积分饱和以及并级控制的技术指导。
一、增量式PID控制器的原理1. PID控制器概述PID控制器是由比例项(P项)、积分项(I项)和微分项(D项)组成的控制算法。
其中,P项用于响应当前误差,I项用于消除系统的稳态误差,D项用于抑制系统的过冲和震荡。
PID控制器的输出可以通过反馈回路作用于系统,以使系统的输出尽可能接近给定的目标值。
2. 增量式PID控制器的基本概念增量式PID控制器是对传统PID控制器的改进,它通过将PID控制器的输入设置为增量形式,有效地解决了饱和和抖动等问题。
增量式PID控制器通过计算当前误差与上一时刻误差的差值,得到增量值,然后累加增量值来获得控制器的输出信号。
二、积分分离技术1. 积分分离概述积分分离技术是增量式PID控制器中的一项关键技术。
传统PID控制器在存在饱和时,积分作用会导致系统的超调和震荡。
而积分分离技术则将PID控制器的积分项与比例项分离,将积分项的计算放在控制器的前端,使其不受饱和的影响。
2. 积分分离原理积分分离技术的原理是通过计算误差的变化率来代替传统PID控制器中的积分项,从而避免了积分项被饱和干扰的问题。
通过计算误差的增量和减量,控制器可以更加灵活地调整输出信号,提高系统的稳定性和响应速度。
三、抗积分饱和技术1. 抗积分饱和概述抗积分饱和技术是用来解决传统PID控制器中积分项饱和问题的一种方法。
当系统的积分项受到限幅作用时,传统PID控制器的性能会受到影响。
通过采用抗积分饱和技术,可以有效地解决这一问题。
#include<stdio.h>#include<stdlib.h>int count;float incrementSpeed;//第一步:定义PID变量结构体struct _pid{float SetSpeed; //定义设定值float ActualSpeed; //定义实际值float err; //定义偏差值float err_next; //定义上一个偏差值float err_last; //定义最上前的偏差值float Kp,Ki,Kd; //定义比例、积分、微分系数}pid;//第二部:初始化变量(统一初始化变量,尤其是Kp,Ki,Kd三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节)void PID_init(){pid.SetSpeed=0.0;pid.ActualSpeed=0.0;pid.err=0.0;pid.err_last=0.0;pid.err_next=0.0;pid.Kp=0.2;pid.Ki=0.015;pid.Kd=0.2; }//第三步:编写控制算法float PID_realize(float speed){pid.SetSpeed=speed;pid.err=pid.SetSpeed-pid.ActualSpeed;incrementSpeed=pid.Kp*(pid.err-pid.err_next)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pi d.err_last);pid.ActualSpeed+=incrementSpeed;pid.err_last=pid.err_next;pid.err_next=pid.err;return pid.ActualSpeed;}//下面是测试代码int main(){ PID_init();count=0;while(count<1000){ float speed=PID_realize(200.0); printf("%f\n",speed); count++;}return 0;}//运行后的1000个数据为。
增量式PID 控制算法程序( 汇编).********增量式PID 控制算法程序***********;T、TD TI、KP依次从30H, 33H, 36H, 39H开始。
;A , B, C的值依次存在BL0CK,1 BL0CK2 BL0CK3勺地址里这里R(k) 给的是定值;0RG 0000HBL0CK1 EQU 43H ;A,B ,C BL0CK2 EQU 46HBL0CK3 EQU 49HUK EQU 4CH ;存结果UKRK EQU 50HEK EQU 53H ;存放偏差值E(k)的始址EK1 EQU 56H ;存放E(k-1)的始址EK2 EQU 59H ;存放E(k-2) 的始址CK EQU 5CH ;采样数据始址BUFF EQU 60H ;暂存区BUFF1 EQU 63HBUFF2 EQU 66HREC EQU 69HTEST:MOV RK,#01H 常数Rk 的BCD码浮点数MOV RK+1,#12H ;1.25 MOVRK+2,#50HMOV 3CH,#01H 常数1 的BCD码浮点数MOV 3DH,#10HMOV 3EH,#00HMOV 40H,#01H 常数2 的BCD码浮点数MOV 41H,#20HMOV 42H,#00HMOV 30H,#01H ;T的BCD码浮点数MOV 31H,#23H ;2.34 MOV 32H,#40HMOV 33H,#01H ;Td的BCD码浮点数MOV 34H,#35H ;3.54 MOV 35H,#40HMOV 36H,#01H ;Ti 的BCD码浮点数MOV 37H,#11H ;1.12 MOV 38H,#20HMOV 39H,#01H ;Kp的BCD码浮点数MOV 3AH,#12H ;1.25 MOV 3BH,#50H MOV R0,#RK ;指向,,, 码浮点操作数LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#3CHLCALL BTOFMOV R0,#40HLCALL BTOFMOV R0,#39HLCALL BTOFMOV R0,#36H ;指向,,, 码浮点操作数Ti LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#33H ;指向,,, 码浮点操作数Td LCALL BTOF ;将其转换成二进制浮点操作数MOV R0,#30H ;指向,,, 码浮点操作数T LCALL BTOF ;将其转换成二进制浮点操作数MOV R1, #BUFF1 保存30H 中的值即T 值LCALL FMOVR0MOV R1, #36H ;计算A值(1+T/Ti+Td/T).KpLCALL FDIVMOV R1,#3CH ;常数1LCALL FADDMOV R0,#33H保存33H中的值MOV R1,#BUFFLCALL FMOVR0MOV R1,#BUFF1LCALL FDIVMOV R1,#30H ;30H里存的是T/Ti+1 LCALL FADDMOV R1,#39HLCALL FMULMOV R1 ,#BLOCK1 将结果保存在BLOCK中LCALL FMOVR0 MOV R1,#BUFF1 ;30H恢复原值MOV R0,#30HLCALL FMOVMOV R1,#BUFF ;33H恢复原值MOV R0,#33HLCALL FMOVMOV R0,#40H 计算B 的值Kp.(1+2.Td/T)MOV R1,#33HLCALL FMULMOV R1,#30HLCALL FDIVMOV R1,#3CHLCALL FADDMOV R1,#39HLCALL FMULMOV R1,#BLOCK2保存B 值到BLOCK中LCALL FMOVR0 MOV R0,#39H 计算C 的值Kp.Td/T MOV R1,#33HLCALL FMULMOV R1,#BLOCK3保存C值到BLOCK中LCALL FMOVROMOV R0,#EK1 将EK1, EK2设初值0 LCALL FCLRMOV RO,#EK2LCALL FCLRMOV REC,#03H 设; 置采样次数LOOP: MOV CK,#7eH ;采样数据暂时给了一个定值MOV CK+1,#21H ;0.002112 MOV CK+2,#12HMOV R0,#CKLCALL BTOFMOV R0,#RK保存R(k)中的值MOV R1,#BUFFLCALL FMOVR0MOV R1,#CKLCALL FSUB ;计算R(k)-C(k) 的值送给E(k) MOV R1,#EKLCALL FMOVR0MOV R1,#BUFF 恢复RK的值释放BUFF MOV R0,#RKLCALL FMOVMOV R0,#BLOCK2将B.e(k-I)的值暂存在BUFF1中MOV R1,#BUFF 保存BLCALL FMOVR0MOV R1,#EK1LCALL FMULAoi/\id nnvon乙归#3 AOI/\I 才(乙-母AOI/\I aoid nnvon 用嗨嫌冲悬曲o日w^n: >in#l od AOIAIAoi/\id nnvon ddna w# v MM ddnatfLd AOIAI0dAOi/\id nnvon 申MCIAOIAIaavd nnvon 乙ddna#1 Ld AOIAI ansd nnvon fe->i)39+(k>i)3 a-(>i)3 v ®>in #44 HdnatfLd AOIAI nniAidnnvon >i3#l Ld AOIAI 0dAOi/\id nnvon ddnatfLd AOIAI(>i)3 v: ^oonatfod AOIAIAoi/\id nnvon ddna MM ddnatfLd AOIAI 0dAOi/\idnnvon 乙ddna#1 Ld AOIAI nniAid nnvon 2>i3#l LdAOIAI 0dAOi/\id nnvon o ddna#1AOIAI 竝run日丑型島粵阴(3->i)90 Boioonatfod AOIAIAoi/\id nnvon ddna w#a MM ddnatfLd AOIAIMOV R1,#EKMOV R0,#EK1LCALL FMOVLCALL DELAY ;等待采样时刻DJNZ REC,NEXT1SJMP $NEXT1: LJMP LOOPDELAY: MOV R7,#02H DELAY1: MOV R6,#0FFH DELAY2: DJNZ R6,DELAY2 DJNZR7,DELAY1RET; (,) 标号: ,,,, 功能: 浮点数格式化; 入口条件: 待格式化浮点操作数在[R0] 中。
PID基础公式及程序仅⽤于备份本⼈所写笔记,如有错误或不完善之处还请包含。
转载请注明出处!位置式离散 PID:$ Pwm = Kp \times e(k) + Ki \times \sum e(k) + Kd \times [e(k) - e(k-1)] $ $ e(k) $ : 本次偏差$ e(k-1) $ : 上次偏差$ \sum e(k) $ : $ e(k) $ 以及之前的偏差的累计和,其中 $ k $ 为 $ 1, 2, 3\ldots k $$ Pwm $ : 代表输出C 语⾔的实现:// 位置式离散 PID// P = Kp * err;// I = Ki * integral_err;// D = Kd * (err - last_err);// Pwm = P + I + D;float PositionPid(int encoder, int target) {static float err = 0, last_err = 0, integral_err = 0, pwm = 0;float kp = 1, ki = 1, kd = 1;err = encoder - target; // 计算偏差integral_err += err; // 求出偏差积分pwm = kp * err + ki * integral_err + kd * (err - last_err);last_err = err; // 保存上⼀次偏差return pwm; // 输出}在舵机⾓度控制闭环系统⾥,只使⽤ PD 控制,因此可将 PID 控制简化为此公式:$ Pwm = Kp \times e(k) + Kd \times [e(k) - e(k-1)] $代码更改如下:// 位置式离散 PD// P = Kp * err;// D = Kd * (err - last_err);// Pwm = P + D;float PositionPid(int encoder, int target) {static float err = 0, last_err = 0, integral_err = 0, pwm = 0;float kp = 1, ki = 1, kd = 1;err = encoder - target; // 计算偏差pwm = kp * err + kd * (err - last_err);last_err = err; // 保存上⼀次偏差return pwm; // 输出}PID 参数整定:P:⽤于提⾼相应速度I:⽤于减⼩静差D:⽤于抑制震荡增量式离散 PID:$ Pwm += Kp × [e(k) - e(k-1)] + Ki × e(k) + Kd × [e(k) - 2e(k-1) + e(k-2)] $ $ e(k) $ : 本次偏差$ e(k-1) $ : 上次的偏差$ e(k-2) $ : 上上次的偏差$ Pwm $ : 代表增量输出C 语⾔实现:// 增量式离散 PID// P = Kp * (err - last_err);// I = Ki * err;// D = Kd * (err - 2 * last_err + before_err);// Pwm += P + I + D;float IncrementalPid(int encoder, int target) {static float err = 0, last_err = 0, before_err = 0, pwm = 0;float kp = 1, ki = 1, kd = 1;err = encoder - target; // 计算偏差pwm += kp * (err - last_err) + ki * err +kd * (err - 2 * last_err + before_err); // 增量式 PI 控制器before_err = last_err; // 保存上上次偏差last_err = err; // 保存上⼀次偏差return pwm; // 增量输出}在速度控制闭环系统⾥,只使⽤ PI 控制,因此可将 PID 控制简化为此公式:$ Pwm += Kp × [e(k) - e(k-1)] + Ki × e(k) $代码更改如下:// 增量式离散 PI// P = Kp * (err - last_err);// I = Ki * err;// Pwm += P + I;float IncrementalPid(int encoder, int target) {static float err = 0, last_err = 0, pwm = 0;float kp = 1, ki = 1, kd = 1;err = encoder - target; // 计算偏差pwm += kp * (err - last_err) + ki * err; // 增量式 PI 控制器last_err = err; // 保存上⼀次偏差return pwm; // 增量输出}。
PID算法的C语言实现PID算法是一种广泛应用于工业控制系统中的经典控制算法。
它通过测量系统的实际输出值与期望输出值之间的误差,并使用一组权重因子来计算一个控制输入量,以使系统的输出值尽可能接近期望输出值。
PID算法由比例(Proportional)、积分(Integral)和微分(Derivative)三个部分组成,可以用以下公式表示:u(t) = Kp * e(t) + Ki * ∫e(t)dt + Kd * de(t)/dt其中,u(t)是控制输入量,Kp、Ki和Kd分别为比例、积分和微分系数,e(t)为系统输出值与期望输出值之间的误差,de(t)/dt为误差的变化率。
下面是PID算法的C语言实现示例:```c#include <stdio.h>//PID参数float Kp = 1.0;float Ki = 0.5;float Kd = 0.2;//误差存储变量float lastError = 0;float integral = 0;//PID控制函数float PIDController(float setpoint, float actual)//计算误差float error = setpoint - actual;//计算比例项float proportional = Kp * error;//计算积分项integral += error;//计算微分项float derivative = error - lastError;//计算控制输入量float output = proportional + (Ki * integral) + (Kd * derivative);//更新误差存储变量lastError = error;return output;int maifloat setpoint = 10.0; // 期望输出值float actual = 0.0; // 实际输出值for (int i = 0; i < 10; i++)float controlInput = PIDController(setpoint, actual);printf("Control Input: %f\n", controlInput);//模拟实际系统响应actual += controlInput;}return 0;```在上述代码中,我们定义了一组PID参数(Kp、Ki和Kd),以及存储误差和积分项的变量(lastError和integral)。