PID控制算法的C语言实现 完整版
经典控制PID控制器-C语言代码实现

经典控制PID控制器-C语言代码的实现// 1.定义PID变量结构体struct _pid{float SetValue; //定义设定值float ActualValue; //定义实际值float err; //定义偏差值float err_last; //定义上一个偏差值float Kp,Ki,Kd; //定义比例、积分、微分系数float ActuatorCtrlValue; //控制执行器变量float integral; //定义积分值float Umax; //定义实际值的上限float Umin; //定义实际值得下限float errDisIntegralVar; //定义接触积分环节的偏差限值float ControlOutValue;//定义控制输出}pid;//2. PID算法实现float PID_realize(float SetVar,float ActualVar,float UHigLim,float ULowLim,float ErrDisIntegralLim){int index;pid.SetValue=SetVar;pid.ActualValue=ActualVar;pid.Umax=UHigLim;pid.Umin=ULowLim;pid.err=pid.ActualValue-pid.SetValue;pid.errDisIntegralVar=ErrDisIntegralLim;//积分饱和处理if (pid.ActualValue>pid.Umax){if (abs(pid.err)>pid.errDisIntegralVar){index=1;if (pid.err>0){pid.integral+=1.3*pid.err;}}else{index=1;if (pid.err>0){ pid.integral+=1.2*pid.err;}}}else if(pid.ActualValue<pid.Umin){if (abs(pid.err)>pid.errDisIntegralVar){index=1;if (pid.err<0){pid.integral+=1.3*pid.err;}}else{index=1;if (pid.err<0){pid.integral+=1.2*pid.err;}}}else{if (abs(pid.err)>pid.errDisIntegralVar){index=1;pid.integral+=1.1*pid.err;}else{index=1;pid.integral+=pid.err;}}pid.ControlOutValue=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pi d.err_last);pid.err_last=pid.err;return pid.ControlOutValue;}。
PID控制算法的C语言实现(完整版)

PID控制算法的C语言实现(完整版) 在现代工业生产中,为了实现对生产过程的精确控制,我们需要采用一种能够根据实际需求自动调整参数的控制算法。
PID(Proportional-Integral-Derivative)控制算法就是这样一种广泛应用于工业控制系统的算法。
本文将详细介绍PID控制算法的C语言实现,包括算法的基本原理、实现方法以及注意事项。
我们来了解一下PID控制算法的基本原理。
PID控制器由三个部分组成:比例(P)、积分(I)和微分(D)。
这三个部分分别对误差信号进行处理,然后将处理后的信号相加得到控制输出。
具体来说,比例部分根据误差信号的大小产生相应的控制作用;积分部分对误差信号进行累积,以消除系统的静差;微分部分对误差信号的变化趋势进行预测,以便及时调整控制策略。
通过这三个部分的综合作用,PID控制器能够实现对生产过程的精确控制。
接下来,我们来看一下如何用C语言实现PID控制算法。
我们需要定义一些变量来存储所需的参数和状态信息。
例如,我们需要定义比例系数Kp、积分系数Ki、微分系数Kd以及误差信号e等。
我们还需要定义一些变量来存储上一次的误差信号和积分项等。
这些变量的定义如下:```cdouble Kp, Ki, Kd; // 比例、积分、微分系数double e; // 当前误差信号double de; // 当前误差信号的导数double last_e; // 上一次的误差信号double integral; // 积分项有了这些变量之后,我们就可以开始实现PID控制器的计算过程了。
PID控制器的计算过程主要包括以下几个步骤:1. 计算误差信号:当前误差信号等于期望值与实际值之差。
2. 计算比例项:比例项等于当前误差信号乘以比例系数Kp;3. 计算积分项:积分项等于当前误差信号乘以积分系数Ki加上累积误差信号乘以积分系数Ki;4. 计算微分项:微分项等于当前误差信号的导数乘以微分系数Kd;5. 计算控制输出:控制输出等于比例项、积分项和微分项之和。
C语言实现PID算法

C语言实现PID算法PID算法是一种常用的控制算法,在工控系统中广泛应用。
下面将详细介绍C语言实现PID算法的步骤和代码。
PID算法是基于反馈的控制算法,通过对系统输出与期望输出之间的差异进行处理,生成一个控制器的输出信号,从而实现对系统状态的调节。
PID算法由比例(P)、积分(I)和微分(D)三个部分组成。
具体的计算公式为:输出值=Kp*(误差+1/Ti*积分项+Td*微分项)其中,Kp为比例系数,Ti为积分时间常数,Td为微分时间常数。
积分项为历史误差的累积,微分项为误差变化率的反馈。
下面是C语言实现PID算法的代码:```c//PID算法的数据结构typedef structdouble Kp; // 比例系数double Ti; // 积分时间常数double Td; // 微分时间常数double lastError; // 上一次的误差double integral; // 积分项}PID;void initPID(PID* pid, double Kp, double Ti, double Td)pid->Kp = Kp;pid->Ti = Ti;pid->Td = Td;pid->lastError = 0;pid->integral = 0;//更新PID算法的参数void updatePID(PID* pid, double error, double dt)double proportional, integral, derivative;//比例项proportional = pid->Kp * error;//积分项pid->integral += error * dt;integral = pid->Kp / pid->Ti * pid->integral;//微分项derivative = pid->Kp * pid->Td * (error - pid->lastError) / dt;//更新上一次的误差pid->lastError = error;//计算输出值double output = proportional + integral + derivative;//进行输出处理(例如对输出进行限幅)//...//输出控制信号//...```使用上述代码,可以通过调用`initPID`函数进行PID算法的初始化,并通过调用`updatePID`函数更新PID算法的参数和计算控制器的输出。
PID算法温控C语言

//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 Const unsigned int Integral; // 积分常数Integral Constunsigned int Derivative; // 微分常数Derivative Const unsigned 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); // 微分项}/***********************************************************温度比较处理子程序***********************************************************/compare_temper(){unsigned char i;if(set_temper>temper) //是否设置的温度大于实际温度{if(set_temper-temper>1) //设置的温度比实际的温度是否是大于1度{high_time=100; //如果是,则全速加热low_time=0;}else //如果是在1度范围内,则运行PID计算{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;TL0=0xe0;}/*****************************************************串行口中断服务程序,用于上位机通讯******************************************************/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;elsedata1=0;_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;TH0=0x2f;TL0=0x40;SCON=0x50;PCON=0x00;TH1=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++){}{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;}compare_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 算法(c语言)2010-01-27 08:53BC31 TC30 编译过,可运行。
PID算法程序范文

PID算法程序范文PID控制器是一种常用的反馈控制算法,用于实时地调整控制系统的输出,以使得被控对象的输出尽可能接近设定值。
PID控制器由比例项(P)、积分项(I)和微分项(D)组成,通过对这三个项的调节,可以实现对被控对象的精确控制。
下面是一个简单的PID算法程序的示例,使用C语言编写:```c#include <stdio.h>//定义PID参数#define KP 0.5 // 比例增益#define KI 0.2 // 积分增益#define KD 0.1 // 微分增益//定义全局变量int error = 0; // 当前误差int last_error = 0; // 上一次误差int integral = 0; // 积分项int derivative = 0; // 微分项int output = 0; // 控制器输出//定义被控对象模拟函数int simulate_plant(int control_input)static int actual_output = 0; // 被控对象的输出actual_output += control_input; // 模拟被控对象的响应return actual_output;//PID算法函数int pid_algorithm(int setpoint, int actual_output)error = setpoint - actual_output; // 计算当前误差//计算比例项int proportional = KP * error;//计算积分项integral = integral + error;int integral_term = KI * integral;//计算微分项derivative = error - last_error;int derivative_term = KD * derivative;//计算PID控制器的输出output = proportional + integral_term + derivative_term; //更新上一次误差供下一次计算使用last_error = error;return output;int mai//设置目标值和初始被控对象输出值int setpoint = 50;int actual_output = 0;//模拟实时控制过程,循环100次for (int i = 0; i < 100; ++i)//调用PID算法计算控制器输出int control_input = pid_algorithm(setpoint, actual_output);//更新被控对象的输出actual_output = simulate_plant(control_input);//输出当前相关变量值供调试printf("Error: %d, Control Input: %d, Actual Output: %d\n", error, control_input, actual_output);}return 0;```上述代码中,`KP`、`KI`和`KD`分别表示比例增益、积分增益和微分增益,根据实际控制系统的需求进行调节。
PID的C语言实现

位置式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;}注意:这里用了最基本的算法实现形式,没有考虑死区问题,没有设定上下限,只是对公式的一种直接的实现,后面的介绍当中还会逐渐的对此改进。
(完整word版)增量式PID控制C语言代码
// LastError=0
//Input: PID的P、I控制常数和之前的误差量(PID *pp)
//Return:
//////////////////////////////////////////////////////////////////////
void PIDInit (PID *pp) //PID参数初始化,都置0
//增量式PID算法(需要控制的不是控制量的绝对值,而是控制量的增量)
int pError,dError,iError;
long templ;
pError = ThisError-pp->LastError;
iError = ThisError;
dError = ThisError-2*(pp->LastError)+pp->PreError;
增量式PID控制C语言代码
增量式PID控制公式:
上面△u(k)是控制量增量,“增量式PID”就是直接以这个增量进行控制。
至于参数的整定,根据响应的情况调,比如,响应慢了,我就增大kp,或者减小kd,超调大了就减小kp或增大点kd,这个规律你可以看看PID三个参数的作用:)
////////////////////////////////////////////////////////////////
{
memset ( pp,0,sizeof(PID));
//memset()的函数,它可以一字节一字节地把整个数组设置为一个指定的值。
// memset()函数在mem.h头文件中声明,它把数组的起始地址作为其第一个参数,
//第二个参数是设置数组每个字节的值,第三个参数是数组的长度(字节数,不是元素个数)。
pid算法温度控制c语言程序
pid算法温度控制c语言程序PID算法是一种常用的温度控制算法,广泛应用于各种温度控制系统中。
在C语言中,我们可以通过编写程序来实现PID算法的温度控制功能。
我们需要了解PID算法的基本原理。
PID算法是通过对系统的反馈信号进行不断调整,使得系统的输出达到期望值。
PID算法由三个部分组成:比例控制、积分控制和微分控制。
比例控制根据反馈信号与期望值的差异来调整输出;积分控制根据反馈信号与期望值的累积差异来调整输出;微分控制根据反馈信号的变化率来调整输出。
在C语言中,我们可以使用变量来表示系统的输入、输出和期望值。
以下是一个简单的示例代码:```c#include <stdio.h>// 定义PID参数float Kp = 1.0; // 比例系数float Ki = 0.5; // 积分系数float Kd = 0.2; // 微分系数// 定义系统变量float setpoint = 25.0; // 期望值float input = 0.0; // 输入值float output = 0.0; // 输出值// 定义误差变量float error = 0.0; // 当前误差float last_error = 0.0; // 上一次误差float integral = 0.0; // 累积误差// PID算法函数float pid_algorithm(float setpoint, float input) {// 计算误差error = setpoint - input;// 计算比例控制float proportional = Kp * error;// 计算积分控制integral += error;float integral_control = Ki * integral;// 计算微分控制float derivative = Kd * (error - last_error); // 计算输出output = proportional + integral_control + derivative;// 更新误差last_error = error;return output;}int main(){// 模拟温度传感器的输入input = 23.5;// 调用PID算法函数output = pid_algorithm(setpoint, input);// 打印输出结果printf("Output: %.2f\n", output);return 0;}```在上述代码中,我们首先定义了PID算法的参数和系统变量。
C语言实现PID算法
C语言实现PID算法#include <stdio.h>struct _pid {int pv; /*integer that contains the process value*/int sp; /*integer that contains the set point*/float integral;float pgain;float igain;float dgain;int deadband;int last_error;};struct _pid warm,*pid;int process_point, set_point,dead_band;float p_gain, i_gain, d_gain, integral_val,new_integ;;/*------------------------------------------------------------------------pid_initDESCRIPTION This function initializes the pointers in the _pid structure to the process variable and the setpoint. *pv and *sp areinteger pointers.------------------------------------------------------------------------*/void pid_init(struct _pid *warm, int process_point, int set_point){struct _pid *pid;pid = warm;pid->pv = process_point;pid->sp = set_point;}/*------------------------------------------------------------------------pid_tuneDESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain), derivitive gain (d_gain), and the dead band (dead_band) ofa pid control structure _pid.------------------------------------------------------------------------*/void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band) {pid->pgain = p_gain;pid->igain = i_gain;pid->dgain = d_gain;pid->deadband = dead_band;pid->integral= integral_val;pid->last_error=0;}/*------------------------------------------------------------------------pid_setintegDESCRIPTION Set a new value for the integral term of the pid equation.This is useful for setting the initial output of thepid controller at start up.------------------------------------------------------------------------*/void pid_setinteg(struct _pid *pid,float new_integ){pid->integral = new_integ;pid->last_error = 0;}/*------------------------------------------------------------------------pid_bumplessDESCRIPTION Bumpless transfer algorithim. When suddenly changing setpoints, or when restarting the PID equation after anextended pause, the derivative of the equation can causea bump in the controller output. This function will helpsmooth out that bump. The process value in *pv shouldbe the updated just before this function is used.------------------------------------------------------------------------*/void pid_bumpless(struct _pid *pid){pid->last_error = (pid->sp)-(pid->pv);}/*------------------------------------------------------------------------pid_calcDESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positio nal form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangu lar integration is used, so this function must be repeated on a consistent time basis for accurate con trol.RETURN V ALUE The new output value for the pid loop.USAGE #include "control.h"*/float pid_calc(struct _pid *pid){int err;float pterm, dterm, result, ferror;err = (pid->sp) - (pid->pv);if (abs(err) > pid->deadband){ferror = (float) err; /*do integer to float conversion only once*/pterm = pid->pgain * ferror;if (pterm > 100 || pterm < -100){pid->integral = 0.0;}else{pid->integral += pid->igain * ferror;if (pid->integral > 100.0){pid->integral = 100.0;}else if (pid->integral < 0.0) pid->integral = 0.0;}dterm = ((float)(err - pid->last_error)) * pid->dgain;result = pterm + pid->integral + dterm;}else result = pid->integral;pid->last_error = err;return (result);}void main(void)float display_value;int count=0;pid = &warm;// printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");// scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);process_point = 30;set_point = 40;p_gain = (float)(5.2);i_gain = (float)(0.77);d_gain = (float)(0.18);dead_band = 2;integral_val =(float)(0.01);printf("The values of Process point, Set point, P gain, I gain, D gain \n");printf(" %6d %6d %4f %4f %4f\n", process_point, set_point, p_gain, i_gain, d_gain); printf("Enter the values of Process point\n");while(count<=20){scanf("%d",&process_point);pid_init(&warm, process_point, set_point);pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);pid_setinteg(&warm,0.0); //pid_setinteg(&warm,30.0);//Get input value for process pointpid_bumpless(&warm);// how to display outputdisplay_value = pid_calc(&warm);printf("%f\n", display_value);//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,warm.dgain);count++;}}PID算法/******************************************************************** *********************************** PID控制算法 PID Control Algorithm* 在仿真和实验中,航向预估控制方法和与之对比的常规控制方法的控制器均采用增量PID算法,* 且两者的比例、积分和微分系数一样.增量PID算法如式(7)所示:* ΔU = U(k)-U(k-1) =Kp*[e(k)-e(k-1)]+Ki*e(k)+Kd*[e(k)-2*e(k-1)+e(k-2)]* 其中:Kp、Ki、Kd分别为比例、积分和微分放大系数,u(k)表示第k个采样时刻的控制量,e(k)表示第k个采样时刻的航向输入偏差.********************************************************************* **********************************/void PID_Calc(int PID_EK){long deltaU,tmp;deltaU = (long)u_dbPIDKp.IntData*(PID_EK-PID_EK_1); // 增量计算deltaU +=(long)u_dbPIDKi.IntData*PID_EK;tmp = (long)PID_EK-(2*PID_EK_1)+PID_EK_2;deltaU +=tmp* u_dbPIDKd.IntData;PID_UK = PID_UK_1+deltaU; // 结果if(PID_UK>4095000) PID_UK = 4095000;else if(PID_UK<0) PID_UK=0;PID_UK_1 = PID_UK; // 保存新的K-1次输出值PID_EK_2 = PID_EK_1; // 保存新的K-1次输入值PID_EK_1 = PID_EK;}PID是比例,积分,微分的缩写,Uo(N)=P*E(N)+I*[E(N)+E(N-1)+...+E(0)]+D*[E(N)-E(N-1)]E-误差P--改变P 可提高响应速度,减小静态误差,但太大会增大超调量和稳定时间。
最全PID控制算法的C语言实现
最全PID控制算法的C语言实现PID控制算法是一种在控制系统中常用的反馈控制算法,用于根据实际测量值来调节输出来实现对系统状态的控制。
PID算法包含三个控制参数:比例常数(Kp)、积分常数(Ki)和微分常数(Kd)。
这三个参数分别调节了比例控制、积分控制和微分控制的比例,用于实现不同的控制效果。
下面是一个最全的PID控制算法的C语言实现示例:```c#include <stdio.h>//定义PID控制算法的参数float Kp = 1.0; // 比例常数float Ki = 0.5; // 积分常数float Kd = 0.2; // 微分常数//定义全局变量用于记录控制过程中的误差与累积误差float error = 0.0;float lastError = 0.0;float integral = 0.0;//定义PID控制函数float pidControl(float target, float current, float dt)//计算误差error = target - current;//计算累积误差integral += error * dt;//计算微分误差float derivative = (error - lastError) / dt;//计算PID输出float output = Kp * error + Ki * integral + Kd * derivative; //更新上一次误差lastError = error;return output;int mai//模拟控制过程float target = 100.0; // 目标值float current = 0.0; // 当前值float dt = 0.1; // 控制周期for(int i = 0; i < 100; i++)//调用PID控制函数float output = pidControl(target, current, dt);//更新当前值,模拟实际过程中的测量误差current += output * dt + 0.2;printf("Target: %.2f, Current: %.2f, Output: %.2f\n", target, current, output);}return 0;```上述代码通过定义全局变量来记录控制过程中的误差与累积误差,并在PID控制函数中进行计算和更新。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
P I D控制算法的C语言实现完整版集团标准化工作小组 [Q8QX9QT-X8QQB8Q8-NQ8QJ8-M8QMN]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之间存在怎样的联系呢(见附录1)这篇文章上给出了一种方法,即,每个电压对应一个转速,电压和转速之间呈现线性关系。
但是我考虑这种方法的前提是把直流电机的特性理解为线性了,而实际情况下,直流电机的特性绝对不是线性的,或者说在局部上是趋于线性的,这就是为什么说PID调速有个范围的问题。
具体看一下(见附录2)这篇文章就可以了解了。
所以在正式进行调速设计之前,需要现有开环系统,测试电机和转速之间的特性曲线(或者查阅电机的资料说明),然后再进行闭环参数整定。
这篇先写到这,下一篇说明连续系统的离散化问题。
并根据离散化后的特点讲述位置型PID和增量型PID的用法和C语言实现过程。
PID控制算法的C语言实现二 PID算法的离散化上一节中,我论述了PID算法的基本形式,并对其控制过程的实现有了一个简要的说明,通过上一节的总结,基本已经可以明白PID控制的过程。
这一节中先继续上一节内容补充说明一下。
1.说明一下反馈控制的原理,通过上一节的框图不难看出,PID控制其实是对偏差的控制过程;2.如果偏差为0,则比例环节不起作用,只有存在偏差时,比例环节才起作用。
3.积分环节主要是用来消除静差,所谓静差,就是系统稳定后输出值和设定值之间的差值,积分环节实际上就是偏差累计的过程,把累计的误差加到原有系统上以抵消系统造成的静差。
4.而微分信号则反应了偏差信号的变化规律,或者说是变化趋势,根据偏差信号的变化趋势来进行超前调节,从而增加了系统的快速性。
好了,关于PID的基本说明就补充到这里,下面将对PID连续系统离散化,从而方便在处理器上实现。
下面把连续状态的公式再贴一下:假设采样间隔为T,则在第K T时刻:偏差err(K)=rin(K)-rout(K);积分环节用加和的形式表示,即err(K)+err(K+1)+……;微分环节用斜率的形式表示,即[err(K)-err(K-1)]/T;从而形成如下PID离散表示形式:则u(K)可表示成为:至于说Kp、Ki、Kd三个参数的具体表达式,我想可以轻松的推出了,这里节省时间,不再详细表示了。
其实到这里为止,PID的基本离散表示形式已经出来了。
目前的这种表述形式属于位置型PID,另外一种表述方式为增量式PID,由U上述表达式可以轻易得到:那么:这就是离散化PID的增量式表示方式,由公式可以看出,增量式的表达结果和最近三次的偏差有关,这样就大大提高了系统的稳定性。
需要注意的是最终的输出结果应该为u(K)+增量调节值;PID的离散化过程基本思路就是这样,下面是将离散化的公式转换成为C语言,从而实现微控制器的控制作用。
PID控制算法的C语言实现三位置型PID的C语言实现上一节中已经抽象出了位置性PID和增量型PID的数学表达式,这一节,重点讲解C语言代码的实现过程,算法的C语言实现过程具有一般性,通过PID算法的C语言实现,可以以此类推,设计其它算法的C语言实现。
第一步:定义PID变量结构体,代码如下:struct _pid{float SetSpeed; 例系数Kp的作用是加快系统的响应速度,提高系统的调节精度。
Kp越大,系统的响应速度越快,系统的调节精度越高,但是容易产生超调,甚至会使系统不稳定。
Kp取值过小,则会降低调节精度,使响应速度缓慢,从而延长调节时间,是系统静态、动态特性变差;2.积分作用系数Ki的作用是消除系统的稳态误差。
Ki越大,系统的静态误差消除的越快,但是Ki过大,在响应过程的初期会产生积分饱和的现象,从而引起响应过程的较大超调。
若Ki过小,将使系统静态误差难以消除,影响系统的调节精度;3.微分系数Kd的作用是改善系统的动态特性,其作用主要是在响应过程中抑制偏差向任何方向的变化,对偏差变化进行提前预报。
但是kd过大,会使响应过程提前制动,从而延长调节时间,而且会降低系统的抗干扰性。
反应系统性能的两个参数是系统误差e和误差变化律ec,这点还是好理解的:首先我们规定一个误差的极限值,假设为Mmax;规定一个误差的比较大的值,假设为Mmid;规定一个误差的较小值,假设为Mmin;当abs(e)>Mmax时,说明误差的绝对值已经很大了,不论误差变化趋势如何,都应该考虑控制器的输入应按最大(或最小)输出,以达到迅速调整误差的效果,使误差绝对值以最大的速度减小。
此时,相当于实施开环控制。
当e*ec>0时,说明误差在朝向误差绝对值增大的方向变化,此时,如果abs(e)>Mmid,说明误差也较大,可考虑由控制器实施较强的控制作用,以达到扭转误差绝对值向减小的方向变化,并迅速减小误差的绝对值。
此时如果abs(e)<Mmid,说明尽管误差是向绝对值增大的方向变化,但是误差绝对值本身并不是很大,可以考虑控制器实施一般的控制作用,只需要扭转误差的变化趋势,使其向误差绝对值减小的方向变化即可。
当e*err<0且e*err(k-1)>0或者e=0时,说明误差的绝对值向减小的方向变化,或者已经达到平衡状态,此时保持控制器输出不变即可。
当e*err<0且e*err(k-1)<0时,说明误差处于极限状态。
如果此时误差的绝对值较大,大于Mmin,可以考虑实施较强控制作用。
如果此时误差绝对值较小,可以考虑实施较弱控制作用。
当abs(e)<Mmin时,说明误差绝对值很小,此时加入积分,减小静态误差。
上面的逻辑判断过程,实际上就是对于控制系统的一个专家判断过程。
(未完待续)PID控制算法的C语言实现十模糊算法简介在PID控制算法的C语言实现九中,文章已经对模糊PID的实质做了一个简要说明。
本来打算等到完成毕业设计,工作稳定了再着力完成剩下的部分。
鉴于网友的要求和信任,抽出时间来,对模糊PID做一个较为详细的论述,这里我不打算做出仿真程序了,但就基本概念和思路进行一下说明,相信有C语言基础的朋友可以通过这些介绍性的文字自行实现。
这篇文章主要说明一下模糊算法的含义和原理。
实际上模糊算法属于智能算法,智能算法也可以叫非模型算法,也就是说,当我们对于系统的模型认识不是很深刻,或者说客观的原因导致我们无法对系统的控制模型进行深入研究的时候,智能算法常常能够起到不小的作用。
这点是方便理解的,如果一个系统的模型可以轻易的获得,那么就可以根据系统的模型进行模型分析,设计出适合系统模型的控制器。
但是现实世界中,可以说所有的系统都是非线性的,是不可预测的。
但这并不是说我们就无从建立控制器,因为,大部分的系统在一定的条件和范围内是可以抽象成为线性系统的。
问题的关键是,当我们系统设计的范围超出了线性的范围,我们又该如何处理。
显然,智能算法是一条很不错的途径。
智能算法包含了专家系统、模糊算法、遗传算法、神经网络算法等。
其实这其中的任何一种算法都可以跟PID去做结合,而选择的关键在于,处理的实时性能不能得到满足。
当我们处理器的速度足够快速时,我们可以选择更为复杂的、精度更加高的算法。
但是,控制器的处理速度限制了我们算法的选择。
当然,成本是限制处理器速度最根本的原因。
这个道理很简单,51单片机和DSP的成本肯定大不相同。
专家PID和模糊PID是常用的两种PID选择方式。
其实,模糊PID适应一般的控制系统是没有问题。
文章接下来将说明模糊算法的一些基本常识。
模糊算法其实并不模糊。
模糊算法其实也是逐次求精的过程。
这里举个例子说明。
我们设计一个倒立摆系统,假如摆针偏差<5°,我们说它的偏差比较“小”;摆针偏差在5°和10°之间,我们说它的偏差处于“中”的状态;当摆针偏差>10°的时候,我们说它的偏差有点儿“大”了。
对于“小”、“中”、“大”这样的词汇来讲,他们是精确的表述,可问题是如果摆针偏差是3°呢,那么这是一种什么样的状态呢。
我们可以用“很小”来表述它。
如果是7°呢,可以说它是“中”偏“小”。
那么如果到了80°呢,它的偏差可以说“非常大”。
而我们调节的过程实际上就是让系统的偏差由非常“大”逐渐向非常“小”过度的过程。
当然,我们系统这个调节过程是快速稳定的。
通过上面的说明,可以认识到,其实对于每一种状态都可以划分到大、中、小三个状态当中去,只不过他们隶属的程度不太一样,比如6°隶属于小的程度可能是,隶属于中的程度是,隶属于大的程度是0。
这里实际上是有一个问题的,就是这个隶属的程度怎么确定这就要求我们去设计一个隶属函数。
详细内容可以查阅相关的资料,这里没有办法那么详细的说明了。
(见附录3)这里面有些说明。
那么,知道了隶属度的问题,就可以根据目前隶属的程度来控制电机以多大的速度和方向转动了,当然,最终的控制量肯定要落实在控制电压上。