PID算法C语言模拟演示

由于暂时没有硬件平台,网上找到一篇"用C语言实现PID控制代码",写的非常好,参照其文章,自己也动手实验了一下,下面通过几张 Execl 截屏说明下 Kp、Ki、Kd 三个参数不同取值时的输出效果。

感谢CSDN博主「生活不易到处是坑」的原创文章:
原文链接:https://blog.csdn.net/qq_38833931/article/details/80630960

下面是参照文章写出的源码,有兴趣做实验的朋友直接复制即可:

#include 

typedef struct pid_parameter
{
	float Target;		//目标值
	float Actual;		//实际值(反馈值)
	float Error;		//偏差值(当前偏差)
	float Last_error;	//上次偏差值
	float Integral;		//积分值
	float Kp,Ki,Kd;		//比例,积分,微分系数
	float Out;			//输出值
}pid;

pid user_pid;

float PID_Calculation(float User_target)//pid算法输出
{
	user_pid.Target = User_target;//将用户输入的目标传入目标值
	user_pid.Error = user_pid.Target - user_pid.Actual;//目标值 - 实际值
	user_pid.Integral += user_pid.Error;//累加误差
	user_pid.Out = (user_pid.Kp*user_pid.Error) + (user_pid.Ki*user_pid.Integral) + (user_pid.Kd*(user_pid.Error-user_pid.Last_error));//pid输出值计算
	user_pid.Last_error = user_pid.Error;//本次偏差值将成为 "Last_error"
	user_pid.Actual = user_pid.Out;//反馈值直接模拟为本次输出值
	return user_pid.Actual;//输出实际值
}

void Pid_init()
{
	printf("user_pid init...\n");
	user_pid.Kp=0.3;//比例项
	user_pid.Ki=0.07;//积分项
	user_pid.Kd=0.1;//微分项
	user_pid.Target=0;
	user_pid.Actual=0;
	user_pid.Error=0;
	user_pid.Last_error=0;
	user_pid.Integral=0;
	user_pid.Out=0;
	printf("user_pid init end.\n");
}

int main()
{
	int i=0;
	float Display;
	
	Pid_init();
	
	while(i<200)
	{
		
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f    ",Display);
		i++;
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f    ",Display);
		i++;
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f    ",Display);
		i++;
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f    ",Display);
		i++;
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f    ",Display);
		i++;
		
		Display=PID_Calculation(100.0);//调用pid算法,并输入目标值
		printf("%f\n",Display);
		i++;
		//之所以这样写是为了让每排打印多几个数
	}
	
	return 0;
}

下面是某次运行的输出结果:(需要注意的是,因为只是纯数字模拟,不是实物,不存在干扰,所以不会产生稳态误差,这些数字中间是不会出现 “…97 98 99 100 99 98 97…” 这种效果的)

user_pid init...
user_pid init end.
55.000000    9.750000    47.887501    22.374374    46.639721    32.072437
47.605526    39.545246    49.704742    45.527699    52.371738    50.495716
55.277756    54.747639    58.231724    58.472073    61.125111    61.790405
63.898846    64.782745    66.523346    67.503662    68.986443    69.991791
71.286079    72.275696    73.425964    74.377449    75.412888    76.314827
77.255203    78.102646    78.961861    79.753639    80.541916    81.279037
82.004181    82.688828    83.357086    83.992035    84.608612    85.196884
85.766212    86.310890    86.836876    87.340973    87.827065    88.293488
88.742828    89.174301    89.589722    89.988815    90.372917    90.742035
91.097198    91.438576    91.766991    92.082710    92.386398    92.678383
92.959213    93.229225    93.488930    93.738632    93.978790    94.209709
94.431808    94.645348    94.850731    95.048210    95.238129    95.420753
95.596397    95.765282    95.927704    96.083878    96.234077    96.378510
96.517410    96.650970    96.779419    96.902939    97.021713    97.135948
97.245781    97.351433    97.452995    97.550697    97.644630    97.734970
97.821838    97.905380    97.985710    98.062965    98.137253    98.208702
98.277397    98.343468    98.407005    98.468094    98.526855    98.583351
98.637688    98.689934    98.740173    98.788490    98.834953    98.879639
98.922615    98.963936    99.003670    99.041878    99.078629    99.113968
99.147949    99.180626    99.212044    99.242271    99.271332    99.299271
99.326157    99.351990    99.376854    99.400742    99.423737    99.445831
99.467094    99.487526    99.507179    99.526085    99.544250    99.561745
99.578537    99.594727    99.610252    99.625214    99.639572    99.653412
99.666687    99.679482    99.691765    99.703590    99.714958    99.725891
99.736404    99.746513    99.756233    99.765587    99.774574    99.783226
99.791534    99.799538    99.807220    99.814621    99.821724    99.828568
99.835136    99.841469    99.847542    99.853394    99.859016    99.864426
99.869621    99.874626    99.879433    99.884056    99.888504    99.892776
99.896889    99.900848    99.904648    99.908295    99.911819    99.915199
99.918457    99.921577    99.924591    99.927475    99.930260    99.932930
99.935501    99.937981    99.940353    99.942642    99.944839    99.946960
99.948997    99.950958    99.952835    99.954651    99.956375    99.958061
99.959663    99.961212    99.962700    99.964134    99.965508    99.966835
99.968109    99.969330    99.970505    99.971642    99.972717    99.973785

可以看到,刚开始计算时,系统上升速度很快,到后面增长越来越慢,这其实就是因为误差值越来越小,积分效果提升越来越小,但只要时间足够,早晚会达到目标。

下面是多次调参结果,注意图片中的 Kp、Ki、Kd 参数取值,另外,这里的值是 PID 算法的输出值,而不是被控对象的反馈值,思考的时候有些东西要反过来想。。。
比例项取值0.5,此时有较大震荡:
PID算法C语言模拟演示_第1张图片
比例项改小后,波动明显变小:
PID算法C语言模拟演示_第2张图片
微分项改小后,PID输出波动更小了:
PID算法C语言模拟演示_第3张图片
积分项取值改小后,经过200次计算,没有最终达到目标值100:
PID算法C语言模拟演示_第4张图片
积分项取值不变,但增加了计算次数(误差累加次数增加了)后,结果也基本接近了100:
PID算法C语言模拟演示_第5张图片
上图是计算次数加到300次的效果(其实就是为了增加积分项对误差的累积)。

你可能感兴趣的:(随笔)