PID评价系统 C语言实现
前言
自大一入学以来,做电控接触的最多的就是pid了,但目前我们判断一个pid的好坏,主要还是通过肉眼来看曲线并借助经验来判断PID调的好坏,本文通过C语言写了一个函数来测量超调率,pid测量值到达目标值90%的响应时间以及稳态误差,便于我们pid调试时能够更加精确的判断pid的好坏,而不仅仅通过曲线粗略的观察
一、超调率是什么?
下面用一张图来解释,假设初始值是0,目标值是100,横坐标为t(时间),纵坐标为测量值和目标值的基本单位,通过matlab仿真得到下图:
超调率用公式表示如下:
用文字表示则是:
二、响应时间是什么?
仍然是那张图:
放大后可以更清楚的看到响应时间
三、稳态误差是什么?
我们将那张图放大,可以看到测量值无限接近与目标值,但并未完全达到目标值,且这个误差并不会随着时间的推移而消失,这就是我们所说的稳态误差。
四、如何通过代码来实现对这几个量的测量
首先是结构体的建立:
typedef struct pid_eva
{
float set_core;
float last_set;
int t_xiang;
float angle;
float evaluate_time;
int core;
int core1;
float max_chao;
float fps;
float fps_core;
float max_set;
float max_get;
float steady_error;
float steady_core;
float get;
float last_get;
float set;
float set_time;
float set_get_d;
} pid_eva;
其次是代码编写部分:
void pid_evaluate(pid_eva*pid_eva,float angle,float set)//在.h文件中定义外部结构体后,输入angle为位置或速度,set为目标值即可使用
{
pid_eva->get=angle;//赋值
pid_eva->set=set;
//响应速率计算单位ms
if(pid_eva->last_set!=pid_eva->set&&pid_eva->core1==0)
{
pid_eva->core1=1;//检测到目标值变化,开始记录响应时间
pid_eva->max_get=pid_eva->get;
pid_eva->max_set=0;
pid_eva->t_xiang=0;
if(pid_eva->last_set<pid_eva->set)//分两种情况对超调率进行讨论计算
pid_eva->core=1;
if(pid_eva->last_set>pid_eva->set)
pid_eva->core=0;
pid_eva->set_get_d=fabs(pid_eva->set-pid_eva->last_set);
}
if(pid_eva->core1==1)
{
if(pid_eva->t_xiang<2000)//记录之后2s秒的数据
{
if(pid_eva->core==1)
{
if(pid_eva->get>pid_eva->max_get)//求出最大获取量
pid_eva->max_get=pid_eva->get;
}
if(pid_eva->core==0)
{
if(pid_eva->get<pid_eva->max_get)//求出最小获取量
pid_eva->max_get=fabs(pid_eva->get);
}
if(fabs(pid_eva->set)>fabs(pid_eva->max_set))//求出最大目标量
{
pid_eva->max_set=fabs(pid_eva->set);
pid_eva->set_time=pid_eva->t_xiang;//目标值到达最大值时的调节时间
}
if(fabs(pid_eva->get)>fabs(0.85*pid_eva->set)&&fabs(pid_eva->get)<fabs(0.9*pid_eva->set))//阶跃至90%的响应时间
pid_eva->evaluate_time=pid_eva->t_xiang;//计算响应时间/单位ms
if(fabs(pid_eva->set-pid_eva->get)<100)//稳态误差计算设置
pid_eva->steady_error=fabs(pid_eva->set-pid_eva->get); //稳态误差
else
pid_eva->steady_error=65535;//未达到稳态误差条件,稳态误差无穷大
pid_eva->t_xiang+=1;//响应时间为1ms
}
else
{
if(pid_eva->max_set!=0)//计算超调率时排除0的情况
pid_eva->max_chao=(fabs(pid_eva->max_get)-fabs(pid_eva->max_set))/fabs(pid_eva->max_set);//循环结束后计算最大超调率
else
pid_eva->max_chao=(fabs(pid_eva->max_get)-0)/pid_eva->set_get_d;
pid_eva->core1=0;
pid_eva->last_set=pid_eva->set;
// pid_eva->max_get=0;
// pid_eva->max_set=0;
}
}
}
五、PID评价函数的使用方法
首先在外部定义一个结构体
像这样:
extern pid_eva pid_eva1;
其次是将这个函数放在单片机1ms循环一次的任务中,这里通过cubemx创建了一个freertos系统,直接放在任务中,osDelay(1)即可
像这样,其中第一个数据为结构体,第二个数据为我们读出的测量值,一般是位置或者速度,第三个数据是我们设置的目标值:
void eva(void const * argument)
{
/* USER CODE BEGIN eva */
/* Infinite loop */
for(;;)
{
pid_evaluate(&pid_eva1,motor_left_position,g_nSpeedTarget);
osDelay(1);
}
/* USER CODE END eva */
}
最后通过硬件仿真查看这几个变量的值即可:
其中超调率为:
响应时间(单位ms)为:
稳态误差为:
总结
提示:这里对文章进行总结:
个人还只是个萌新,对自控原理还不是非常了解,所以有错的话希望大家能够批评指出。