# 利用python进行pid仿真控制

#### 一、控制对象：二阶震荡环节

1. 控制系统框图如下

1.2 初始条件
y ( 0 ) = 0 u ( 0 ) = 0 e ( 0 ) = 0 r = 1 y(0)=0\quad u(0)=0\quad e(0)=0\quad r=1
1.3 测试结果

#### 二、python实现

##### 1. 传递函数
from numpy import *
from matplotlib.pyplot import *

class Transfer: # 传递函数类
def __init__(self,num, den): # 初始化传递函数分子和分母
self.num = array(num, dtype=float); self.den = array(den[1:], dtype=float)
# 初始化历史输入和历史输出
self.x = array([0]*len(num), dtype=float); self.y = array([0]*(len(den)-1), dtype=float)
self.overflow = False # 判断是否发散震荡
def __call__(self, x):
if not self.overflow:
self.x = roll(self.x, 1); self.x[0] = x # 历史输入串入新数据
y = self.num @ self.x - self.den @ self.y # 计算输出
self.y = roll(self.y, 1); self.y[0] = y # 历史输出串入新数据
if y > 1e3: self.overflow = True
return y
else: return nan

##### 2.PID
class PID:
def __init__(self,Kpid, pid_method=None): # 初始化PID类
# 初始化PID，历史误差
self.Kpid = array(Kpid, dtype=float); self.err = array([0]*3, dtype=float)
self.y = 0; self.overflow = False
self.q = array([Kpid[0]*(1 + Kpid[1] + Kpid[2]), -Kpid[0]*(1 + 2*Kpid[2]), Kpid[0]*Kpid[2]], dtype=float) # 计算误差系数q
self.pid_method = pid_method if pid_method != None else lambda q,err: q @ err # 选择PID方法

def __call__(self, err):
if not self.overflow:
self.err = roll(self.err, 1); self.err[0] = err # 历史误差串入新数据
self.y += self.pid_method(self.q, self.err) # 计算输出
if self.y > 1e3:
self.overflow = True
return self.y
else: return nan

##### 3.响应参数计算
def draw(y, save=None, titleName=None): # 绘制输出阶梯图
step(range(len(y)), y)
if save != None: savefig(save)
def is_stable(y): # 判断系统是否稳定
if max(abs(y)) > 1e2: return False
dy = diff(y)
return sum(dy[int(len(dy)*0.8):]<1e-3) / (len(dy) - int(len(dy)*0.8)) > 0.8
def over_shoot(y): # 计算输出超调量
return abs(max(y) -1)
dy = diff(y); dy_stable = (dy < 1e-3) & (dy > -1e-3)
idx = len(dy_stable) - 1
while dy_stable[idx]:
idx -= 1
if idx < 0: break
while abs(1 - y[idx]) < 2e-2:
idx -= 1
return idx + 1

##### 4.测试类
class Analysor: # 系统pid参数测试类
def __init__(self, num, den, r, t_len): # 初始化系统的分子和分母，给定值和仿真时间
self.num = num; self.den = den; self.r = r
self.t_len = t_len; self.record = []; self.y = None

def view(self, kpid): # 仿真给定pid时系统输出
G = Transfer(self.num, self.den); pid = PID(kpid)
self.kpid=kpid; self.q = [kpid[0]*(1 + kpid[1] + kpid[2]), -kpid[0]*(1 + 2*kpid[2]), kpid[0]*kpid[2]]
y = zeros(self.t_len); u = 0; u_out = zeros(self.t_len)
for i in range(self.t_len):
y[i] = G(u)
e = self.r - y[i]
u = pid(e); u_out[i] = u
self.y = y
return y, u_out
def sort(self): # 对系统的pid记录排序
content = ''
for each in sorted(self.record):
content += repr(each)
with open('sort.txt', 'w') as f: f.write(content)
def analyse(self, kpid, auto=True): # 对给定pid值下系统响应曲线分析超调和调整时间
y = self.view(kpid) if auto else self.y
os,ts = (over_shoot(y), idx_adjust(y)) if is_stable(y) else (nan, nan)
return (os, ts)
def pid(self):
print(f'pid:{self.kpid}, q:{self.q}')

##### 5.主程序
num, den = [0, 1, 0.5],[1, -1.5, 0.7]; pid = [0.01825, 1.3    , 3.65   ] # 系统一分子分母系数以及测试最佳pid值
r=1; y = []; t_len = 100
A = Analysor(num,den,r,t_len) # 初始化系统
y, u=A.view(pid) # 仿真最佳pid系统输出曲线，以及控制器输出曲线
draw(y)
draw(u)


• 1
点赞
• 37
收藏
觉得还不错? 一键收藏
• 打赏
• 3
评论
04-27 1142
07-21 1546
03-17 925
04-08 6296
06-14 5944
01-16
04-30
02-11 148

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

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