【学习草稿】pid控制基础实现--往水桶注水

pid

1)非常通俗易懂的PID控制(1)https://zhuanlan.zhihu.com/p/37515841
球场上运动至指定地点(比例控制):有图【很直观的帮助理解】&有文字分析
2)初识PID-搞懂PID概念 https://zhuanlan.zhihu.com/p/74131690
【重点】数据有错误,但是跟着分析模拟了用p、pi、pid调控往水桶加水的过程
3)PID控制算法原理(抛弃公式,从本质上真正理解PID控制) https://zhuanlan.zhihu.com/p/39573490
看2)的时候 有时会看看3)帮助理解
在这里插入图片描述
在这里插入图片描述
其中r(t)表示给定输入值,c(t)表示实际输出值,e(t)表示信号偏差量=r(t)-c(t),u(t)表示修正量。 ------- https://www.cnblogs.com/cv-pr/p/4785195.html PID控制原理和算法。
PID调节器是一种线性调节器,它将给定值r(t)与实际输出值c(t)的偏差e(t)的比例§、积分(I)、微分(D)通过线性组合构成控制量u(t),对控制对象进行控制。
在这里插入图片描述

代码实现与绘图:python3+matplotlib

import matplotlib.pyplot as plt
print(list(range(1,5))) # python3
# 参考  https://zhuanlan.zhihu.com/p/74131690
# (1)有个水桶,需要时刻保持1m 的高度,目前水桶里有0.2m 的水
# 采用P(比例) 的方法加水:即每次测量与1m 的误差,并加入与误差成比例的水量
# 比如设Kp=0.5.
# 第一次,误差是 1-0.2=0.8m,那么加入水量是 Kp*0.8= 0.4m

target = 1
now = 0.2
kp = 0.5

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
while add_num < 30:
    error = target-now
    error_list.append(error)
    uk = kp*error # 基于误差输出
    add_num += 1 
    uk_list.append(uk)
    now = now + uk
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 0.5")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()
    
print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

# (2) 新任务: 有个水桶,但桶底漏了个洞,仍需保持1m 的高度,
# 目前水桶里有0.2m 的水,但每次加水都会流出0.1m.
# 这个例子就接近我们实际工程的例子了,比如电机摩擦的阻力,损耗.
# 【】第一次仍是使用P (比例控制) u= Kp* e
target = 1
now = 0.2
kp = 0.5#1.9 #1 # 0.5

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
while add_num < 60:
    error = target-now
    error_list.append(error)
    uk = kp*error # 基于误差输出
    add_num += 1 
    uk_list.append(uk)
    now = now + uk - 0.1
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 0.5")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()
    
print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

# (2) 新任务: 有个水桶,但桶底漏了个洞,仍需保持1m 的高度,
# 目前水桶里有0.2m 的水,但每次加水都会流出0.1m.
# 这个例子就接近我们实际工程的例子了,比如电机摩擦的阻力,损耗.
# 【】第一次仍是使用P (比例控制) u= Kp* e
target = 1
now = 0.2
kp = 1 #1.9 #1 # 0.5

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
while add_num < 60:
    error = target-now
    error_list.append(error)
    uk = kp*error # 基于误差输出
    add_num += 1 
    uk_list.append(uk)
    now = now + uk - 0.1
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 1")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()
    
print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

# (2) 新任务: 有个水桶,但桶底漏了个洞,仍需保持1m 的高度,
# 目前水桶里有0.2m 的水,但每次加水都会流出0.1m.
# 这个例子就接近我们实际工程的例子了,比如电机摩擦的阻力,损耗.
# 【】第一次仍是使用P (比例控制) u= Kp* e
target = 1
now = 0.2
kp = 1.9 #1.9 #1 # 0.5

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
while add_num < 60:
    error = target-now
    error_list.append(error)
    uk = kp*error # 基于误差输出
    add_num += 1 
    uk_list.append(uk)
    now = now + uk - 0.1
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 1.9")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()
    
print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

# 结论: 比例控制引入了稳态误差,且无法消除.
#       比例常数增大可以减小稳态误差,但如果太大则引起系统震荡,不稳定.
# 为了消除稳态误差,第二次加入积分,使用PI(比例积分控制) 
# 积分控制就是将历史误差全部加起来乘以积分常数.

target = 1
now = 0.2
kp = 0.5
ki = 0.5

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
history_error_list = [0]
ukp_list = [0]
uki_list = [0]
while add_num < 30:
    error = target-now
    error_list.append(error)
    ukp = kp*error # 比例部分
    ukp_list.append(ukp)
    history_error=sum(error_list)
    history_error_list.append(history_error)
    uki = ki*history_error #积分部分
    uki_list.append(uki)
    add_num += 1
    uk = ukp + uki #基于误差输出
    uk_list.append(uk)
    now = now + uk - 0.1
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 0.5, ki = 0.5")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()    

print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("ukp_list={}, len(ukp_list)={}".format(ukp_list, len(ukp_list)))
print("uki_list={}, len(uki_list)={}".format(uki_list, len(uki_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

# 引入积分可以消除稳态误差,但会增加超调,且Ki 增大,超调量也增大.
# 为了消除超调,我们引入微分作用

target = 1
now = 0.2
kp = 0.5
ki = 0.5
kd = 0.3

error_list = [0]
uk_list = [0]
now_list = [0.2]
add_num = 0
history_error_list = [0]
ukp_list = [0]
uki_list = [0]
ukd_list = [0]
while add_num < 30:
    error = target-now
    error_list.append(error)
    ukp = kp*error # 比例部分
    ukp_list.append(ukp)
    history_error=sum(error_list)
    history_error_list.append(history_error)
    uki = ki*history_error #积分部分
    uki_list.append(uki)
    if add_num==0:
        diff_error=0
    else:
        diff_error=error_list[-1]-error_list[-2]
    ukd = kd*diff_error # 微分部分
    ukd_list.append(ukd)
    add_num += 1
    uk = ukp + uki + ukd #基于误差输出
    uk_list.append(uk)
    now = now + uk - 0.1
    now_list.append(now)

x=list(range(len(now_list)))
y=now_list
# 绘制折线图
plt.plot(x, y, label='Data Line')
# 绘制纵坐标线
plt.axhline(y=1, color='gray', linestyle='--')
# 绘制数据标记
for i in range(len(x)):
    # 绘制散点图
    plt.scatter(x[i], y[i], s=10, marker='o', color='red')
    # 用于标注文字,注释文本内容+被注释的坐标点+。。。
    # plt.annotate((x[i], y[i]), (x[i] + 0.1, y[i] - 0.051))
# 设置图表标题和标签
plt.title("kp = 0.5, ki = 0.5, kd = 0.3 ")
plt.xlabel("Adjustment times")
plt.ylabel("water level/m")
# 显示图表,得到一个带数据标记的折线图
plt.legend()
plt.show()       
    
print("error_list={}, len(error_list)={}".format(error_list, len(error_list)))
print("ukp_list={}, len(ukp_list)={}".format(ukp_list, len(ukp_list)))
print("uki_list={}, len(uki_list)={}".format(uki_list, len(uki_list)))
print("ukd_list={}, len(ukd_list)={}".format(ukd_list, len(ukd_list)))
print("uk_list={}, len(uk_list)={}".format(uk_list, len(uk_list)))
print("now_list={}, len(now_list)={}".format(now_list, len(now_list)))

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值