智能控制实验
实验名称 单神经元自适应PID控制
电子工程与自动化 学院
智能科学与技术 专业
班
作者 学号
实验日期 20## 年 11 月 15 日
辅导员意见:
辅导员
成绩 签 名
单神经元自适应PID控制
一、实验目的
1、熟悉单神经元PID控制器的原理。
2、通过实验进一步掌握有监督的Hebb学习规则及其算法仿真。
二、实验内容
利用单神经元实现自适应PID控制器,对如下二阶对象进行控制,在MATLAB环境中进行仿真。被控对象为:
y(k)=0.368y(k-1)+0.26y(k-2)+0.1u(k-1)+0.632u(k-2)
三、实验原理
线性神经网络是最简单的一种神经元结构,它不同于感知器,其函数是一线性函数,因此神经元的输出可以是任意值。我们可以用它实现增量PID控制器的功能,误差为神经元的输入,权系数为PID控制系数,由于神经网络可以用在线学习对权系数进行实时修改,所以使得PID控制具有了自适应功能。
PID控制器的增量公式为:
一个三输入的线性神经元的计算公式为:
k为神经元的比例系数, w i 为神经元权系数, x i为神经元输入, u为神经元的输出。
神经元的学习方法可以采用Hebb学习规则。有监督的Hebb学习算法规范法处理后为
四、实验步骤
1、编写程序实现单神经元的自适应PID控制器,输入信号为单位阶跃信号。
单神经元控制的各参考参数为
实验结果:
阶跃输入信号Yd及系统输出 Y 系统误差E和受控对象输入信号U
2、修改输入信号为,进行上述试验。
正弦输入信号Yd及系统输出 Y 系统误差E和受控对象输入信号U
神经元的权值调整情况
3、改变被控制对象为如下几种情况,进行上述试验。
模型1:
y(k)=0.368y(k-1)+0.264y(k-2)+u(k-1)+0.632u(k-2)
阶跃输入信号Yd及系统输出 Y 系统误差E和受控对象输入信号U
神经元的权值调整情况
模型2:
y(k)=0.368y(k-1)+0.264y(k-2)+gu(k-1)+0.632u(k-2)
g=1+0.1*sin(0.01k)
阶跃输入信号Yd及系统输出Y 系统误差E和受控对象输入信号U
神经元的权值调整情况
五、问题
讨论神经网络学习算法的收敛速度与自适应控制效果的关系,收敛过程与学习规则中学习系数选取的关系。
答:学习速度快系统的调节时间变短,但是调整的精度会降低,可能会是的系统的稳定性降低。如果学习速度过低会影响系统的实时性。而系统的学习速率是影响收敛速度的主要因素。因此学习速度不能太小也不能太大。
六、总结
经本次实验,我熟悉单神经元PID控制器的原理加深了对单神经元自适应PID控制的认识和理解。掌握有监督的Hebb学习规则及其算法仿真。
七、实验代码:
%Single Neural Adaptive PID Controller
clear all;
close all;
x=[0,0,0]';
xiteP=0.4;
xiteI=0.35;
xiteD=0.4;
%权值初始化
wkp_1=0.1;
wki_1=0.1;
wkd_1=0.1;
%误差初始化
error_1=0;
error_2=0;
%输入输出初始化
y_1=0;y_2=0;y_3=0;
u_1=0;u_2=0;u_3=0;
ts=0.001; %步长
for k=1:1:1000;
time(k)=k*ts;
yd(k)=0.5*sign(sin(2*2*pi*k*ts));%输入信号
y(k)=0.368*y_1+0.26*y_2+(1+0.1*sin(0.01*k))*u_1+0.632*u_2;%受控对象
error(k)=yd(k)-y(k);
%Hebb法则权值调整
wkp(k)=wkp_1+xiteP*error(k)*u_1*x(1);
wki(k)=wki_1+xiteI*error(k)*u_1*x(2);
wkd(k)=wkd_1+xiteD*error(k)*u_1*x(3);
K=0.12;
x(1)=error(k)-error_1;
x(2)=error(k);
x(3)=error(k)-2*error_1+error_2;
%权值修改
wadd(k)=abs(wkp(k))+abs(wki(k))+abs(wkd(k));
w11(k)=wkp(k)/wadd(k);
w22(k)=wki(k)/wadd(k);
w33(k)=wkd(k)/wadd(k);
w=[w11(k),w22(k),w33(k)];
%受控对象信号调整
u(k)=u_1+K*w*x;
%计算系统误差
error_2=error_1;
error_1=error(k);
%计算输出
u_3=u_2;u_2=u_1;u_1=u(k);
y_3=y_2;y_2=y_1;y_1=y(k);
%更新权值
wkp_1=wkp(k);
wkd_1=wkd(k);
wki_1=wki(k);
end
figure(1);
plot(time,yd,'r',time,y,'k:','linewidth',2);
xlabel('时间');ylabel('输入信号(红)/输出信号(黑)');
legend('ideal position','position traching');
figure(2);
plot(time,u,'r',time,error,'k','linewidth',2);
xlabel('时间');ylabel('受控对象的控制信号(红)/系统误差(黑)');
figure(3);
plot(time,w11,'r',time,w22,'k',time,w33,'b','linewidth',3);
xlabel('时间');ylabel('权值w1(红)/权值w2(黑)/权值w3(蓝)');
第二篇:智能控制实验报告
智能控制实验报告
数字PID及其算法
戴子文 200730580307
房柳煌 200730580309
张荣春200730580331
指导老师:陈瑜
日期:20##年12月2日
华南农业大学工程学院
数字PID及其算法
一、 实验目的:
1、 掌握数字PID及其算法
2、 掌握AS-UII电机的软件驱动方法特性、AS-UII走直线的开环特性、AS-UII的闭环特性及其分析方法
二、 实验原理及实验步骤:
1、PID算法的数字化实现
在模拟系统中,PID算法的表达式为:
式中,
P(t)----调节器的输出信号;
e(t)-----调节器的偏差信号,它等于测量值与给定值之差;
Kp-----调节器的比例系数;
T1----调节器的积分时间;
TD----调节器的微分时间;
离散化的PID:
Δt=T 采样周期,必须使T足够少,才能保证系统有一定的精度;
E(k) 第K次采样时的偏差值;
E(k-1) 第K-1次采样时的偏差值;
K 采样序号,K=0,1,2……;
P(k) 第K次采样时调节器的输出;
上式计算复杂,经过化简为:
式中:
积分系数
微分系数
要计算第K次输出值P(k),只需要知道P(K-1),E(K),E(k-1),E(K-2)即可。
上式也称为位置型PID的位置控制算法。
在很多控制系统中,由于执行机构是采用布进电机进行控制,所以只要给一个增量信号即可。因此得到增量型PID的位置控制算法
2、AS-UII的PID算法的程序设计
(1) AS-UII电机的软件驱动特性
我们控制AS-UII的电机转动是通过编程实现的,我们的编译环境是VJC1.5开发版。这种用软件实现控制的方式与一般的用电压或频率直接控制电机不同,控制量是通过函数drive(参1,参2)或motor(参1,参2)给予。函数motor()用于电机功率级别的控制,功率范围是-100(反向最大)到100(前向最大),系统软件实际上只能控制电机工作于7个不同的功率级别,但参数是从-100到100。
我们的问题是,这个对象没有准确的数学模型。
那么,输入和输出大概有什么样的关系呢,我们需要通过测量得到对象大致的特性。在motor()内输入控制量,记下输出值,也即左右轮胎速度。这些都是通过编程实现的。输出值显示在AS-UII上的液晶显示屏上。
求轮胎的速度要用到光电编码器,虽然AS-UII的每个光电编码器都是按照每圈33个脉冲设计的,但是因为机械原因会出现误差,所以用光电编码器读得的脉冲数计算速度之前要检测一下它的实际值。
求实际速度的算法如下:
float v1,v2;
float T=1.5;
void main()
{
motor(1,50);
motor(2,50);
rotation(1);
rotation(2);
resettime();
while(1)
{
if(seconds()>5.0)
{
stop();
break;
}
wait(T);
v1=(float)rotation(1)*v1/T;
v2=(float)rotation(2)*v2/T;
printf("v1=%f,v2=%f\n",v1,v2);
}
}
注:v1、v2分别是测得的左轮和右轮的分辨率
2)观察对象的特性
a.输入定值(左轮右轮的输入值都为50,T=1.5秒),记录不同时刻的输出值,测
得的实验数据如下:
表一:
输入输出图形大致如下
这样观察对象的特性,存在很多误差(每个周期记录的速度只是这个周期的平均速度,没法看到轮胎速度变化的全过程;光电编码器的读值有误差,这样,平均速度就不是很准确),但因为我们这个实验只是用于说明我们可以控制能力风暴走直线这样一个事实,不追求很大的精确性,所以这样的误差就不去考虑了。
从上图可看出,输出对输入响应很快,反应时间几乎不用考虑,并且输出基本在某个定值附近脉动。
b. 输入不同值,记录输出值于表二(T=1.5秒)
(2) AS-UII走直线的开环特性
代码如下:
void main()
{motor(1,50);
motor(2,50);
}
让AS-UII纵向走两米,观察它的横向偏移。
改变输入值,测量偏移距离。
(3) AS-UII的闭环特性
应用PID算法进行反馈控制。根据控制量,我们采用位置式算法。
3、 位置式算法
P公式如:U=Kei+Uo;
PI公式如:U=K(Ei+T/Ti*Σej)+Uo;
PID公式如:U=K(Ei+T/Ti*Σej+Td/T*(Ei-Ei-1))+Uo;
因为左右轮的特性不一样,可以对他们分别控制。
这里Uo是控制量的基准,这里是50,电机期望的速度是50,E是实际速度与期望速度的偏差,U是控制量,将做为motor()的控制参数。
代码如下:
/*用PID控制算法实现的走直线控制,位置式算法*/
/*左右轮有相同的设定值,对误差进行调整;根据左右轮的误差再对右轮进行调整,使左右轮尽量保持一致,从而走直线。*/
float K1=0.05;
float Ti1=15.0;
float Td1=0.1;
float K2=0.2;
float Ti2=15.0;
float Td2=0.1;
float T=0.5;
float velocity_1;
float velocity_2;
float u_1_i;/*控制量*/
float u_2_i;
float error_1_i,error_1_i1,error_1_i2;
float error_2_i,error_2_i1,error_2_i2;
void main()
{
motor(1,50);
motor(2,50);
rotation(1); /*将左右轮脉冲记数清零*/
rotation(2);
resettime(); /*系统时间复位*/
error_1_i1=0.0;
error_2_i1=0.0;
error_1_i2=0.0;
error_2_i2=0.0;
while(1)
{
if(seconds()>4.0)
{
stop();
break;
}
wait(T);
/*计算error_i*/
velocity_1=(float)rotation(1)*0.619/T;
error_1_i=50.0-velocity_1;
velocity_2=(float)rotation(2)*0.659/T;
error_2_i=50.0-velocity_2;
printf(“v1=%f”,velocity_1);
printf(“v2=%f\n”,velocity_2);
u_1_i=K1*(error_1_i+T/Ti1*error_1_i2+Td1/T*(error_1_i-error_1_i1))+50.0; //PID算法
u_2_i=K2*(error_2_i+T/Ti2*error_2_i2+Td2/T*(error_2_i-error_2_i1))+50.0;
/*
u_1_i=K1*error_1_i+50.0; //P算法
u_2_i=K2*error_2_i+50.0;
*/
/*
u_1_i=K1*(error_1_i+T/Ti1*error_1_i2)+50.0; //PI算法
u_2_i=K2*(error_2_i+T/Ti2*error_2_i2)+50.0;
*/
motor(1,(int)u_1_i);
motor(2,(int)u_2_i);
/*将error_i的值赋给error_i1,并将error_i叠加到error_i2上*/
error_1_i1=error_1_i;
error_2_i1=error_2_i;
error_1_i2=error_1_i2+error_1_i;
error_2_i2=error_2_i2+error_2_i;
}
}
对偏移有如下规定:
A.先用P算法,保持T=0.5不变。测量左右轮比例系数和重点偏移距离。
B.用PI算法,取上一步骤中直线效果较好的K1和K2, T取0.5,测量左右轮微分系数和偏移距离。
C.PID算法,取上一步骤中直线效果较好的Ti1和Ti2,K1、K2 和T不变,测量左右轮微分系数和偏移距离。
2)增量式算法
P算法公式如:Δui=Ui-Ui-1=K*(Ei-Ei-1);
PI算法公式如:Δui=Ui-Ui-1=K*(Ei-Ei-1+T/Ti*Ei);
PID算法公式如:Δui=Ui-Ui-1=K*(Ei-Ei-1+T/Ti*Ei+Td/T*(Ei-2Ei-1+Ei-2));
原来增量式算法是用于一些步进电机之类的对象,因为它的控制量是增量。以增量为控制量可以减少切换时的冲击。但是我们这里的电机并非步进电机,所以输入的控制量应是绝对数值。所以算法公式应改成如下:
P算法公式如:Ui=K*(Ei-Ei-1)+Ui-1;
PI算法公式如:Ui=K*(Ei-Ei-1+T/Ti*Ei)+Ui-1;
PID算法公式如:Ui=K*(Ei-Ei-1+T/Ti*Ei+Td/T*(Ei-2Ei-1+Ei-2))+Ui-1;
但是,这样的话,增量式算法和位置式算法的结果实质上是一样的。这里就不采用了。
三、实验记录及数据分析:
1、测量光电编码器的实际分辨率:
给左右轮相同的设定值,在一定的时间段,读编码器的读数和轮胎转动圈数。
从上表可见,左右轮的光电编码器的分辨率不同,左轮为33,右轮为32。
所以,我们在计算时将取左轮的光电编码器一圈读33个脉冲,右轮的光电编码器一圈读32个脉冲。虽然左右轮的周长可能也不同,但是该误差较小,所以暂且假设他们相等,都为65mm,所以左轮的分辨率为6.18mm/脉冲,右轮的分辨率为6.35mm/脉冲。
2、 观察对象的特性
输入不同值,记录输出值,实验测得的数据如下:(T=1.5秒)
表二:
因为电机的控制函数motor()或drive()的控制范围在0~100之间,所以取10~90,在图纸上描点,发现对象是非线性的。而且,在相同输入下,右轮比左轮输出值小。
我们得到了对象大致的特性后,就可以控制它,使它走直线。使左轮右轮走直线,可以用两种方式。第一种,使左轮右轮都趋近于同一个设定值;第二种,使右轮跟随左轮的速度。采用第一种,使左右轮都趋近于50。
从表一的图可看出,我们要控制的不是对象的反应速度,而是控制它的脉动和偏差,尽量趋向于设定值,从表二,可以看出右轮的特性与左轮不同,所以可以对左右轮分开控制。因为PID调节方法对任何对象都有较大的调节作用,所以我们采用该调节方法对对象特性进行调节。
3、AS-UII走直线的开环特性
测得的实验数据如下:
4、AS-UII的闭环特性
A.P算法,保持T=0.5不变,记录数据如下:
由以上数据可见,要使能力风暴走直线,右轮的比例系数应比左轮的比例系数大一点,但右轮比左轮大到一定程度时走路会发生弯曲,并从偏移正值变为负值。另一方面,他们的比例系数增大时,横向偏差越来越小。但当比例系数大到一定程度时,速度会有较大的振荡。取上面最理想的比例系数K1=0.1,K2=0.1不变,改变T。
所以,T取0.5最合适。
B.用PI算法,保持K1=0.1,K2=0.1,T=0.5不变。
PI算法可以减小静差,用在这里,效果不是很大,甚至会因为积分累积引起AS-UII走路弯曲。
C.PID算法,取K1=0.1,K2=0.1,Ti1=20,Ti2=30,T=0.5不变
PID可以减小超调,在PI基础上加上微分因子,超调就小了,从AS-UII的弯曲程度上就可看出。
四、实验结论
能力风暴的对象特性不确定,所以难以给出明确的对象传递函数,这样也就难以用我们平时所用的步骤来设计控制器,即根据传递函数来设计控制器的函数。但实际上有时即使对象明确,也难以用计算得的PID控制器来控制,而是要采用试凑法,所以我们在能力风暴走直线的问题上采用试凑法。事实证明,PID控制算法的确实能控制能力风暴走直线。但是其中还存在不少问题,在电池电量不同的情况下,能力风暴在相同设定值下的转速不同,这样就会发生刚刚调的最好的PID参数过一会就显得没那么好了,所以我们要寻找鲁棒性最好的PID参数。
并且需注意的是,以上的数据是基于某台能力风暴,对于不同的能力风暴,机械特性不同,所以可以参照我做实验的步骤,从测对象特性开始做。我的实验数据的价值在于观察变化趋势,其绝对值可能因为不同情况而不同。
附录:参考程序
/*用PID控制算法实现的走直线控制,位置式算法*/
/*左右轮有相同的设定值,对误差进行调整。*/
float K1=0.1;
float Ti1=20.0;
float Td1=0.1;
float K2=0.1;
float Ti2=20.0;
float Td2=0.1;
float T=0.5;
float velocity_1;
float velocity_2;
float u_1_i;/*控制量*/
float u_2_i;
float error_1_i,error_1_i1,error_1_i2;
float error_2_i,error_2_i1,error_2_i2;
void main()
{
motor(0,50);
motor(0,50);
rotation(1); /*将左右轮脉冲记数清零*/
rotation(2);
resettime(); /*系统时间复位*/
error_1_i1=0.0;
error_2_i1=0.0;
error_1_i2=0.0;
error_2_i2=0.0;
while(1)
{
if(seconds()>5.5)
{
stop();
break;
}
wait(T);
/*计算error_i*/
velocity_1=(float)rotation(1)*0.619/T;
error_1_i=50.0-velocity_1;
velocity_2=(float)rotation(2)*0.659/T;
error_2_i=50.0-velocity_2;
printf("v1=%f",velocity_1);
printf("v2=%f\n",velocity_2);
/*
u_1_i=K1*(error_1_i+T/Ti1*error_1_i2+Td1/T*(error_1_i-error_1_i1))+50.0;
u_2_i=K2*(error_2_i+T/Ti2*error_2_i2+Td2/T*(error_2_i-error_2_i1))+50.0;
*/
u_1_i=K1*error_1_i+50.0;
u_2_i=K2*error_2_i+50.0;
/*
u_1_i=K1*(error_1_i+T/Ti1*error_1_i2)+50.0;
u_2_i=K2*(error_2_i+T/Ti2*error_2_i2)+50.0;
*/
motor(1,(int)u_1_i);
motor(2,(int)u_2_i);
/*将error_i的值赋给error_i1,并将error_i叠加到error_i2上*/
error_1_i1=error_1_i;
error_2_i1=error_2_i;
error_1_i2=error_1_i2+error_1_i;
error_2_i2=error_2_i2+error_2_i;
}
}