PID控制算法的C语言实现完整版修订稿
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. 计算控制输出:控制输出等于比例项、积分项和微分项之和。
PID控制算法的C语言实现完整版精修订
PID控制算法的C语言实现完整版精修订```c#include <stdio.h>typedef structfloat Kp; // Proportional gainfloat Ki; // Integral gainfloat Kd; // Derivative gainfloat setpoint; // Setpointfloat errorSum; // Sum of errors for integral term float prevError; // Previous error for derivative term } PIDController;float PIDUpdate(PIDController *pid, float measurement) // Calculate errorfloat error = pid->setpoint - measurement;// Proportional termfloat pterm = pid->Kp * error;// Integral termpid->errorSum += error;float iterm = pid->Ki * pid->errorSum;// Derivative termfloat dterm = pid->Kd * (error - pid->prevError); // Update previous errorpid->prevError = error;// Calculate outputfloat output = pterm + iterm + dterm;return output;int main// Initialize PID controllerPIDController pid;pid.Kp = 1.0;pid.Ki = 0.2;pid.Kd = 0.5;pid.setpoint = 10.0;pid.errorSum = 0.0;pid.prevError = 0.0;// Simulate measurementfloat measurement = 0.0;// Update controllerfor (int i = 0; i < 100; i++)float output = PIDUpdate(&pid, measurement);// Simulate plant dynamicsmeasurement += output * 0.01;printf("Output: %f\n", output);}return 0;```在以上代码中,`typedef struct`定义了一个PIDController结构体,包含了PID控制器的参数和状态信息。
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;}注意:这里用了最基本的算法实现形式,没有考虑死区问题,没有设定上下限,只是对公式的一种直接的实现,后面的介绍当中还会逐渐的对此改进。
基于C语言的数字PID控制算法及实现
参考文献
[1] 曹 书 生 , 等 . 网 络 业 务 流 模 型 综 述 [J]. 江 苏 通 信 技 术 ,2003,(05) [2] 刘 建 辉 , 等 . 基 于 离 散 MMDP 信 源 模 型 的 ATM 网 络 排 队 性 能 仿 真 [J]. 计 算 机 仿 真 . [3] 杨 敏 维 .ATM 突 发 模 型 MMDP 的 信 元 丢 失 率 估 计 [J]. 湖 南 大 学 学 报 ,1999,(02). [4] 陈 文 云 , 等 . 基 于 ON/OFF 信 源 模 型 的 信 元 丢 失 分 析 [J]. 数 字 通 信 ,2 000, (01 ). [5] 程 伟 明 . 基 于 ATM 网 络 的 多 媒 体 通 信 [J]. 现 代 电 信 科 技 ,1998, (07 ). [6] 过 莉 .ATM 网 络 实 时 通 信 系 统 的 响 应 时 间 分 析 [J]. 电 机 电 器 技 术 , 2 00 3 , ( 06 ) . [7] 张 如 娟 . 基 于 ATM 技 术 的 多 协 议 信 息 传 送 及 应 用 [J]. 甘肃科技 , 2001,(03). [8] A bdelnaser Adas.Traffic Models in Broadband Networks[J]. IEEE communications Magazine. Ju期 , 一 般 为 200ms, e ( k ) 为 系 统 第 k 次 采 样 时 刻 的 偏 差 值 , e ( k -l) 为 系 统 第 ( k -l) 次 采 样 时 刻 的 偏 差 值 , i 为 采 样 序 号 , i =0,1,2, … 。 将 上 面 的 (3) 式 和 (4) 式 代 入 (1) 式 , 则 可 以 得 到 离 散 的 PID 表 达 式 i T e( j ) + TD [ e ( k )- e ( k -1)]} u ( i )= K p { e ( i )+ T (5) T 1 j =0 如 果 采 样 周 期 T 足 够 小 (200ms), 该 算 式 可 以 很 好 的 逼 近 模 拟 PID 算式 , 因 而 使 被 控 过 程 与 连 续 控 制 过 程 十 分 接 近 。 通 常 把 (5) 式 称 为 PID 的 位 置 式 控 制 算 法 。 若 把 (5) 式 进 行 转 化 , 则 : 0.2 td u ( i )= k * e +k* e +k* (p v x -p v 1 ) (6 ) 0 .2 i ti i 式 (6) 即 为 数 字 PID 控 制 算 法 的 编 程 表 达 式 ,p vx 为 第 ( i -1) 次 测 量 值 ,p v1 为 第 i 次 测 量 值 。 其 程 序 流 程 图 如 图 1所 示 。 其 中 给 定 转 换 s v1 /25+1 是 要 把 设 定 值 数 模 转 化 , 比 如 要 求 给 定 液 位 100CM, 则 通 过 转 换 100/25+1=5, 代 表 的 是 最 高 液 位 所 测 量 的 电 压 为 5V 。 而 对 于 数 模 转 化 (O P1 +25)/ 6 .2 5 是 要 把 输 出 转 化 为 电 流 大 小 , 假 如 输 出 O P1 为 1 0 0% , 那 么 (100+25)/6.25=20, 代 表 输 出 为 最 大 电 流 20MA 。 对 于 输 入 输 出 量 ,要 注 意 内 部 的 数 模 /模 数 转 换 关 系 :经 过 变 送 器 输 出 (1 ~ 5v) 模 拟 量 , 送 入 A/D 模 块 转 化 为 (0 ~ 250) 数 字 量 , 数 字 量 要 与 给 定 量 进 行 比 较 , 就 必 须 要 数 模 转 化 , 把 0 ~ 250 十 进 制 数 转 换 为 1.00 ~ 5.00V, 数 据 处 理 公 式 参 考 下 面 程 序 。 反 之 ,同 样 可 把 (4 ~ 20mA) 进 行 模 数 转 化 , 得 出 0 ~ 250 十 进 制 数 , 再 经 过 D/A 模 块 , 把模拟量送给执行元件。 ( 图 1)
(完整版)PID控制算法介绍与实现
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算法的C语言程序
我的题目是:基于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); // 微分项}/***********************************************************温度比较处理子程序***********************************************************/ compare_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;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 codenumber[]={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;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;}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); //480us DQ=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;}参考资料:你把这两个程序组合就可以了图1 模拟PID 控制系统原理图PID 控制器的控制规律可以描述为:(1)比例(P)控制能迅速反应误差,从而减小稳态误差。
c语言pid控制算法实现
c语言pid控制算法实现
《C语言PID控制算法实现》
一、简介
PID控制是通用的过程控制算法,它可以用来实现自动控制的过程,广泛应用于工业中的温控、流量控制、电压控制等。
PID控制算法实现了对控制环境中指定输出的追踪和控制,它可以有效地实现双环控制的效果,把参数调整为最佳控制系统。
二、算法原理
PID控制算法,是Proportional-Integral-Derivative的英文缩写,即比例-积分-微分控制算法,也叫PI-D控制算法,是利用比例系数、积分系数和微分系数,对控制变量的变化和偏差进行调节,达到控制系统输出稳定的过程。
PID控制的结构和原理:
1、比例控制:比例控制利用当前输入控制量和指定点之间的偏差来确定控制量,其调节量是根据偏差程度的大小而定的,多加大偏差时,控制量也加大,但是偏差越小控制量也越小,如果偏差为0,控制量也为0,这种控制可以快速改变输出,用于跟踪和控制和最佳状态。
2、积分控制:积分控制把控制量加上积分量,可以产生一种偏差补偿效应,当一定的时间内连续发生偏差时,控制量就会不断地积累,直到偏差消失,其作用是把持续存在的偏差纠正,同时它有一定的缓解作用,能够起到一个抗抖动的作用,减少随机扰动的影响。
3、微分控制:微分控制的控制量是根据输入量与指定量偏差的变化速率而决定的,其加入的控制量使系统反应更加敏捷,使系统更容易跟随变化。
(完整word版)增量式PID控制C语言代码
LASERL=laser.Num[1];
}
}
///////////////////////////////////////////////////////////////////////
//rtion="0"
vPID. SetPoint = //根据实际情况设定
while(1)
{
Verror=Measure(); //得到AD的输出值
Error =vPID. SetPoint- Verror; //与设定值比较,得到误差值
tempi=PIDCal(&vPID, Error;
laser.Value+=tempi; // Value与Num[2]为共同体,共同体名laser
//增量式PID算法(需要控制的不是控制量的绝对值,而是控制量的增量)
int pError,dError,iError;
long templ;
pError = ThisError-pp->LastError;
iError = ThisError;
dError = ThisError-2*(pp->LastError)+pp->PreError;
int Integral; // Integral积分系数
int Derivative; // Derivative微分系数
int LastError; // Error[-1]前一拍误差
int PreError; // Error[-2]前两拍误差
} PID;
main()
{
PID vPID; //定义结构变量名
//Input: PID的P、I控制常数和之前的误差量(PID *pp)&当前误差量(ThisError)
PID控制算法的C语言实现三
PID控制算法的C语⾔实现三位置型PID的C语⾔实现上⼀节中已经抽象出了位置性PID和增量型PID的数学表达式,这⼀节,重点讲解C语⾔代码的实现过程,算法的C语⾔实现过程具有⼀般性,通过PID算法的C语⾔实现,可以以此类推,设计其它算法的C语⾔实现。
/*-------------------------------------------位置型PID C实现(控制电机转速)--------------------------------------------*/#include <iostream>using namespace std;void pid_value_init(void);float PID_realize(float speed);//(1)定义PID 结构体变量struct pid{float SetSpeed; //设定速度float ActualSpeed; //实际值float err; //定义偏差值float err_last; //上⼀个偏差值float Kp, Ki, Kd; //p,i,d系数float voltage; //电压值float integral; //积分值,即积分部分的累计值}pid;int main(){int count = 0;cout << "Please begin \n";pid_value_init();while (count < 1000){float speed = PID_realize(200.0);cout <<"value is " <<speed<<endl ;count++;}system("pause");}//(3) 控制算法注意:这⾥⽤了最基本的算法实现形式,没有考虑死区问题,//没有设定上下限,只是对公式的⼀种直接的实现,后⾯的介绍当中还会逐渐的对此改进。
PID控制算法的C语言实现四增量型PID的C语言实现
PID控制算法的C语⾔实现四增量型PID的C语⾔实现上⼀节中介绍了最简单的位置型PID的实现⼿段,这⼀节主要讲解增量式PID的实现⽅法,位置型和增量型PID的数学公式请参见我的系列⽂《PID控制算法的C语⾔实现⼆》中的讲解。
实现过程仍然是分为定义变量、初始化变量、实现控制算法函数、算法测试四个部分,详细分类请参加《PID控制算法的C语⾔实现三》中的讲解,这⾥直接给出代码了。
#include<stdio.h>#include<stdlib.h>struct _pid{float SetSpeed; //定义设定值float ActualSpeed; //定义实际值float err; //定义偏差值float err_next; //定义上⼀个偏差值float err_last; //定义最上前的偏差值float Kp,Ki,Kd; //定义⽐例、积分、微分系数}pid;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;float incrementSpeed=pid.Kp*(pid.err-pid.err_next)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);pid.ActualSpeed+=incrementSpeed;pid.err_last=pid.err_next;pid.err_next=pid.err;return pid.ActualSpeed;}int main(){PID_init();int count=0;while(count<1000){float speed=PID_realize(200.0);printf("%f\n",speed);count++;}return 0;}运⾏后的1000个数据为:83.00000011.55500059.55967728.17540652.90742538.94414951.89170146.14165553.33905051.51000255.90844755.94463758.97067659.88294262.22499863.53724765.52770267.01104768.81063870.35530972.04202373.59564275.20760376.74543078.30151479.81212681.32191582.80029384.26889885.71309787.14344088.55299489.94694591.32206792.68097794.02222495.34717696.65523597.94717499.222801100.482597101.726562102.955040104.168114105.366058106.549004107.717178108.870743110.009888118.625099 119.642311 120.646812 121.638756 122.618294 123.585594 124.540794 125.484062 126.415535 127.335365 128.243698 129.140671 130.026443 130.901138 131.764893 132.617859 133.460159 134.291931 135.113297 135.924408 136.725372 137.516327 138.297394 139.068695 139.830353 140.582489 141.325226 142.058685 142.782974 143.498199 144.204498 144.901962 145.590714 146.270844 146.942474 147.605713 148.260651 148.907410 149.546082 150.176773 150.799576 151.414597 152.021927 152.621674 153.213913 153.798752 154.376282 154.946594159.259811 159.769073 160.271973 160.768585 161.258987 161.743271 162.221481 162.693726 163.160065 163.620575 164.075333 164.524399 164.967865 165.405777 165.838226 166.265259 166.686951 167.103378 167.514587 167.920670 168.321671 168.717667 169.108704 169.494858 169.876175 170.252731 170.624588 170.991791 171.354401 171.712479 172.066086 172.415268 172.760086 173.100601 173.436844 173.768890 174.096786 174.420578 174.740326 175.056076 175.367889 175.675797 175.979858 176.280121 176.576630 176.869431 177.158569 177.444092179.603470 179.858429 180.110214 180.358841 180.604370 180.846817 181.086243 181.322662 181.556137 181.786682 182.014359 182.239182 182.461197 182.680435 182.896942 183.110733 183.321854 183.530334 183.736206 183.939514 184.140274 184.338531 184.534302 184.727631 184.918533 185.107056 185.293228 185.477066 185.658615 185.837891 186.014923 186.189743 186.362381 186.532852 186.701202 186.867432 187.031601 187.193710 187.353790 187.511871 187.667984 187.822128 187.974365 188.124680 188.273132 188.419724 188.564484 188.707428189.788513 189.916168 190.042221 190.166702 190.289627 190.411011 190.530884 190.649246 190.766144 190.881561 190.995544 191.108109 191.219254 191.329025 191.437408 191.544449 191.650146 191.754517 191.857590 191.959366 192.059875 192.159134 192.257141 192.353928 192.449509 192.543884 192.637085 192.729126 192.820007 192.909760 192.998383 193.085907 193.172333 193.257675 193.341965 193.425186 193.507385 193.588531 193.668686 193.747818 193.825974 193.903152 193.979370 194.054626 194.128952 194.202332 194.274811 194.346375194.887619 194.951523 195.014633 195.076950 195.138489 195.199265 195.259277 195.318542 195.377060 195.434845 195.491913 195.548264 195.603912 195.658859 195.713135 195.766724 195.819641 195.871902 195.923508 195.974472 196.024796 196.074493 196.123566 196.172028 196.219879 196.267136 196.313797 196.359879 196.405380 196.450317 196.494690 196.538513 196.581787 196.624512 196.666702 196.708374 196.749512 196.790146 196.830261 196.869888 196.909012 196.947647 196.985809 197.023483 197.060699 197.097443 197.133728 197.169556197.440521 197.472519 197.504105 197.535309 197.566116 197.596542 197.626587 197.656250 197.685547 197.714478 197.743042 197.771255 197.799118 197.826630 197.853806 197.880630 197.907120 197.933289 197.959122 197.984634 198.009827 198.034698 198.059265 198.083527 198.107483 198.131134 198.154495 198.177567 198.200348 198.222839 198.245056 198.266998 198.288666 198.310059 198.331177 198.352036 198.372635 198.392975 198.413071 198.432907 198.452499 198.471848 198.490952 198.509811 198.528442 198.546829 198.565002 198.582932198.718597 198.734619 198.750443 198.766068 198.781494 198.796722 198.811768 198.826614 198.841278 198.855759 198.870056 198.884186 198.898132 198.911911 198.925507 198.938934 198.952194 198.965286 198.978226 198.990997 199.003616 199.016068 199.028366 199.040512 199.052505 199.064346 199.076050 199.087601 199.099014 199.110275 199.121399 199.132385 199.143234 199.153946 199.164520 199.174973 199.185287 199.195465 199.205521 199.215454 199.225266 199.234955 199.244522 199.253967 199.263290 199.272507 199.281601 199.290588199.358521 199.366547 199.374466 199.382294 199.390015 199.397644 199.405167 199.412613 199.419952 199.427200 199.434357 199.441422 199.448410 199.455307 199.462112 199.468842 199.475479 199.482040 199.488510 199.494904 199.501221 199.507462 199.513611 199.519699 199.525696 199.531631 199.537476 199.543259 199.548965 199.554611 199.560181 199.565674 199.571106 199.576462 199.581757 199.586990 199.592148 199.597244 199.602280 199.607254 199.612167 199.617020 199.621811 199.626541 199.631210 199.635818 199.640366 199.644867199.678864 199.682877 199.686844 199.690750 199.694626 199.698441 199.702209 199.705933 199.709610 199.713242 199.716827 199.720367 199.723862 199.727310 199.730713 199.734085 199.737411 199.740692 199.743942 199.747147 199.750305 199.753433 199.756516 199.759567 199.762573 199.765549 199.768478 199.771378 199.774231 199.777054 199.779846 199.782593 199.785309 199.787994 199.790649 199.793259 199.795853 199.798401 199.800919 199.803406 199.805862 199.808289 199.810684 199.813049 199.815384 199.817688 199.819962 199.822220199.839233 199.841248 199.843231 199.845200 199.847137 199.849045 199.850937 199.852798 199.854645 199.856461 199.858261 199.860031 199.861786 199.863510 199.865219 199.866898 199.868561 199.870209 199.871826 199.873428 199.875015 199.876572 199.878113 199.879639 199.881149 199.882629 199.884094 199.885544 199.886978 199.888397 199.889786 199.891174 199.892532 199.893875 199.895203 199.896515 199.897812 199.899094 199.900360 199.901611 199.902847 199.904068 199.905273 199.906464 199.907639 199.908798 199.909943 199.911072199.920578 199.921570 199.922546 199.923523 199.924469 199.925415 199.926346 199.927261 199.928177 199.929077 199.929962 199.930832 199.931702 199.932556 199.933395 199.934235 199.935059 199.935867 199.936676 199.937469 199.938248 199.939026 199.939789 199.940536 199.941284 199.942017 199.942749 199.943466 199.944168 199.944870 199.945557 199.946243 199.946915 199.947586 199.948242 199.948883 199.949524 199.950150 199.950775 199.951385 199.951996 199.952591 199.953186 199.953766 199.954346 199.954910 199.955475199.960220 199.960724 199.961212 199.961700 199.962173 199.962646 199.963120 199.963577 199.964035 199.964478 199.964920 199.965363 199.965790 199.966217 199.966644 199.967056 199.967468 199.967880 199.968277 199.968674 199.969070 199.969452 199.969833 199.970215 199.970581 199.970947 199.971313 199.971664 199.972015 199.972366 199.972717 199.973053 199.973389 199.973724 199.974045 199.974380 199.974701 199.975021 199.975327 199.975632 199.975937 199.976242 199.976532 199.976822 199.977112 199.977402 199.977676199.980072 199.980331 199.980576 199.980820 199.981064 199.981293 199.981537 199.981766 199.981995 199.982224 199.982437 199.982666 199.982880 199.983093 199.983307 199.983521 199.983719 199.983932 199.984131 199.984329 199.984528 199.984726 199.984909 199.985107 199.985291 199.985474 199.985657 199.985840 199.986023 199.986191 199.986374 199.986542 199.986710 199.986877 199.987045 199.987213 199.987366 199.987534 199.987686 199.987839 199.987991 199.988144 199.988297 199.988449 199.988586 199.988739 199.988876199.990067 199.990189 199.990311 199.990433 199.990555 199.990677 199.990799 199.990906 199.991028 199.991135 199.991257 199.991364 199.991470 199.991577 199.991684 199.991791 199.991898 199.992004 199.992096 199.992203 199.992294 199.992401 199.992493 199.992584 199.992676 199.992767 199.992859 199.992950 199.993042 199.993134 199.993225 199.993301 199.993393 199.993469 199.993561 199.993637 199.993713 199.993790 199.993866 199.993942 199.994019 199.994095 199.994171 199.994247 199.994324 199.994400 199.994476199.995056 199.995117 199.995178 199.995239 199.995300 199.995361 199.995422 199.995483 199.995544 199.995605 199.995667 199.995712 199.995773 199.995819 199.995880 199.995926 199.995987 199.996033 199.996094 199.996140 199.996185 199.996231 199.996277 199.996323 199.996368 199.996414 199.996460 199.996506 199.996552 199.996597 199.996643 199.996689 199.996735 199.996780 199.996826 199.996872 199.996902 199.996948 199.996979 199.997025 199.997055 199.997101 199.997131 199.997177 199.997208 199.997253 199.997284199.997559 199.997589 199.997620 199.997650 199.997681 199.997711 199.997742 199.997772 199.997803 199.997833 199.997864 199.997894 199.997925 199.997955 199.997986 199.998016 199.998047 199.998077 199.998093 199.998123 199.998138 199.998169 199.998184 199.998215 199.998230 199.998260 199.998276 199.998306 199.998322 199.998352 199.998367 199.998398 199.998413 199.998444 199.998459 199.998489 199.998505 199.998520 199.998535 199.998550 199.998566 199.998581 199.998596 199.998611 199.998627 199.998642 199.998657199.998795 199.998810 199.998825 199.998840 199.998856 199.998871 199.998886 199.998901 199.998917 199.998932 199.998947 199.998962 199.998978 199.998993 199.999008 199.999023 199.999039 199.999054 199.999069 199.999084 199.999100 199.999115 199.999130 199.999146 199.999161 199.999176 199.999191 199.999207 199.999222 199.999237 199.999252 199.999268 199.999283 199.999298 199.999298 199.999313 199.999313 199.999329 199.999329 199.999344 199.999344 199.999359 199.999359 199.999374 199.999374 199.999390 199.999390199.999466 199.999466 199.999481 199.999481 199.999496 199.999496 199.999512 199.999512。
PID算法的C语言实现
PID算法的C语⾔实现1.根据我控制算法类⽂章中关于PID的理论的⼀些描述,同时也根据⽹络上⼀些其他的PID⽂章,以及⾃⼰最近⼀个项⽬的实践后,总结了⼏套基于C语⾔的PID算法,由于⽹络中很少有⼈进⾏分享完整的PID算法实现,我这⾥分享下。
(1)头⽂件,定义pid的结构体,类的概念,包含pid的属性和⽅法#ifndef __PID_H_#define __PID_H_#include <stdint.h>typedef struct _pid{int16_t set_value; // 给定值,rin(k)int16_t actual_value; // 实际值,反馈值,rout(k)int16_t err; // 偏差值,rin(k) - rout(k)int16_t err_last; // 上⼀次偏差值,rin(k - 1) - rout(k - 1)int16_t err_last_last; // 上⼀次上⼀次的偏差值,rin(k - 2) - rout(k - 2)float kp; // ⽐例系数float ki; // 积分系数float kd; // 微分系数float uk; // pid公式运算结果值float incremental_value; // 增量值float integral_value; // 积分值float umax; // uk的上限值,抗积分饱和⽤float umin; // uk的下限值,抗积分饱和⽤int16_t err_up_value; // 偏差上限值,积分分离⽤int16_t ki_k; // 积分的再次乘机系数,积分分离⽤float out_value; //float(*position_type)(struct _pid *ppid); // 位置型PID算法,⽆积分分离、⽆抗积分饱和float(*incremental_type)(struct _pid *ppid); // 增量型PID算法float(*integral_separation_type)(struct _pid *ppid); // 积分分离PID算法float(*int_sep_anti_sat_type)(struct _pid *ppid); // 积分分离 + 抗积分饱和PID算法}_pid_t;_pid_t *pid_create(void);extern _pid_t *pg_pid;#endif(2).c⽂件,包含头⽂件中4个PID算法的实现,包含位置型PID算法、增量型PID算法、积分分离PID算法、积分分离+抗饱和PID算法#include <stdlib.h>#include <string.h>#include "pid.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "portmacro.h"#include "semphr.h"#include "Debug.h"/*************************************** Funciton Name : pid_position_type* Function :位置型PID算法,⽆积分分离、⽆抗积分饱和** @author :why* @note : 积分分离:能解决初期系统偏差值⼤,累加到积分项中,引起系统超调、振荡问题。
PID控制算法的C语言实现精修订
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.读取当前系统的温度值:使用温度传感器读取当前系统的实际温度值。
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控制算法的C语言实现完整版代码。
```#include <stdio.h>#include <stdlib.h>//定义PID参数#define KP 0.5#define KI 0.2#define KD 0.1//PID结构体typedef structfloat setpoint; // 设定值float error; // 误差float integral; // 积分float derivative; // 微分float prev_error; // 上一次误差float output; // 输出}PID;//初始化PIDvoid initializePID(PID *pid, float setpoint)pid->setpoint = setpoint;pid->error = 0;pid->integral = 0;pid->derivative = 0;pid->prev_error = 0;pid->output = 0;//更新PIDfloat updatePID(PID *pid, float input, float dt)//计算误差pid->error = pid->setpoint - input;//计算积分pid->integral += pid->error * dt;//计算微分pid->derivative = (pid->error - pid->prev_error) / dt;//计算输出pid->output = KP * pid->error + KI * pid->integral + KD * pid->derivative;//保存当前误差作为上一次误差pid->prev_error = pid->error;return pid->output;int mai//创建PID对象PID pid;//初始化PIDinitializePID(&pid, 50);//模拟控制过程for (int step = 0; step < 100; step++)//模拟获取输入值float input = input_value(step); // 自定义获取输入值的函数,根据实际应用进行修改//更新PID并获取输出float output = updatePID(&pid, input, 0.1); // 假设采样时间间隔为0.1秒//输出控制信号printf("Step: %d, Output: %.2f\n", step, output);}return 0;```上述代码实现了一个简单的PID控制算法。
(完整版)模糊PID控制的C程序
(完整版)模糊PID控制的C程序//e:[-3,3] ec:[-3,3] kp:[-0.3,0.3]#include#define NB 0#define NM 1#define NS 2#define ZO 3#define PS 4#define PM 5#define PB 6/*********************************************************/ float uf(float x,float a,float b,float c);float cuf(float x,float a,float b,float c);float ufl(float x,float a,float b);float cufl(float x,float a,float b);float ufr(float x,float a,float b);float cufr(float x,float a,float b);float ufr(float x,float a,float b);float cufr(float x,float a,float b);float fand(float a,float b);float forr(float a,float b);float FuzzyKp(float e,float ec);//主程序void main(){float a,b,Kp;printf("The E is:");scanf("%f",&a);printf("The Ec is:");scanf("%f",&b);Kp=FuzzyKp(a,b);printf("The parameter Kp is: %f\n\n",Kp);float FuzzyKp(float e,float ec){float es[7];float ecs[7];/******模糊推理规则的可信度通过取小点运算得到*****/ float form[7][7];//(表X7)(隶属度表)int i,j;/*************求得的最大值赋给form[a][b]*********/ int a=0,b=0;float lsd;int p;float detkp;/**************************/int kp[7][7]={{PB,PB,PM,PS,PS,ZO,ZO},{PB,PB,PM,PS,PS,ZO,NS},{PM,PM,PM,PS,ZO,NS,NS},{PM,PM,PS,ZO,NS,NM,NM},{PS,PS,ZO,NS,NS,NM,NM},{PS,ZO,NS,NM,NM,NM,NB},{ZO,ZO,NM,NM,NM,NB,NB}};es[NB]=ufl(e,-3,-1);es[NM]=uf(e,-3,-2,0);es[NS]=uf(e,-3,-1,1);es[ZO]=uf(e,-2,0,2);es[PS]=uf(e,-1,1,3);es[PM]=uf(e,0,2,3);es[PB]=ufr(e,1,3);ecs[NB]=ufl(ec,-3,-1);//ececs[NM]=uf(ec,-3,-2,0);ecs[NS]=uf(ec,-3,-1,1);ecs[ZO]=uf(ec,-2,0,2);ecs[PS]=uf(ec,-1,1,3);ecs[PM]=uf(ec,0,2,3);ecs[PB]=ufr(ec,1,3);for(i=0;i<7;i++){float w,h,r;for(j=0;j<7;j++){h=es[i];r=ecs[j];w=fand(h,r);form[i][j]=w;}}for(i=0;i<7;i++){for(j=0;j<7;j++){if(form[a][b]<form[i][j])< p="">{a=i;b=j;}}}lsd=form[a][b];//es和ecs最值中的最大值p=kp[a][b]; if(p==NB)detkp=cufl(lsd,-0.3,-0.1);else if(p==NM)detkp=cuf(lsd,-0.3,0.2,0);else if(p==NS)detkp=cuf(lsd,-0.3,-0.1,0.1);else if(p==ZO)detkp=cuf(lsd,-0.2,0,0.2);else if(p==PS)detkp=cuf(lsd,-0.1,0.1,0.3);else if(p==PM)detkp=cuf(lsd,0,0.2,0.3);else if(p==PB)detkp=cufr(lsd,0.1,0.3);return detkp;}/**************************************以下为附属子函数*//**************求隶属度(三角形)模糊化处理***************/ float uf(float x,float a,float b,float c){if(x<=a)return (0);else if((a<x)&&(x<=b))< p="">return( (x-a)/(b-a));else if((b<x)&&(x<=c))< p="">return( (c-x)/(c-b));else if(x>c)return (0);}/****************三角形反模糊化处理(最大隶属度法)**********************/float cuf(float x,float a,float b,float c){float y,z;z=(b-a)*x+a;y=c-(c-b)*x;return (y+z)/2;}/*****************梯形(左)求隶属度模糊化*******************/ float ufl(float x,float a,float b){if(x<=a)return 1;else if((a<x)&&(x<=b))< p="">return (b-x)/(b-a);else if(x>b)return 0;}/*******************梯形反模糊化***********************/ float cufl(float x,float a,float b){return b-(b-a)*x;}/*****************梯形(右)求隶属度模糊化*******************/ float ufr(float x,float a,float b){if(x<=a)return 0;if((a<x)&&(x<b))< p="">return (x-a)/(b-a);if(x>=b)return 1;}/*******************梯形反模糊化***********************/ float cufr(float x,float a,float b){return (b-a)*x +a;}/*******************求交集***********************/ float fand(float a,float b){return (a}/*******************求并集***********************/ float forr(float a,float b){return (a<b)?b:a;< p="">}</b)?b:a;<></x)&&(x<b))<></x)&&(x<=b))<></x)&&(x<=c))<></x)&&(x<=b))<></form[i][j])<>。
PID算法的C语言实现
PID算法的C语言实现PID算法的C语言实现积分饱和通俗讲就是系统在一个偏差方向上的饱和,下面一起来跟着店铺学习一下PID算法的C语言实现方法吧,希望可以帮助到大家!比如一个系统设定了输出不会超过100,但因为出现一个方向上的偏差积分使得输出超过了100,此时达到了饱和状态,如果继续在这个方向上积分会导致PID控制超过100系统却运行在100,相当于积分调节对系统输出没有作用,就出现失控的状态,这是系统不能接受的,而且饱和积分越深,退出饱和就越久。
上面是在正向的饱和,负向的饱和类似!为了解决这个问题,我们采用抗积分饱和算法,其思路就是:如果上一次的输出控制量超过了饱和值,饱和值为正,则这一次只积分负的偏差,饱和值为负,则这一次只积分正的偏差,从而避免系统长期留在饱和区!下面我以位置型+抗积分饱和+积分分离的.PID控制算法C语言来观察调节结果:(相对应的代码可以参考以往的文章)//位置型+抗积分饱和+积分分离 PID控制算法struct _pid{float SetSpeed;float ActualSpeed;float Err;float Err_Last;float Kp,Ki,Kd;float Voltage;float Integral;float Umax; //最大正饱和上限值float Umin; //最大负饱和下限值}pid;void PID_Init(void){printf("PID_Init begin! ");pid.SetSpeed = 0;pid.ActualSpeed = 0;pid.Err = 0;pid.Err_Last = 0;pid.Kp = 0.2;pid.Ki = 0.1; //增大了积分环节的值pid.Kd = 0.2;pid.Voltage = 0;pid.Integral = 0;pid.Umax = 400; //正饱和值为400pid.Umin = -200; //负饱和值为-200printf("PID_Init end! ");}float PID_Cal(float Speed){unsigned char index;pid.SetSpeed = Speed;pid.Err = pid.SetSpeed - pid.ActualSpeed;if(pid.ActualSpeed>pid.Umax) //如果上一次输出变量出现正向的饱和{if(abs(pid.Err)>200){index = 0;}else{index = 1;if(pid.Err<0){pid.Integral += pid.Err; //正饱和只积分负偏差}}}else if(pid.ActualSpeed {if(abs(pid.Err)>200){index = 0;}else{index = 1;if(pid.Err>0){pid.Integral += pid.Err; //负饱和只积分正偏差}}}else{if(abs(pid.Err)>200) //积分分离的PID优化,可参考以往的文章{index = 0;}else{index = 1;pid.Integral += pid.Err;}}pid.Voltage = pid.Kp*pid.Err +index*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;}int main(void){int count = 0 ;printf("SYSTEM BEGIN! ");PID_Init();while(count<1000){float speed = PID_Cal(200.0);printf("-%d-%f-",count,speed);count++;}return 0;}最后运行结果:我们发现,相对以往的算法,还算法大大提高了调节的速度和稳定!【PID算法的C语言实现】。
PID控制算法的C语言实现完整版
PID控制算法(de)C语言实现一 PID算法原理最近两天在考虑一般控制算法(de)C语言实现问题,发现网络上尚没有一套完整(de)比较体系(de)讲解.于是总结了几天,整理一套思路分享给大家.在工业应用中PID及其衍生算法是应用最广泛(de)算法之一,是当之无愧(de)万能算法,如果能够熟练掌握PID算法(de)设计与实现过程,对于一般(de)研发人员来讲,应该是足够应对一般研发问题了,而难能可贵(de)是,在我所接触(de)控制算法当中,PID控制算法又是最简单,最能体现反馈思想(de)控制算法,可谓经典中(de)经典.经典(de)未必是复杂(de),经典(de)东西常常是简单(de),而且是最简单(de),想想牛顿(de)力学三大定律吧,想想爱因斯坦(de)质能方程吧,何等(de)简单简单(de)不是原始(de),简单(de)也不是落后(de),简单到了美(de)程度.先看看PID算法(de)一般形式:PID(de)流程简单到了不能再简单(de)程度,通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节(de)加和.这里我们规定(在t时刻):1.输入量为rin(t);2.输出量为rout(t);3.偏差量为err(t)=rin(t)-rout(t);pid(de)控制规律为理解一下这个公式,主要从下面几个问题着手,为了便于理解,把控制环境具体一下:1.规定这个流程是用来为直流电机调速(de);2.输入量rin(t)为电机转速预定值;3.输出量rout(t)为电机转速实际值;4.执行器为直流电机;5.传感器为光电码盘,假设码盘为10线;6.直流电机采用PWM调速转速用单位转/min表示;不难看出以下结论:1.输入量rin(t)为电机转速预定值(转/min);2. 输出量rout(t)为电机转速实际值(转/min);3.偏差量为预定值和实际值之差(转/min);那么以下几个问题需要弄清楚:1.通过PID环节之后(de)U(t)是什么值呢2.控制执行器(直流电机)转动转速应该为电压值(也就是PWM占空比).3.那么U(t)与PWM之间存在怎样(de)联系呢(见附录1)这篇文章上给出了一种方法,即,每个电压对应一个转速,电压和转速之间呈现线性关系.但是我考虑这种方法(de)前提是把直流电机(de)特性理解为线性了,而实际情况下,直流电机(de)特性绝对不是线性(de),或者说在局部上是趋于线性(de),这就是为什么说PID调速有个范围(de)问题.具体看一下(见附录2)这篇文章就可以了解了.所以在正式进行调速设计之前,需要现有开环系统,测试电机和转速之间(de)特性曲线(或者查阅电机(de)资料说明),然后再进行闭环参数整定.这篇先写到这,下一篇说明连续系统(de)离散化问题.并根据离散化后(de)特点讲述位置型PID和增量型PID(de)用法和C语言实现过程.PID控制算法(de)C语言实现二 PID算法(de)离散化上一节中,我论述了PID算法(de)基本形式,并对其控制过程(de)实现有了一个简要(de)说明,通过上一节(de)总结,基本已经可以明白PID控制(de)过程.这一节中先继续上一节内容补充说明一下.1.说明一下反馈控制(de)原理,通过上一节(de)框图不难看出,PID控制其实是对偏差(de)控制过程;2.如果偏差为0,则比例环节不起作用,只有存在偏差时,比例环节才起作用.3.积分环节主要是用来消除静差,所谓静差,就是系统稳定后输出值和设定值之间(de)差值,积分环节实际上就是偏差累计(de)过程,把累计(de)误差加到原有系统上以抵消系统造成(de)静差.4.而微分信号则反应了偏差信号(de)变化规律,或者说是变化趋势,根据偏差信号(de)变化趋势来进行超前调节,从而增加了系统(de)快速性.好了,关于PID(de)基本说明就补充到这里,下面将对PID连续系统离散化,从而方便在处理器上实现.下面把连续状态(de)公式再贴一下:假设采样间隔为T,则在第K T时刻:偏差err(K)=rin(K)-rout(K);积分环节用加和(de)形式表示,即err(K)+err(K+1)+……;微分环节用斜率(de)形式表示,即[err(K)-err(K-1)]/T;从而形成如下PID离散表示形式:则u(K)可表示成为:至于说Kp、Ki、Kd三个参数(de)具体表达式,我想可以轻松(de)推出了,这里节省时间,不再详细表示了.其实到这里为止,PID(de)基本离散表示形式已经出来了.目前(de)这种表述形式属于位置型PID,另外一种表述方式为增量式PID,由U上述表达式可以轻易得到:那么:这就是离散化PID(de)增量式表示方式,由公式可以看出,增量式(de)表达结果和最近三次(de)偏差有关,这样就大大提高了系统(de)稳定性.需要注意(de)是最终(de)输出结果应该为u(K)+增量调节值;PID(de)离散化过程基本思路就是这样,下面是将离散化(de)公式转换成为C语言,从而实现微控制器(de)控制作用.PID控制算法(de)C语言实现三位置型PID(de)C语言实现上一节中已经抽象出了位置性PID和增量型PID(de)数学表达式,这一节,重点讲解C语言代码(de)实现过程,算法(de)C语言实现过程具有一般性,通过PID算法(de)C语言实现,可以以此类推,设计其它算法(de)C语言实现.第一步:定义PID变量结构体,代码如下:struct _pid{float SetSpeed;例系数Kp(de)作用是加快系统(de)响应速度,提高系统(de)调节精度.Kp越大,系统(de)响应速度越快,系统(de)调节精度越高,但是容易产生超调,甚至会使系统不稳定.Kp取值过小,则会降低调节精度,使响应速度缓慢,从而延长调节时间,是系统静态、动态特性变差;2.积分作用系数Ki(de)作用是消除系统(de)稳态误差.Ki越大,系统(de)静态误差消除(de)越快,但是Ki过大,在响应过程(de)初期会产生积分饱和(de)现象,从而引起响应过程(de)较大超调.若Ki过小,将使系统静态误差难以消除,影响系统(de)调节精度;3.微分系数Kd(de)作用是改善系统(de)动态特性,其作用主要是在响应过程中抑制偏差向任何方向(de)变化,对偏差变化进行提前预报.但是kd过大,会使响应过程提前制动,从而延长调节时间,而且会降低系统(de)抗干扰性.反应系统性能(de)两个参数是系统误差e和误差变化律ec,这点还是好理解(de):首先我们规定一个误差(de)极限值,假设为Mmax;规定一个误差(de)比较大(de)值,假设为Mmid;规定一个误差(de)较小值,假设为Mmin;当abs(e)>Mmax时,说明误差(de)绝对值已经很大了,不论误差变化趋势如何,都应该考虑控制器(de)输入应按最大(或最小)输出,以达到迅速调整误差(de)效果,使误差绝对值以最大(de)速度减小.此时,相当于实施开环控制.当eec>0时,说明误差在朝向误差绝对值增大(de)方向变化,此时,如果abs(e)>Mmid,说明误差也较大,可考虑由控制器实施较强(de)控制作用,以达到扭转误差绝对值向减小(de)方向变化,并迅速减小误差(de)绝对值.此时如果abs(e)<Mmid,说明尽管误差是向绝对值增大(de)方向变化,但是误差绝对值本身并不是很大,可以考虑控制器实施一般(de)控制作用,只需要扭转误差(de)变化趋势,使其向误差绝对值减小(de)方向变化即可.当eerr<0且eerr(k-1)>0或者e=0时,说明误差(de)绝对值向减小(de)方向变化,或者已经达到平衡状态,此时保持控制器输出不变即可.当eerr<0且eerr(k-1)<0时,说明误差处于极限状态.如果此时误差(de)绝对值较大,大于Mmin,可以考虑实施较强控制作用.如果此时误差绝对值较小,可以考虑实施较弱控制作用.当abs(e)<Mmin时,说明误差绝对值很小,此时加入积分,减小静态误差.上面(de)逻辑判断过程,实际上就是对于控制系统(de)一个专家判断过程.(未完待续)PID控制算法(de)C语言实现十模糊算法简介在PID控制算法(de)C语言实现九中,文章已经对模糊PID(de)实质做了一个简要说明.本来打算等到完成毕业设计,工作稳定了再着力完成剩下(de)部分.鉴于网友(de)要求和信任,抽出时间来,对模糊PID做一个较为详细(de)论述,这里我不打算做出仿真程序了,但就基本概念和思路进行一下说明,相信有C语言基础(de)朋友可以通过这些介绍性(de)文字自行实现.这篇文章主要说明一下模糊算法(de)含义和原理.实际上模糊算法属于智能算法,智能算法也可以叫非模型算法,也就是说,当我们对于系统(de)模型认识不是很深刻,或者说客观(de)原因导致我们无法对系统(de)控制模型进行深入研究(de)时候,智能算法常常能够起到不小(de)作用.这点是方便理解(de),如果一个系统(de)模型可以轻易(de)获得,那么就可以根据系统(de)模型进行模型分析,设计出适合系统模型(de)控制器.但是现实世界中,可以说所有(de)系统都是非线性(de),是不可预测(de).但这并不是说我们就无从建立控制器,因为,大部分(de)系统在一定(de)条件和范围内是可以抽象成为线性系统(de).问题(de)关键是,当我们系统设计(de)范围超出了线性(de)范围,我们又该如何处理.显然,智能算法是一条很不错(de)途径.智能算法包含了专家系统、模糊算法、遗传算法、神经网络算法等.其实这其中(de)任何一种算法都可以跟PID去做结合,而选择(de)关键在于,处理(de)实时性能不能得到满足.当我们处理器(de)速度足够快速时,我们可以选择更为复杂(de)、精度更加高(de)算法.但是,控制器(de)处理速度限制了我们算法(de)选择.当然,成本是限制处理器速度最根本(de)原因.这个道理很简单,51单片机和DSP(de)成本肯定大不相同.专家PID和模糊PID是常用(de)两种PID选择方式.其实,模糊PID适应一般(de)控制系统是没有问题.文章接下来将说明模糊算法(de)一些基本常识.模糊算法其实并不模糊.模糊算法其实也是逐次求精(de)过程.这里举个例子说明.我们设计一个倒立摆系统,假如摆针偏差<5°,我们说它(de)偏差比较“小”;摆针偏差在5°和10°之间,我们说它(de)偏差处于“中”(de)状态;当摆针偏差>10°(de)时候,我们说它(de)偏差有点儿“大”了.对于“小”、“中”、“大”这样(de)词汇来讲,他们是精确(de)表述,可问题是如果摆针偏差是3°呢,那么这是一种什么样(de)状态呢.我们可以用“很小”来表述它.如果是7°呢,可以说它是“中”偏“小”.那么如果到了80°呢,它(de)偏差可以说“非常大”.而我们调节(de)过程实际上就是让系统(de)偏差由非常“大”逐渐向非常“小”过度(de)过程.当然,我们系统这个调节过程是快速稳定(de).通过上面(de)说明,可以认识到,其实对于每一种状态都可以划分到大、中、小三个状态当中去,只不过他们隶属(de)程度不太一样,比如6°隶属于小(de)程度可能是,隶属于中(de)程度是,隶属于大(de)程度是0.这里实际上是有一个问题(de),就是这个隶属(de)程度怎么确定这就要求我们去设计一个隶属函数.详细内容可以查阅相关(de)资料,这里没有办法那么详细(de)说明了.(见附录3)这里面有些说明.那么,知道了隶属度(de)问题,就可以根据目前隶属(de)程度来控制电机以多大(de)速度和方向转动了,当然,最终(de)控制量肯定要落实在控制电压上.这点可以很容易(de)想想,我们控制(de)目(de)就是让倒立摆从隶属“大”(de)程度为1(de)状态,调节到隶属“小”(de)程度为1(de)状态.当隶属大多一些(de)时候,我们就加快调节(de)速度,当隶属小多一些(de)时候,我们就减慢调节(de)速度,进行微调.可问题是,大、中、小(de)状态是汉字,怎么用数字表示,进而用程序代码表示呢其实我们可以给大、中、小三个状态设定三个数字来表示,比如大表示用3表示,中用2表示,小用1表示.那么我们完全可以用1+2+3=来表示它,当然这个公式也不一定是这样(de),这个公式(de)设计是系统模糊化和精确化(de)一个过程,读者也可参见相关文献理解.但就这个数字而言,可以说明,目前6°(de)角度偏差处于小和中之间,但是更偏向于中.我们就可以根据这个数字来调节电机(de)转动速度和时间了.当然,这个数字与电机转速(de)对应关系,也需要根据实际情况进行设计和调节.前面一个例子已经基本上说明了模糊算法(de)基本原理了.可是实际上,一个系统(de)限制因素常常不是一个.上面(de)例子中,只有偏差角度成为了系统调节(de)参考因素.而实际系统中,比如PID系统,我们需要调节(de)是比例、积分、微分三个环节,那么这三个环节(de)作用就需要我们认清,也就是说,我们需要根据超调量、调节时间、震荡情况等信息来考虑对这三个环节调节(de)比重,输入量和输出量都不是单一(de),可是其中必然有某种内在(de)逻辑联系.所以这种逻辑联系就成为我们设计工作(de)重点了.下一篇文章将详细分析PID三个变量和系统性能参数之间(de)联系.PID控制算法(de)c语言实现十一(PID系列完结篇)模糊PID(de)参数整定这几天一直在考虑如何能够把这一节(de)内容说清楚,对于PID而言应用并没有多大难度,按照基本(de)算法设计思路和成熟(de)参数整定方法,就算是没有经过特殊训练和培训(de)人,也能够在较短(de)时间内容学会使用PID算法.可问题是,如何能够透彻(de)理解PID算法,从而能够根据实际(de)情况设计出优秀(de)算法呢.通过讲述公式和基本原理肯定是最能说明问题(de),可是这样(de)话怕是犯了“专家”(de)错误了.对于门槛比较低(de)技术人员来讲,依然不能透彻理解.可是说(de)入耳了,能不能透彻说明也是一个问题,所以斟酌了几天,整理了一下思路才开始完成PID系列文章(de)最后一篇.我所说(de)最后一篇不代表PID(de)功能和发展就止步与此,仅仅是说明,透过这一些列(de)文章,基本上已经可以涵盖PID设计(de)要点,至于更深入(de)研究,就交给有需要(de)读者去做.上一节中大致讲述了一下模糊算法.实际上模糊算法(de)很多概念在上一节中并没有深入(de)解释.举(de)例子也只是为了说明模糊算法(de)基本含义,真正(de)模糊算法是不能这么设计(de),当然也不会这么简单.模糊算法(de)核心是模糊规则,如果模糊规则制定(de)出色,那么模糊算法(de)控制效率就高.其实这是智能算法(de)一般特性,规则是系统判断和处理(de)前提.那么就说说PID(de)规则该怎么制定.我们知道,模糊算法(de)本质是对PID(de)三个参数进行智能调节.那么首先要提出(de)问题是如何对PID(de)参数进行调节这个问题其实是参数整定(de)问题,现实当中有很多整定方法.可是我们需要从根本上了解为什么这么整定,才能知道该如何建立数学模型进行分析.那么要回答如何整定参数(de)问题,就需要先明白PID参数(de)作用都是什么对系统有什么影响我们从作用和副作用两个方面说明参数对系统(de)影响.1.比例环节Kp,作用是加快系统(de)响应速度,提高系统(de)调节精度,副作用是会导致超调;2.积分环节Ki,作用是消除稳态误差,副作用是导致积分饱和现象;3.微分环节Kd,作用是改善系统(de)动态性能,副作用是延长系统(de)调节时间.理解了上述问题,那么就可以“辩证施治,对症下药”了.比如说,如果系统响应速度慢,我们就加大Kp(de)取值,如果超调量过大我们就减小Kp(de)取值等等.可是问题这些语言(de)描述该如何用数学形式表达出来呢.我们所知道(de),反馈系统(de)实质就是系统(de)输出量作为反馈量与系统(de)输入量进行作差,从而得到系统(de)误差e,那么这个误差e就能够反应目前系统所处(de)状态.误差e可以表明目前系统(de)输出状态到底偏离要求多少.而误差e(de)变化律ec,表示误差变化(de)速度.这样,我们可以根据这两个量(de)状态来分析三个参数此时应该如何取值,假如e为负方向比较大,ec也为负方向增大状态,此时比例环节要大一些,从而加快调节速度,而积分环节要小一些,甚至不加积分环节,从而防止负方向上出现饱和积分(de)现象.微分环节可以稍加一些,在不影响调节时间(de)情况下,起到改善系统动态性能(de)作用.附录1看到有不少人问到底如何让UK值与PWM占空比值对应,进而实现占空比输出和输出控制电压对应.(注意,我这里讨论(de)前提是输出控制(de)是电压,不是PWM方波.PWM输出后要经过滤波整形再输出控制.)前提条件:输出电压控制电压范围是0-10V.给定、反馈、输出电压采样输入电压范围是0-5V(经过运放).使用单片机AD为10位AD芯片.那么10位AD芯片电压采集得到(de)数据范围就是0-1024.PWM为 8位可调占空比方波,0对应输出占空比为0(de)方波,255对应输出占空比100%(de)方波,127对应输出50%(de)方波.比如当前给定是,反馈电压是1V.(KP,KI,KD等系数略,关于PID算法(de)整数实现我在前文中有论述如何实现).那么经过AD采样1、给定对应为 5122、反馈1V对应为 205假定经过PID计算得到(de)UK为400也就意味着输出电压应当为(400(UPWM峰值电压))/1024那么UK对应(de)PWM占空比是多少呢我们知道,UK=1024对应占空比为100,也就是PWM(de)占空比系数为255.可知,PWM系数 = UK/4;那么400就应当对应系数 400/4=100.也就是输出电压=40010/1024=同时,由于采样精度以及PWM输出占空比精度控制(de)问题,将导致输出电压和期望值不是那么线性,所以,我在项目内加入了输出电压采样(de)控制.采样AD输入为0-5V,所以,对于输出0-10V有一个缩小(de)比例.输出10V则采样值对应为255输出5V则采样之对应127可知,对应AD结果为97采样输出电压值,可以针对性(de)调整一下占空比输出,从而得到误差允许范围内(de)一个控制输出电压.同时,经过一些加速控制(de)手段.可以比较迅速(de)达到控制(de)目(de).下文中(de)UK控制方法是针对增量式PID控制而来做(de).//void PWMProcess(void){uint16 idata temp;uint16 idata UKTemp;temp = 0;UKTemp = 0;if( = 0 ) //判断是否需要改变占空比{ //是否需要改变占空比和你(de)被控系统特性有关= 0;UKTemp = + ;//计算UK控制量//控制量和计算值以及一个开关量有关,我这里(de)开关量是系统需要(de)时候叠加在控制量上(de)一个变量.if(UKTemp>999){UKTemp = 999;}//这里只所以是999封顶而不是1024是因为我(de)系统PWM(de)峰值电压是12V导致.while(1) //如果输出电压和期望电压相差 Delta,则继续调整占空比,直到在误差以内{ADChPro(UPWMADCH); //测量输出电压if( [UPWMADCH] == UKTemp){return;}if( [UPWMADCH] > UKTemp) //如果当前电压大于输出电压,减小占空比{if( ( [UPWMADCH] - UKTemp ) > UDELTA ){temp = [UPWMADCH] - UKTemp; //temp = temp / 2; //下降可以加速下降,所以下降参数加倍if( > temp ){= - temp;else{= 0;}}else{return;}}else //如果当前电压小于输出电压{if( ( UKTemp - [UPWMADCH] ) > UDELTA ){temp = UKTemp - [UPWMADCH];temp = temp / 4; //上升处理不要超调,所以每次只+一半 if( > temp ){+= (temp/2);}else{= 255;}}elsereturn;}}DisPlayVoltage();PWMChangeDuty; //改变占空比Delay(10,10);}}}//附录2直流电机PWM调速系统中控制电压非线性研究引言由于线性放大驱动方式效率和散热问题严重,目前绝大多数直流电动机采用开关驱动方式.开关驱动方式是半导体功率器件工作在开关状态,通过脉宽调制PWM控制电动机电枢电压,实现调速.目前已有许多文献介绍直流电机调速,宋卫国等用89C51单片机实现了直流电机闭环调速;张立勋等用AVR单片机实现了直流电机PWM调速;郭崇军等用C8051实现了无刷直流电机控制;张红娟等用PIC单片机实现了直流电机PWM调速;王晨阳等用DSP实现了无刷直流电机控制.上述文献对实现调速(de)硬件电路和软件流程(de)设计有较详细(de)描述,但没有说明具体(de)调压调速方法,也没有提及占空比与电机端电压平均值之间(de)关系.在李维军等基于单片机用软件实现直流电机PWM调速系统中提到平均速度与占空比并不是严格(de)线性关系,在一般(de)应用中,可以将其近似地看作线性关系.但没有做深入(de)研究.本文通过实验验证,在不带电机情况下,PWM波占空比与控制输出端电压平均值之间呈线性关系;在带电机情况下,占空比与电机端电压平均值满足抛物线方程,能取得精确(de)控制.本文(de)电机闭环调速是运用Matlab拟合(de)关系式通过PID控制算法实现.1 系统硬件设计本系统是基于TX-1C实验板上(de)AT89C52单片机,调速系统(de)硬件原理图如图1所示,主要由AT89C52单片机、555振荡电路、L298驱动电路、光电隔离、霍尔元件测速电路、MAX 232电平转换电路等组成.图1 闭环控制系统示意图2 系统软件设计系统采用模块化设计,软件由1个主程序,3个中断子程序,即外部中断0、外部中断1,定时器0子程序,PID算法子程序,测速子程序及发送数据到串口显示子程序组成,主程序流程图如图2所示.外部中断0通过比较直流电平与锯齿波信号产生PWM波,外部中断1用于对传感器(de)脉冲计数.定时器0用于对计数脉冲定时.测得(de)转速通过串口发送到上位机显示,通过PID模块调整转速到设定值.本实验采用M/T法测速,它是同时测量检测时间和在此检测时间内霍尔传感器所产生(de)转速脉冲信号(de)个数来确定转速.由外部中断1对霍尔传感器脉冲计数,同时起动定时器0,当计数个数到预定值2 000后,关定时器0,可得到计2 000个脉冲(de)计数时间,由式计算出转速:n=60f/K=60N/(KT) (1)式中:n为直流电机(de)转速;K为霍尔传感器转盘上磁钢数;f为脉冲频率;N为脉冲个数;T为采样周期.图2 主程序流程图3 实验结果及原因分析3.1 端电压平均值与转速关系3.1.1 实验结果实验用(de)是永磁稳速直流电机,型号是EG-530YD-2BH,额定转速2 000~4 000 r/min,额定电压12 V.电机在空载(de)情况下,测得(de)数据用Matlab做一次线性拟合,拟合(de)端电压平均值与转速关系曲线如图3(a)所示.相关系数R-square:0.952 1.拟合曲线方程为:y=0.001 852x+0.296 3 (2)由式(2)可知,端电压平均值与转速可近似为线性关系,根椐此关系式,在已测得(de)转速(de)情况下可以计算出当前电压.为了比较分析,同样用Matlab做二次线性拟合,拟合(de)端电压平均值与转速关系曲线如图3(b)所示.相关系数R-square:0.986 7.图3 端电压平均值与转速关系曲线图3.1.2 原因分析比较图3(a)可知,当转速在0~1 500 r/min和4 000~5 000 r/min,端电压平均值与转速间存在(de)非线性,用二次曲拟合如图3(b)所示,拟合相关系数较高.由图3(a)可见,当电机转速为0时电机两端电压平均值约为1.3 V.这是因为电机处于静止状态时,摩擦力为静摩擦力,静摩擦力是非线性(de).随着外力(de)增加而增加,最大值发生在运动前(de)瞬间.电磁转矩为负载制动转矩和空载制动转矩之和,由于本系统不带负载,因此电磁转矩为空载制动转矩.空载制动转矩与转速之间此时是非线性(de).。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
P I D控制算法的C语言实现完整版公司标准化编码 [QQX96QT-XQQB89Q8-NQQJ6Q8-MQM9N]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)这里面有些说明。
那么,知道了隶属度的问题,就可以根据目前隶属的程度来控制电机以多大的速度和方向转动了,当然,最终的控制量肯定要落实在控制电压上。