华北电力大学计算机控制课程ddc串级回路pid闭环.docx
(26页)
本资源提供全文预览,点击全文预览即可进行全文预览,如果您喜欢下载文档,查找使用更方便哦!
9.90 积分
课程设计报告名称:过程计算机控制主题: DDC串级回路PID闭环控制系统设计及实时仿真系统:控制班: 学号: 学生姓名: 同组人: 指导教师:李明扬设计周数:一周一、设计目的1. 学习并了解用高级语言(C语言)实现数字PID控制算法模块程序的方法;2. 比较验证理想微分PID和实际微分PID控制算法阶跃响应,加深对上述两种算法各自特征的理解;3. 学习如何使用模拟计算机;4. 学习掌握A/D、D/A使用转换接口板的方法;5. 了解微机中断定时的方法;6. 学习掌握通过A/D、D/A用计算机转换被控对象的动态特性;7. 通过实时仿真实验掌握实时仿真实验DDC编制和调试单回路控制程序。二、实验仪器(1)一台微型计算机,系统软件Windows 98或DOS (不能直接使用I/O能力的NT或XP系统), 内装Turbo C 2.0/3.集成开发环境软件;(2)模拟计算机(XMN-(3)一块通用数据采集控制板(PCL-812PG型)。三、PID离散化理想微分PID该算法的传递函数形式为:采用向后差分法离散上式,差分方程形式为: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);使用模拟计算机中的电容电阻和操作放大器构建硬件二阶惯性环节,搭接二阶惯性链接,模拟被控对象。其传递函数为,硬件电路如下:图中各元件参数如下: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闭环控制系统,为通信做好准备。五、实验结果理想与实践PID上图通过阶跃响应曲线(2)被控对象(实物构建二阶惯性环节)D/A输出约1伏的信号输入模拟被控对象(惯性链接),A/D收集对象的输入信号及其响应D/A输出一个幅度为2伏左右的阶跃信号,同时采集输入输出信号。然后,D/A反向输出约2伏负的阶跃信号,同时收集输入输出信号,获得模拟对象的飞升特性曲线。然后,D/A然后反向输出约2伏负的阶跃信号,同时收集输入输出信号,获得模拟对象的飞行特征曲线。在程序中,模拟对象输入信号通过按钮加减。按下H键并按下U键时,D/A输出1伏阶跃信号,按下按钮再次累积阶跃信号。每次按下D键D/A输出阶跃信号递减1。(3)根据对象单位阶跃响应曲线寻求增益和惯性时间:利用切线法寻求对象的增益和一阶等效的惯性时间:如上图所示,对象增益和一阶等效惯性时间分别为: Ti≈13s(4)手动切换:(5)设定值r、阶跃响应曲线:程序列表/*---------------头文件定义---------------*/#include#include#include#include/*---------------定义绘图坐标---------------*/#defineox8/*-原点横坐标-------*/#defineoy440/*------原点纵坐标------*/#definexx620/*------x轴顶横坐标--*/#definexy440/*-----x轴顶点纵坐标---*/#definelenx580#defineleny400#defineyx8/*-----y轴顶横坐标----*/#defineyy15/*------y轴顶点纵坐标----*//*-----------------定义绘图区域----------------*/#defineleft20#definetop20#defineright620#definebottom460/*----------------坐标轴注释---------------------*/#definextext1x450#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运算式--------------------------*/nbsp;float sjpid(float kp,float tf,float td,float ti,float e[3],float du1,float u1) { int t=1; float u2; float c1=tf/(t+tf); float c2=kp*t*(1+t/ti+td/t)/(t+tf); float c3=-kp*t*(1+2*td/t)/(t+tf); float c4=kp*td/(t+tf); u2=c1*du1+c2*e[0]+c3*e[1]+c4*e[2]+u1; return u2; }/*-------------------------绘图初始化--------------------------*/ void Initial_Sys(void) { int GraphDriver; int GraphMode; detectgraph(&GraphDriver,&GraphMode); initgraph(&GraphDriver,&GraphMode,"C:\\TC201E\\BGI"); cleardevice(); }/*-------------------------绘制坐标系------------------*/ void DrawAxis(void) { int i; 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++) /*-x轴刻度-*/{ 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;i<=8;i++) /*-y轴刻度-*/ 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,"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,"The output (Response)"); outtextxy(ytext2x,ytext2y,"U(t)\/V"); }}main() { float kp,ti,td,tf,e[3]={0},ee[3]={0},u[6]={0},au1=0; int r=1,k=1; Initial_Sys(); DrawAxis(); while(k<100) { u[0]=lxpid(1,3.0,10,e,u[1]); e[0]=r; u[3]=sjpid(1,5,3.0,10,ee,au1,u[4]); setcolor(5); 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[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); delay(10000); 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" #include "math.h" #include "graphics.h" #include "string.h" #include "dos.h" #include "bios.h" #include "conio.h" /*中断程序头文件定义*/#include "stdlib.h" #include "io.h"/*--------------按键地址区定义--------------------*/ /*statements*/ double key_ESC=0x011b; /*退出*/double key_E=0x1265; double key_A=0x1e61; /*自动*/double key_H=0x2368; /*手动*/double key_U=0x1675; /*自动时增SP,手动时增手操器输出*/double key_D=0x2064; /*自动时减SP,手动时增手操器输出*/double key_I=0x1769; /*理想PID*/double key_P=0x1970; /*实际PID*/ double key_up=0x4800; /*手动时,增Kp*/double key_down=0x5000; /*手动时,减Kp*/double key_left=0x4b00; /*手动时,减Ti*/ double key_right=0x4d00; /*手动时,增Ti*/double key_pgup=0x4900; /*手动时,增Td*/ double key_pgdown=0x5100; /*手动时,减Td*//*--------------PLCD780基址定义--------------------*/ #define BASE 0x220 /*------------PCL812G need 16 addresses in a row,from 220H to 3F0H*/ #define REG 0/*---------------定义绘图坐标---------------*/ #define ox 40 /*------------原点横坐标-------------*/ #define oy 440 /*------------原点纵坐标------------*/ #define xx 600 /*------------x轴顶点横坐标--------*/ #define xy 440 /*------------x轴顶点纵坐标--------*/ #define yx 40 /*------------y轴顶点横坐标--------*/ #define yy 40 /*------------y轴顶点纵坐标---------*//*---------------PID参数定义---------------*/float Kp=1.0; float Ti=10.0; float Td=3.0; float Tf0=15.0; float Tf=0; float T=0.1; /*---------------采样时间------------*/ float ad,e,pv0; float u=0.0; float pv=0.0; /*反馈值*/ float sp=0.0; /*设定值*/char A_H='H'; /*手动-自动,开始为手动*/char manu; /*用于调节u_m的增减*/ int key=0; /*存键盘扫描结果*/ int time_counter=0; /*中断计数*/ int cj_counter=0; /*采样计数器*/ int Q_counter=800; /* 采集步长 赋初始值*/ int stepdata[800]; int slopedata[800]; int error[800];/*--------------函数声明 -----------------*/ void interrupt (*fadd1C)(void); /*中断*/void loop(); /*主程序循环*/float AD(unsigned char channal); /*A/D*/ void DA(float pv1); /*D/A*/ void interrupt INT_1C(void); /*8259,reset interrupt controller*/ int scankey(); /*扫描键盘,判断是否有建按下*/float DelayAction(float y0); /*软件延迟*/void PIDset(void); /*PID设置*/float PID(float sp1,float pv1,float Kp1,float Ti1,float Td1,float Tf1,char A_H1,float T1); float Object(float u1,float T1); /*仿真对象*/void Initial_Sys(void); /*初始化为图形模式*/void axis(void); /*画坐标轴*/void Drawline(int cj,float pv1,float sp1,float u1,float e1); /*画线*//*主函数*/ void main(void){int i; for(i=0;i<500;i++) { stepdata[i]=10; slopedata[i]=i; error[i]=0;} /* Set new INT_1C and save old */ disable(); /*保存旧中断,设置新中断*/fadd1C=getvect(0x1C);/*1C为定时器控制的软中断,平均一秒发生18.2次,即周期为55ms 中断程序*/ /* 开启中断服务*/ setvect(0x1C,INT_1C); enable(); axis(); loop(); } /*主函数结束 下面为定时采值输出程序*/void loop() { do { if((cj_counter*T)0) printf("Parallal,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); else printf("\t\tTf got a wrong value! Please exit and restart this program.\r");cj_counter++; } }while(cj_counter<500); /* 恢复中断*/ disable(); setvect(0x1C,fadd1C); enable(); } /*D/A conversion program,0 to 4095 -- 0to +5*/ float AD(unsigned char channal) { float result=0; int i; unsigned char hb=0,lb=0,poll=0x10; outportb(BASE+11,REG); /*软件程序触发*/ for(i=0;i<10000;i++);outportb(BASE+10,channal); /*进行通道设置.选择通道0*/ for(i=0;i<10000;i++);outportb(BASE+9,0); /*设置增益通道增益*/ for(i=0;i<10000;i++); outportb(BASE+12,0); /*触发A/D转换*/ for(i=0;i<10000;i++); do{ /*查询法读PV*/poll=inportb(BASE+5); }while(poll&0x10); hb=inportb(BASE+5); for(i=0;i<10000;i++);lb=inportb(BASE+4); result = lb + ((hb&0x0F)<<8); /*0 to 4095*/ result=result*5/4096; /*0 V to +5V*/ return result; } /*A/D conversion program,0 to +5 -- 0 to 4095*/ void DA(float pv1) { int temp,i; unsigned char hb,lb; /*限幅 */if (pv1>5) /* make the output real */ pv1=5; else if (pv1<0) pv1=0; temp=(int)(4095*pv1/5.0); hb=temp<<8; lb=temp-(hb<<8);outportb(BASE,1); /*启动DA转换*/ for(i=0;i<10000;i++); outportb(BASE+4,lb); /* low 8 */ for(i=0;i<10000;i++); outportb(BASE+5,hb); /* high 4 */ }/*00----------------------------中断子程序-------------------------*/void interrupt INT_1C(void) { time_counter++; outportb(0x20,0x20); } /*键盘控制*/ int scankey(void) { int key0; /*扫描键盘,判断是否有建按下*/ key0=bioskey(1); /*1:无键按下则返回0 */ if(key0!=0) key0=bioskey(0); /*0:返回按下的键*/ return key0; }/*DelayAction*/ /*tao=(int)(18.2*2) Delay action=2 seconds*/ float DelayAction(float y0) /*软件延迟*/ { float y_out;static float y_old[36]={0}; /*将ad延迟2s作为PV,T=0.2s,于是延迟36步*/int cyc; y_out=y_old[36-1]; for(cyc=1;cyc<36;cyc++) y_old[36-cyc]=y_old[36-cyc-1]; y_old[0]=y0; return y_out; }/*PID 主程序*/ void PIDset(void) /*PID设置*/ { key=scankey(); /*扫描键盘,并将按键存为key*/ if(A_H=='H') /*手动状态*/{ if(key==key_up) Kp+=0.2; else if(key==key_down) Kp-=0.2;else if(key==key_left) Ti-=0.2; else if(key==key_right) Ti+=0.2; else if(key==key_pgup) Td+=0.2; else if(key==key_pgdown) Td-=0.2;else if(key==key_U) /*控制u_m增减*/manu='+'; else if(key==key_D) manu='-'; } if(A_H=='A') /*自动状态*/ { if(key==key_U) /*设定值增减*/sp+=10; if(key==key_D) sp-=10; } if(key==key_E||key==key_ESC) /*退出*/ exit(1); if(key==key_A) /*设为手动*/ A_H='A'; if(key==key_H) /*设为自动*/A_H='H'; if(key==key_I) /*理想PID*/Tf=0; if(key==key_P) /*实际PID*/Tf=Tf0; }/*PID-default:IdealPID*/ float PID(float sp1,float pv1,float Kp1,float Ti1,float Td1,float Tf1,char A_H1,float T1) { float delta_u,u0,e,C1,C2,C3,C4; /*离散化后PID参数 当前时刻,u0为返回值*/static float e1,e2,u1,delta_u1; /*前一时刻的值*/ if(Kp1<0) printf("Kp becomes a negative number,please restart."); else if(Ti1<0) printf("Ti becomes a negative number,please press restart."); else if(Td1<0) printf("Td becomes a negative number,please press restart."); else { C1=Tf1/(T1+Tf1); C2=Kp1*T1*(1+T1/Ti1+Td1/T1)/(T1+Tf1); C3=-Kp1*T1*(1+2*Td1/T1)/(T1+Tf1); C4=Kp1*Td1/(T1+Tf1); /*自动控制*/ if(A_H1=='A') { e=sp1-pv1; delta_u=C1*delta_u1+C2*e+C3*e1+C4*e2; /*delta_u1是delta_u前一时刻的值*/ u0=u1+delta_u; /*当前时刻控制器输出*/ e2=e1; e1=e; delta_u1=delta_u; u1=u0; /*自动时,手操器输出跟踪自动输出*/ error[cj_counter]=sp1-pv1; return u0;}/*手动控制*/ else if(A_H1=='H') { if(manu=='+') /*调节手操器输出*/u+=10; if(manu=='-') u-=10; sp1=pv1; u1=u; sp=pv1; /*sp跟踪pv保证偏差e为0*/ e1=0; e2=0; delta_u1=0; /*将前两时刻的偏差赋值为0*/ error[cj_counter]=sp1-pv1; return u; } } } /*显示与画图*//*初始化 CRT*/ void Initial_Sys(void) { int GraphDriver; int GraphMode; detectgraph(&GraphDriver,&GraphMode); initgraph(&GraphDriver,&GraphMode,"C:\\TC201E\\BGI"); } /*draw basic coordinate axis*/ void axis(void) { int i;Initial_Sys(); setbkcolor(15); /*white0/black15*/ setcolor(9); /*linght blue*/ rectangle(10,20,630,470); /*zone of drawing*/ line(ox,oy,xx,xy); /*axis and arrow*/ line(xx-5,xy-5,xx,xy); line(xx,xy,xx-5,xy+5); line(ox,oy,yx,yy); line(yx-5,yy+5,yx,yy); line(yx+5,yy+5,yx,yy); settextstyle(2,1,5); /*Small font,vert,5 times bigger*/ outtextxy(20,100,"The Output (Response)"); outtextxy(20,40,"U(t)"); settextstyle(2,0,5); /*Small font,horiz,5 times bigger*/ outtextxy(300,455,"Time"); outtextxy(590,455,"t/sec"); setlinestyle(1,0,1); /*dot line,none,width*/ for(i=1;i<4;i++) /*each inport starting position*/ line(ox,oy-100*i,ox+500,oy-100*i); outtextxy(ox-16,oy-100*0,"0"); outtextxy(ox-16,oy-100*1,"1"); outtextxy(ox-16,oy-100*2,"2"); outtextxy(ox-16,oy-100*3,"3"); for(i=1;i<=500/50;i++) /*scale*/ { line(ox+50*i,oy,ox+50*i,oy-400); /*1/T=10,that is 10px=1sec*/ line(ox+50*i-25,oy,ox+50*i-25,oy-10); } setlinestyle(0,0 关 键 词: 华北 电力大学 过程 进程 计算机控制 ddc 回路 pid 闭环
天天文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文
本文标题:华北电力大学过程计算机控制课设ddc串级回路pid闭环.docx
链接地址: https://www.wenku365.com/p-32738997.html