MATLAB串口绘制波形

​ 对于MATLAB我也是久仰大名,最近安装了一个,感觉功能很丰富,也比较有意思。当然本人也是刚安装MABLAB不久,对其理解还是分浅薄,暂时也只是一些简单的使用。

函数说明

代码实现

新建函数文件——Serial.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Serial()   %创建函数
delete(instrfindall); %先关闭串口,否则可能导致出错

global x %全局变量,供串口中断函数使用
global t; %全局变量,这里根据需要绘制图形的个人需要而设
global m;
global i;

t = [0]; %时间轴
m = [0]; %数据轴
i = 0; %用于计数

%串口参数配置
x = serial('com3');
set(x,'BaudRate',115200);
set(x,'BytesAvailableFcnMode','Terminator') %ASCII触发,字符触发
set(x,'Terminator','CR/LF') %接收到\r\n后触发中断
x.BytesAvailableFcn = @Callback %定义中断响应函数对象,类似于中断函数名
fopen(x);
pause
fclose(x);
end

另建回调函数文件Callback.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Callback(obj,event)   %创建中断服务函数,绘制图像

global t; %时间
global m; %纵坐标
global i; %时间变化值

out = fscanf(obj);
data = str2num(out) %将接收到的字符转换为数值

%%----------------------以下根据需要自行编写-------------------------------
t = [t i];
m = [m data];
plot(t,m)
xlabel('t');
ylabel('data');
axis([i-50 i+50 0 1000]);
grid on;
i=i+1;
end

样式预览

可以参考下文。

积分优化

梯形积分PID

​ 从微积分的角度来说,当微分到无限小时,矩形积分与梯形积分是没有区别的。但是实际上采样时间不可能无穷小,采样周期越大,偏差就越大。而梯形积分则是更加接近实际曲线,所以用梯形积分可以得到更高的精度。

积分分离PID

在普通的PID控制算法中,由于积分系数是常数,所以在整个控制过程中,积分增量不变。而系统对积分项的要求是:系统偏差大时积分减弱甚至全无,偏差小时积 分加强。积分系数大了会产生超调,小了又不能消除静差。变速积分PID可以根据系统偏差大小改变积分的速度。
在普通的PID控制算法中,引入积分环节目的主要是为了消除静差。但在过程的启动、结束或大幅度增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,使控制量超过可能允许的最大动作范围对应的极限控制量,引起系统较大的超调,甚至引起较大的振荡。积分分离PID可以较好地解决这⼀问题。

基本思想

​ 思路是偏差值较大时,取消积分作用,以免超调量增大;而偏差值较小时,引入积分作用,以便消除静差,提⾼控制精度。
具体的实现步骤是:根据实际情况,设定⼀个阈值

  • 当偏差大于阈值时,消除积分仅用PD控制;
  • 当偏差小于等于阈值时,引⼊积分采⽤PID控制。

积分项表达式

其中β称为积分开关系数

由上述表述及公式我们可以知道,积分分离算法的效果其实与ε值的选取有很大的关系,所以ε值的选取是实现的难点

  • ε值过大则达不到积分分离的效果

  • ε值过小则难以进入积分区。

变速积分PID

基本思想

变速积分PID的基本思想是设法改变积分项的累加速度,使其与偏差大小相对应。

  • 偏差越大,积分越慢;
  • 偏差越小则越快。

为此,设置系数f(e(k)) ,它是e(k)的函数。当e(k)增大时, f减小,反之增大。

积分项表达式

f(e(k))可根据具体情况设定,比较简单的设置为:

由上述公式可知,f(e(k))的值在[0,1]区间变化。

  • 当偏差值e(k)大于分离区间A + B时,不对当前e(k)进行累加;

  • 当偏差值e(k)小于B时,加入当前偏差e(k)进行累加;

  • 介于BA + B之间时,按一定函数关系变化。

这种算法对A,B两个参数的要求不精确,参数整定较容易。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct __PID_t{
float target;
float actual;
float dead_zone;
float Kp, Ki, Kd;
float last_error, pre_error, sum_error;
float I_MAX;
float P_out, I_out, D_out, D_last_out;
float out_MAX, out, out_last;
float I_up, I_low;
float RC_DF;
}PID_t;

if(ABS(p->pre_error) < P->I_low)
{
p->sum_error += (p->pre_error + p->last_error)/2;
p->sum_error = limit(p->sum_error, p->I_MAX, -p->I_MAX);
}
else if(ABS(p->pre_error) < p->I_up)
{
p->sum_error += ((ABS(p->pre_error) - p->I_low)/(p->I_up - p->I_low)) * ((p->last_error + p->pre_error)/2);
p->sum_error = limit(p->sum_error, p->I_MAX, -p->I_MAX);
}

虽然定义的是I_up,I_low, 但是实际上这是与error相比较的

效果展示

Kp = 350Kp350.png

ki = 120

Kp350Ki120.png

Kd = 100

Kd80.png

Kd = 80, up = 80, low = 50

up80low50.png