DDC单回路PID闭环控制系统的设计及实时仿真Word文档下载推荐.docx
《DDC单回路PID闭环控制系统的设计及实时仿真Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《DDC单回路PID闭环控制系统的设计及实时仿真Word文档下载推荐.docx(30页珍藏版)》请在冰豆网上搜索。
u[k]=u[k-1]+q0*e[2]+q1*e[1]+q2*e[0];
其中各项系数为:
q0=kp*(1+T/Ti+Td/T);
q1=-kp*(1+2*Td/T);
q2=kp*Td/T;
实际微分PID算法的传递函数形式为:
采用向后差分法对上式进行离散化,写成差分方程的形式为:
u[k]=c0*(Δu[k-1])+c1*e[k]+c2*e[k-1]+c3*e[k-2]+u[k-1];
c0=Tf/(T+Tf);
c1=kp*T/(T+Tf)*(1+T/Ti+Td/T);
c2=-kp*T/(T+Tf)*(1+2*Td/T);
c3=kp*Td/(T+Tf);
(2.2)数字PID算法的改进
积分分离算法
积分分离算法通过控制PID输入偏差e达到优化目的,当偏差较大时停止积分作用,只有当偏差较小时才投入积分,算法如下表示:
当|e(k)|>
β时,采用PD控制;
当|e(k)|<
β时,采用PID控制;
β的值根据具体对象及要求确定。
抗积分饱和算法
抗积分饱和算法依据控制系统最终的控制输出量u达到优化目的,当控制量u较大且超出执行机构与A/D转换范围时,控制器停止积分作用,保证输出超限时不积分;
带死区的数字PID算法
在实际控制系统中,计算机控制为了避免控制动作过于频繁,以消除系统振荡,就会采用带死区的PID算法。
该算法是在原PID算法前加一个不灵敏区来实现,即
当|e(k)|>
C时,|e(k)|=|e(k)|;
C时,|e(k)|=0
其中C代表不灵敏区值;
(2.3)手动/自动双向无扰切换
自动切手动:
系统处于自动时,手操器实时跟踪自动PID调节器的输出,切换瞬间由于手操器内部电路起保持作用,使得切换没有扰动产生,此时对象处于手操器的开环控制,调节器跟踪手操器的输出。
手动切自动:
手动到自动的切换过程主要由计算机软件实现,一方面PID调节器获得手操器输出,同时软件使得算法中的Δu[k-1])、e[k]、e[k-1]、e[k-2]等历史状态清零。
程序中通过设置键盘,使的按下手动键H时,系统处于手动状态,按下自动键A时,系统处于自动状态。
(3)硬件二阶惯性环节搭建
利用模拟计算机中的电容电阻及运算放大器,搭接二阶惯性环节,仿真一个被控对象。
其传递函数为
,硬件电路如下:
图中各元件参数如下:
R3=R2=510K;
R1=R4=R5=R6=R7=1M;
C1=C2=C=4.7uF;
则可得:
K=(R5/R1)*(R6/R4)=1
T1=T2=R5*C1=R6*C2=1000000*0.0000047=4.7s
所以G(s)=1/(4.7s+1)*(4.7s+1)
搭建好硬件电路后,将PLCD-780插入IPC机箱插槽,用导线将PLCD-780中的A/D、D/A、电源的接线端子与所搭二阶惯性环节的输出、输入端口及机箱上的电源连接,组成一个完整的PID闭环控制系统,为通信做好准备。
(4)PID参数的整定
运用过程控制中PID参数的工程整定方法,运用衰减曲线法对PID参数进行整定。
在matlab中,设置PID参数为Td=0,Ti=
,设置合适的比例带使得对象闭环阶跃响应曲线衰减率为0.9,从而确定PID的整定参数为:
P=0.8
,Ti=1.2tr,Td=0.4tr;
matlab中对象响应曲线为:
由曲线可得PID参数为:
=0.8×
5=4,Ti=1.2tr=1.2×
10=12,Td=0.4tr=0.4×
10=4
(5)实验结果输出
通过在程序中编写相应的绘图模块子程序,在需要画图时调用相应的子程序实现曲线的绘制。
同时在程序中,本小组采用按键实现了PID手自动切换,理想PID与实际PID的切换,以及在手自动状态下由按键改变PID参数,使得调节方式更加的灵活。
3.设计结果
(1)PID阶跃响应曲线
调用程序,向PID模块输入一个阶跃信号,绘出PID阶跃响应曲线如下:
(1.1)理想PID阶跃响应图:
(1.2)实际PID阶跃响应图:
(2)被控对象(惯性环节)阶跃响应曲线
上图通过D/A输出一个1伏左右的信号输入模拟的被控对象(惯性环节),A/D采集对象的输入信号及其响应,再使D/A输出一个幅度为2伏左右的阶跃信号,同时采集输入输出信号。
然后,D/A再反向在输出一个幅度为2伏左右负的阶跃信号,同时采集输入输出信号,得出仿真对象飞升特性曲线。
程序中,通过按键实现模拟对象输入信号的加减。
当按下H按键时,且按下U键时,D/A输出一个1伏阶跃信号,再次按下按键时阶跃信号累加。
每次按下D键时,D/A输出的阶跃信号递减1。
(3)设定值r、控制量u和被控对象输出y的响应曲线:
4.程序清单
/*---------------头文件定义---------------*/
#include<
conio.h>
graphics.h>
#include<
stdio.h>
dos.h>
/*---------------定义绘图坐标---------------*/
#defineox8/*-----原点横坐标-------*/
#defineoy440/*------原点纵坐标------*/
#definexx620/*------x轴顶点横坐标--*/
#definexy440/*-----x轴顶点纵坐标---*/
#definelenx580
#defineleny400
#defineyx8/*-----y轴顶点横坐标----*/
#defineyy15/*------y轴顶点纵坐标----*/
/*-----------------定义绘图区域----------------*/
#defineleft20
#definetop20
#defineright620
#definebottom460
/*----------------坐标轴注释---------------------*/
#definextext1x550
#definextext1y450
#defineytext1x10
#defineytext1y60
#definextext2x610
#definextext2y450
#defineytext2x10
#defineytext2y20
/*-------------------------理想PID运算式--------------------------*/
floatlxpid(floatkp,floattd,floatti,floate[3],floatu1)
{
intt=1;
floatu;
floatq0=kp*(1+t/ti+td/t);
floatq1=-kp*(1+2*td/t);
floatq2=kp*td/t;
u=q0*e[0]+q1*e[1]+q2*e[2]+u1;
returnu;
}
/*-------------------------实际PID运算式--------------------------*/
floatsjpid(floatkp,floattf,floattd,floatti,floate[3],floatdu1,floatu1)
intt=1,k=1000;
floatu2;
floatc1=tf/(t+tf);
floatc2=kp*t*(1+t/ti+td/t)/(t+tf);
floatc3=-kp*t*(1+2*td/t)/(t+tf);
floatc4=kp*td/(t+tf);
u2=c1*du1+c2*e[0]+c3*e[1]+c4*e[2]+u1;
returnu2;
}
/*-------------------------绘图初始化--------------------------*/
voidInitial_Sys(void)
intGraphDriver;
intGraphMode;
detectgraph(&
GraphDriver,&
GraphMode);
initgraph(&
GraphMode,"
C:
\\TC201E\\BGI"
);
cleardevice();
/*-------------------------绘制坐标系------------------*/
voidDrawAxis(void)
inti;
setbkcolor(15);
setcolor(5);
line(ox,oy,xx,xy);
/*x_axis*/
line(xx-5,xy-5,xx,xy);
line(xx,xy,xx-5,xy+5);
line(ox,oy,yx,yy);
/*y_axis*/
line(yx-5,yy+10,yx,yy);
line(yx+5,yy+10,yx,yy);
for(i=0;
i<
51;
i++)
{
line(ox+10*i,oy,ox+10*i,oy-10);
line(ox+10*i+5,oy,ox+10*i+5,oy-5);
for(i=1;
=8;
line(ox,oy-50*i,ox+10,oy-50*i);
outtextxy(ox+50*0-7,oy+20,"
0"
outtextxy(ox+50*1-7,oy+20,"
5"
outtextxy(ox+50*2-7,oy+20,"
10"
outtextxy(ox+50*3-7,oy+20,"
15"
outtextxy(ox+50*4-7,oy+20,"
20"
outtextxy(ox+50*5-7,oy+20,"
25"
outtextxy(ox+50*6-7,oy+20,"
30"
outtextxy(ox+50*7-7,oy+20,"
35"
outtextxy(ox+50*8-7,oy+20,"
40"
outtextxy(ox+50*9-7,oy+20,"
45"
outtextxy(ox+50*10-7,oy+20,"
50"
outtextxy(ox-10,oy-50*1,"
1"
outtextxy(ox-10,oy-50*2,"
2"
outtextxy(ox-10,oy-50*3,"
3"
outtextxy(ox-10,oy-50*4,"
4"
outtextxy(ox-10,oy-50*5,"
outtextxy(ox-10,oy-50*6,"
6"
outtextxy(ox-10,oy-50*7,"
7"
outtextxy(ox-10,oy-50*8,"
8"
settextstyle(SMALL_FONT,HORIZ_DIR,5);
outtextxy(xtext1x,xtext1y,"
Time"
outtextxy(xtext2x,xtext2y,"
t\/s"
settextstyle(SMALL_FONT,VERT_DIR,5);
outtextxy(ytext1x,ytext1y,"
Theoutput(Response)"
outtextxy(ytext2x,ytext2y,"
U(t)\/V"
main()
floatkp,ti,td,tf,e[3]={0},ee[3]={0},u[6]={0},au1=0;
intr=1,k=1;
Initial_Sys();
DrawAxis();
while(k<
100)
u[0]=lxpid(1,3.0,10,e,u[1]);
e[0]=r;
/*printf("
%f\n"
u[0]);
*/
u[3]=sjpid(1,5,3.0,10,ee,au1,u[4]);
line((k-1)*10,130-u[1]*100,k*10,130-u[1]*100);
line(k*10,130-u[1]*100,k*10,130-u[0]*100);
delay(10000);
u[2]=u[1];
u[1]=u[0];
e[2]=e[1];
e[1]=e[0];
ee[0]=r;
setcolor(3);
line((k-1)*10,150-u[4]*100,k*10,150-u[4]*100);
line(k*10,150-u[4]*100,k*10,150-u[3]*100);
u[5]=u[4];
u[4]=u[3];
ee[2]=ee[1];
ee[1]=ee[0];
au1=u[4]-u[5];
k++;
#include"
stdio.h"
math.h"
graphics.h"
/*forgraphdriverinstalling,onlycanbecalledinTurboC*/
string.h"
dos.h"
bios.h"
conio.h"
/*forinterruptprogram头文件定义*/
stdlib.h"
io.h"
/*--------------按键地址区定义--------------------*/
/*statements*/
doublekey_ESC=0x011b;
/*definecannotsuitthelengthofbioskey键盘内存定义*/
doublekey_E=0x1265;
doublekey_A=0x1e61;
doublekey_H=0x2368;
doublekey_U=0x1675;
doublekey_D=0x2064;
doublekey_I=0x1769;
doublekey_P=0x1970;
doublekey_up=0x4800;
doublekey_down=0x5000;
doublekey_left=0x4b00;
doublekey_right=0x4d00;
doublekey_pgup=0x4900;
doublekey_pgdown=0x5100;
/*--------------PLCD780基址定义--------------------*/
#defineBASE0x220/*------------PCL812Gneed16addressesinarow,from220Hto3F0H*/
#defineREG0
#defineox40/*------------原点横坐标-------------*/
#defineoy440/*------------原点纵坐标------------*/
#definexx600/*------------x轴顶点横坐标--------*/
#definexy440/*------------x轴顶点纵坐标--------*/
#defineyx40/*------------y轴顶点横坐标--------*/
#defineyy40/*------------y轴顶点纵坐标---------*/
/*---------------PID参数定义---------------*/
floatKp=1.0;
floatTi=10.0;
floatTd=3.0;
floatTf0=15.0;
floatTf=0;
floatT=0.1;
/*---------------采样时间------------*/
floatad,e,pv0;
floatu=0.0;
floatpv=0.0;
floatsp=0.0;
charA_H='
H'
;
charmanu;
intkey=0;
inttime_counter=0;
/*timesofinterrupt中断的次数*/
intcj_counter=0;
/*samplingcounter采样次数*/
intQ_counter=800;
/*采集步长赋初始值*/
intstepdata[800];
intslopedata[800];
interror[800];
/*--------------函数声明-----------------*/
voidinterrupt(*fadd1C)(void);
/*中断函数声明*/
voidloop();
/*定值采样输出程序声明*/
floatAD(unsignedcharchannal);
/*A/D*/
voidDA(floatpv1);
/*D/A*/
voidinterruptINT_1C(void);
/*8259,resetinterruptcontroller*/
intscankey();
floatDelayAction(floaty0);
/*延迟*/
voidPIDset(void);
/*pid设置声明*/
floatPID(floatsp1,floatpv1,floatKp1,floatTi1,floatTd1,floatTf1,charA_H1,floatT1);
/*pid计算声明*/
floatObject(floatu1,floatT1);
/*二阶惯性环节声明*/
voidInitial_Sys(void);
/*Initiategraphdisplay*/
voidaxis(void);
voidDrawline(intcj,floatpv1,floatsp1,floatu1,floate1);
/*主函数*/
voidmain(void)
500;
{stepdata[i]=10;
slopedata[i]=i;
error[i]=0;
/*SetnewINT_1Candsaveold*/
disable();
/*屏蔽中断*/
fadd1C=getvect(0x1C);
/*1C为定时器控制的软中断,平均一秒发生18.2次,即周期为55ms中断程序,getvect用于取得中断向量入口*/
/*开启中断服务*/
setvect(0x1C,INT_1C);
/*设置中断矢量入口*/
enable();
axis();
/*画坐标轴*/
loop();
/*定时采值输出程序*/
/*主函数结束下面为定时采值输出程序*/
voidloop()
{do
if((cj_counter*T)<
(time_counter/18.2))/*采样次数乘以采样时间小于中断次数除以每分钟中断次数=中断时间*/
{
PIDset();
/*Introduction:
Exit-E/ESC,A_H-A/H,Ideal/ParallelPID,sp-U/D由键盘输入设置pid参数*/
u=PID(sp,pv,Kp,Ti,Td,Tf,A_H,T);
/*DA(u);
*/
pv=Object(u,T);
/*ad=AD(O);
/*pv=DelayAction(u);
e=error[cj_counter];
Drawline(cj_counter,pv,sp,u,e);
manu=0;
/*statusbar,atthetopofthescreen--------------howtoexpress%.2f*/
if(Tf==0)
printf("
IdealPID,Mode:
%c,sp=%.1f,pv=%2.1f,u=%.1f,error=%.1f,Kp=%.1f,Ti=%.1f,Td=%.1f\t\r"
A_H,sp,pv,u,e,Kp,Ti,Td);
elseif(Tf>
0)
Parallal,Mode:
%