自抗扰控制(ADRC)—— python 实战「建议收藏」

自抗扰控制(ADRC)—— python 实战「建议收藏」本文利用跟踪微分器(TD)、扩张状态观测器(ESO)和非线性PID实现了受外扰的未知系统的控制,使得受控系统输出了期望信号。

大家好,又见面了,我是你们的朋友全栈君。

本文利用跟踪微分器(TD)+ 扩张状态观测器(ESO)+ 非线性 PID 实现了受外扰的未知系统的控制,使得受控系统输出了期望的信号。

无超调,无震颤,参数好调节,堪称完美控制器!!!

什么是自抗扰控制

自抗扰技术的提出是为了解决PID控制技术的几个缺点:

  1. 要求缓变的输出变量跟踪跳变的控制目标是不合理的;
  2. 误差的微分信号不好提取, 易受噪声影响;
  3. P、I、D的线性组合不是最优的组合方式;
  4. 误差积分I的引入带来很多副作用, 比如使得闭环变得迟钝、产生震荡等.

针对以上问题, 在自抗扰控制中分别使用以下策略来克服:

  1. 安排控制目标的“过渡过程”;
  2. 使用跟踪微分器(Tracking Differentiator, TD)提取“微分”;
  3. 寻找合适的非线性组合;
  4. 使用扩张状态观测器来估计总扰动.

以上四点中, 1和3可以视为工程上的优化策略, 而2和4的核心技术都是跟踪微分器.

跟踪微分器的功能为: 输入信号 v ( t ) v(t) v(t), 输出 n n n个信号 z 1 ( t ) , … , z n ( t ) z_1(t),\ldots,z_n(t) z1(t),,zn(t). 其中 z 1 ( t ) z_1(t) z1(t)跟踪信号 v ( t ) v(t) v(t), 而 z i ( t ) = z ˙ i − 1 ( t ) , i = 2 , 3 , … , n z_i(t)=\dot{z}_{i-1}(t), i=2,3,\ldots,n zi(t)=z˙i1(t),i=2,3,,n.

扩张状态观测器本质上也是一个跟踪微分器.

自抗扰控制中主要讨论的控制对象为受外扰的不确定对象:
x ( n ) = f ( x , x ˙ , … , x ( n − 1 ) , t ) + w ( t ) + u ( t ) x^{(n)} = f(x,\dot{x},\ldots,x^{(n-1)},t) + w(t) + u(t) x(n)=f(x,x˙,,x(n1),t)+w(t)+u(t)其中 f ( x , x ˙ , … , x ( n − 1 ) , t ) f(x,\dot{x},\ldots,x^{(n-1)},t) f(x,x˙,,x(n1),t)为未知函数, w ( t ) w(t) w(t)为未知的外扰, u ( t ) u(t) u(t)为控制量.

通常把 x , x ˙ , … , x ( n − 1 ) x,\dot{x},\ldots,x^{(n-1)} x,x˙,,x(n1)作为系统状态, 而扩张状态就是把 x ( n ) x^{(n)} x(n)也视为系统状态.

y = x ( t ) y = x(t) y=x(t)为观测量, 那么 x ˙ , … , x ( n ) \dot{x},\ldots,x^{(n)} x˙,,x(n)就是观测量的各阶导数. 利用跟踪微分器, 可以直接根据 y y y将系统的各阶导数估计出来, 即实现了扩张状态的观测.

而估计出 x ( n ) x^{(n)} x(n)等价于将系统的未知动态 f ( x , x ˙ , … , x ( n − 1 ) , t ) f(x,\dot{x},\ldots,x^{(n-1)},t) f(x,x˙,,x(n1),t)和外扰 w ( t ) w(t) w(t)的总和估计出来了.

系统的未知动态和外扰之和称为总扰动.

在控制量 u ( t ) u(t) u(t)中将系统的总扰动抵消, 配合误差反馈, 就实现了自抗扰控制.

龙格库塔

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

def dxdt(F, X, t, h=1e-2):
    assert(len(F)==len(X))
    X = np.array(X)
    K1 = np.array([f(X, t) for f in F])
    dX = h*K1/2
    K2 = np.array([f(X+dX, t+h/2) for f in F]) 
    dX = h*K2/2
    K3 = np.array([f(X+dX, t+h/2) for f in F])
    dX = h*K3 
    K4 = np.array([f(X+dX, t+h) for f in F])

    dX = (K1 + 2*K2 + 2*K3 + K4)*h/6

    return dX, np.array([f(X, t) for f in F])

辅助函数

def sat(x, delta):
    return  x/delta if np.abs(x)<delta else np.sign(x)

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)

在这里插入图片描述
fal 函数具有小误差时高增益,大误差是低增益的特性,对抑制震颤发挥了重要作用。

跟踪微分器

期望输出为方波信号 v ( t ) v(t) v(t)

# target signal
def v(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)

def v1(X, t):
    x1, x2 = X[0], X[1]
    return x2

def v2(X, t):
    x1, x2 = X[0], X[1]
    return -R*sat(x1 - v(t) + np.abs(x2)*x2/(2*R), delta)

扩张状态观测器

# eso
# 极点配置
p = np.poly1d([-15,-15,-15],True)
_, b1, b2, b3 = tuple(p.coef)

def g1(X, t):
    x1,x2,x3 = X[0], X[1], X[2]    
    return x2 - b1 * (x1 - y)  # y is model output

def g2(X, t):
    x1, x2, x3 = X[0], X[1], X[2]    
    return x3 - b2 * (x1 - y) + u

def g3(X, t):
    x1, x2, x3 = X[0], X[1], X[2]    
    return -b3 * (x1 - y)

未知真实状态

x ¨ = − x 3 − x − 0.2 x ˙ + w ( t ) + u ( t ) \ddot{x} = -x^3-x-0.2\dot{x} + w(t) + u(t) x¨=x3x0.2x˙+w(t)+u(t)
其中 w ( t ) w(t) w(t) 为外部扰动, u ( t ) u(t) u(t) 为控制输入。

# hidden uncertain model
def f1(X, t):
    x, y = X[0], X[1]    
    return y

def f2(X, t):
    x, y = X[0], X[1]
    return -x*x*x - x -0.2*y + w(t) + u

def w(t):
    return 0.2 * np.sign(np.cos(t))  # perturbation

控制仿真

R = 90  # params in sal
delta = 0.001  # params in sal
h = 0.01  # discrete time unit
T = 20  # total time
N = int(T/h)  # num of points
V = [0., 0.]  # TD signal
X = [0., 0.]  # true state
Z = [0., 0., 0.]  # ESO 
u = 0  # initial control input

actual_output = []
expect_output = []
uncertain_dynamics = []

for i in range(N):
    t = i*h  # time

    dX, _ = dxdt([f1,f2],X,t,h)
    X = X + dX
    y = X[0]  # model output

    dV, _ = dxdt([v1,v2],V,t,h)
    V = V + dV

    dZ, _ = dxdt([g1,g2,g3],Z,t,h)
    Z = Z + dZ

    e_p = V[0] - Z[0]
    e_d = V[1] - Z[1]

    fep, fed = fal(e_p), fal(e_d)

    u = 10*fep + 50*fed - Z[2]

    actual_output.append(y)
    expect_output.append(V[0])
    uncertain_dynamics.append(Z[2])


plt.plot(actual_output, color='black', label='output')
plt.plot(expect_output, color='red', linestyle='--',label='expect')
plt.plot(uncertain_dynamics, color='green', linestyle='--',label='uncertain state')
plt.legend(loc='lower right')
plt.show()

在这里插入图片描述
妈妈再也不用担心我调不好PID啦?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144673.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Ubuntu20.04安装Mysql

    Ubuntu20.04安装MysqlUbuntu20.04安装Mysql1.1下载安装MySQL1.2通过apt安装MySQL服务2.1初始化配置2.2检查mysql服务状态3.1配置远程访问3.2新建数据库和用户3.3mysql服务命令4、数据库操作命令4.1mysql服务操作4.2数据库操作4.3表操作4.4修改表结构4.5数据操作4.6数据的备份与恢复4.7卸载1.1下载安装MySQL在Ubuntu中,默认情况下,只有最新版本的MySQL包含在APT软件包存储库中,要安装它,只需更新服务器上的包索引并安装默认包apt-get

    2022年7月22日
    11
  • EnterCriticalSection 和 LeaveCriticalSection[通俗易懂]

    EnterCriticalSection 和 LeaveCriticalSection[通俗易懂]EnterCriticalSection和LeaveCriticalSection是干嘛用的?多个线程操作相同的数据(内存块)时,一般是需要按顺序访问的,否则会引导数据错乱,无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。这两个函数就是实现这种功能的。作用域:不是针对于资源的,而是针对于不同线程间的代码段的什么是临界区:临界区是一种轻量级机制,在某一时…

    2022年9月20日
    0
  • 背单词的方法

    背单词的方法

    2021年5月2日
    115
  • 【WP7进阶】——分享一个可供切换状态的ListBox组件「建议收藏」

    【WP7进阶】——分享一个可供切换状态的ListBox组件

    2022年3月8日
    50
  • CentOS7开启端口(永久)

    CentOS7开启端口(永久)redis等服务启动后,外网默认是无法访问的,因为防火墙不允许,所以要开启防火墙,让其可以访问这些端口号。方法一:使用firewall1、运行命令:firewall-cmd–get-active-zones运行完成之后,可以看到zone名称,如下:2、执行如下命令命令:firewall-cmd–zone=public–add-port=6379/tcp–per…

    2022年6月23日
    47
  • Matlab矩阵操作[通俗易懂]

    Matlab矩阵操作[通俗易懂]第一部分:矩阵基本知识矩阵是进行数据处理和运算的基本元素。在MATLAB中a、通常意义上的数量(标量)可看成是”1*1″的矩阵;b、n维矢量可看成是”n*1″的矩阵;c、多项式可由它的系数矩阵完全确定。一、矩阵的创建在MATLAB中创建矩阵有以下规则:a、矩阵元素必须在”[]”内;b、矩阵的同行元素之间用空格(或”,”)隔开;c、矩阵的行与行之间用”;”(或回车符)隔开;d、矩阵的元素可以是数值、变量、表达式或函数;e、矩阵的尺寸不必预先定义。下面介绍四种矩阵的创建方法:

    2022年6月25日
    28

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号