自抗扰控制(ADRC)—— 一阶系统
程序员文章站
2024-01-09 22:28:40
...
问题描述
使用 ADRC 控制任意一阶系统:
其中表示系统所受的总扰动,包含未知的外扰和未建模的内部动态。
这里的仿真实验中测试的总扰动为:
而且控制器不应该知道该具体形式。
????♀️
控制目标为使得输出如下形状的信号:
代码
总扰动和目标信号
def f(x,t):
return x**2 + 0.5*np.sign(np.sin(2*t)) + np.cos(x*t)
def target(t):
if t < 10:
return np.sign(np.sin(0.8*t))
elif t < 20:
return 2*(0.5*t-int(0.5*t)-0.5)
else:
return np.sin(0.8*t)
定义一个类保存时间序列,方便画图
class Logger:
def __init__(self):
self.data = {}
def add(self, key, value):
if key not in self.data:
self.data[key] = []
self.data[key].append(value)
def plot(self, keys=None):
plt.figure(figsize=(20,10))
if keys is None:
for k in self.data:
plt.plot(self.data[k], label=k)
else:
for k in keys:
plt.plot(self.data[k], label=k)
plt.legend()
plt.show()
一个常用的非线性误差函数,具有小误差大增益,大误差小增益的特性。
def fal(x, alpha=0.5, delta=0.1):
return x/np.power(delta,1-alpha) if np.abs(x)<delta else np.power(np.abs(x), alpha)*np.sign(x)
使用欧拉积分做数值积分
logger = Logger()
h = 0.01
T = 30
N = int(T/h)
r0 = 5 # r0调控过渡的快慢
# 一些初值的设定
v1 = 0
z1,z2 = 0,0
x = 0
y = x
u = 0
for i in range(N):
t = i*h
# 目标信号
v = target(t)
# 过渡过程 v1 -> v, v1的过渡比v更加平缓
v1 += h*r0*fal(v-v1, 0.5, h)
# ESO: z1 -> y, z2 = \dot{z1}
e = y - z1
fe = fal(e, 0.5, h)
z1 += h*(z2 + 100*e + u)
z2 += h*(300*fe)
# 误差反馈
# e1 = v1 - y
e1 = v1 - z1
u = 10*fal(e1,0.5,0.1) - z2
# 系统状态更新
w = f(x,t)
x += h*(w + u)
# 输出
y = x
logger.add('v1',v1)
logger.add('y',y)
logger.add('v',v)
logger.add('u',u)
logger.add('z2', z2)
logger.add('w', w)
logger.plot(['v'])
logger.plot(['v','v1','y'])
logger.plot(['w','z2','u'])
结果展示如下,v代表真实目标信号,是v的平滑过渡,y是实际输出
w 代表真实总扰动,是对总扰动的跟踪,u是控制输入
下面我来增大 ,意味着过渡信号更加逼近真实信号
过渡过程越短,意味着要在更短的时间做出同样的变化,自然就要求控制量的绝对值要增大,从上图可以看出这一点。
上一篇: 微信网页授权