【LADRC】对自抗扰算法的理解及公式推导(附代码)

前言

        在学习和研究自抗扰控制(LADRC)算法的过程中,我积累了一些自己的理解和心得。为了更好地整理这些知识,同时也希望与有共同兴趣的朋友们进行交流和探讨,故撰写此文章。文章中的内容基于我的个人学习经验,难免会存在理解上的偏差或错误。第一次撰写博客,非常欢迎大家批评指正,共同进步!

1、从PID控制器开始

        对于串联积分型,我们可以很容易的使用P和PD控制器完成无稳态误差、无超调量到控制。

一阶系统:G_{(s)}=\frac{k_{p}}{s+k_{p}}

二阶系统:G_{(s)}=\frac{k_{p}}{s^{2}+k_{d}s+k_{p}}

        当系统不再是积分串联型的时候,如对于一个系统为:

\ddot{y}=-\alpha \dot{y}+\beta y+b u+d

式中d为未知的外部扰动。

        对于传统的PID控制,则引入一个积分器“I”

\ddot{y}=-\alpha \dot{y}+\beta y+b (k_{p}(y_{r}-y)+k_{d}\dot{y}+k_{i}\int (y_{r}-y)dt)+d

        传递函数G_{(s)}=\frac{b k_{p}s+b k_{i}}{s^{3}+(b k_{d}+\alpha )s^{2}+(b k_{p}+\beta )s+b k_{i}}。PID的参数可由极点配置法进行参数整定,当\alpha\betab发生改变后,系统的特性也会发生改变,导致在含扰动的非积分串联型系统中PID控制器的鲁棒性下降。

2、 线性自抗扰控制(LADRC)

        LADRC优势在于其不依赖于系统的精确数学模型,其思想为通过线性扩张状态观测器(LESO)来实时估计和补偿系统中的扰动和不确定性,将系统转变为一个串联积分型后进行控制,而LADRC相比于ADRC,引入了带宽的概念,减少了要调整的参数数量和调整难度。

同样针对上述系统:

\left\{\begin{matrix} \ddot{y}=-\alpha \dot{y}+\beta y+bu+d \\x_{1}=y \\x_{2}=\dot{y} \end{matrix}\right.

其状态空间为:

\begin{bmatrix} \dot{x_{1}} \\\dot{x_{2}} \end{bmatrix}=\begin{bmatrix} 0 & 1\\ \beta & -\alpha \end{bmatrix}\begin{bmatrix} x_{1}\\ x_{2} \end{bmatrix}+ \begin{bmatrix} 0\\b \end{bmatrix}u+ \begin{bmatrix} 0\\1 \end{bmatrix}d

y=\begin{bmatrix} 1 & 0 \end{bmatrix}\begin{bmatrix} x_{1}\\ x_{2} \end{bmatrix}

控制器设计为:

u=-\begin{bmatrix} K_{1} & K_{2} \end{bmatrix}\begin{bmatrix} x_{1}\\ x_{2} \end{bmatrix}+F_{r}

Fr为前馈项。当x1,x2不可测的时候,我们使用状态观测器来估计x1,x2的状态,则控制器变为:

u=-\begin{bmatrix} K_{1} & K_{2} \end{bmatrix}\begin{bmatrix} \widehat{x_{1}}\\ \widehat{x_{2}} \end{bmatrix}+F_{r}

引入的闭环观测器--Luenberger观测器公式如下:

\dot{\widehat{x}}=A\widehat{x}+Bu+\begin{bmatrix} L_{1}\\ L_{2} \end{bmatrix}(y-\widehat{y})

2.1无对象模型的线性扩张状态观测器(LESO)的设计

        有了以上准备,我们把LADRC的扩张状态观测器(LESO)写作:

\left\{\begin{matrix} \ddot{y}=-\alpha \dot{y}+\beta y+b_o u+d \\x_{1}=y \\x_{2}=\dot{y} \\\ x_{3}=f\end{matrix}\right.

LESO中的x3即为“扩张”出来的状态。

        式子中的f为总扰动,这个总扰动不仅包括了系统受到的外部扰动,还有系统数学模型不准确所带来的内部扰动。所以在上述式子中的\dot{x_{2}}=\ddot{y}=f+bu,我们可以将系统中除去输出的部分全部视作总扰动f=-\alpha \dot{y}+\beta y+d

则包含了扩张状态的状态空间方程为:

\begin{bmatrix} \dot{x_{1}}\\ \dot{x_{2}} \\ \dot{x_{3}} \end{bmatrix}=\begin{bmatrix} 0 & 1 &0 \\ 0& 0 & 1\\ 0&0 &0 \end{bmatrix}\begin{bmatrix} x_{1}\\ x_{2} \\ x_{3} \end{bmatrix}+\begin{bmatrix} 0\\b_o \\ 0 \end{bmatrix}u

y=\begin{bmatrix} 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} x_{1}\\ x_{2} \\ x_{3} \end{bmatrix}

根据Luenberger观测器的形式:

\left\{\begin{matrix} \dot{\widehat{x}}=A\widehat{x}+Bu+L(y-\widehat{y})\\ \widehat{y}=C\widehat{x} \end{matrix}\right.

式中A=\begin{bmatrix} 0 & 1 &0 \\ 0& 0 & 1\\ 0&0 &0 \end{bmatrix}B=\begin{bmatrix} 0\\b_o \\ 0 \end{bmatrix}​​​​​​,​C=\begin{bmatrix} 1 &0 &0 \end{bmatrix}L=\begin{bmatrix} l_1\\ l_2 \\l_3 \end{bmatrix}推导得出:

\dot{\widehat{x}}=A\widehat{x}+Bu+L(y-\widehat{y})

        =(A-LC)\widehat{x}+Bu+Ly

                =\begin{bmatrix} l_{1} & 1 &0 \\ l_{2}& 0 &1 \\ l_{3}& 0&0 \end{bmatrix}\widehat{x}+\begin{bmatrix} 0 &l_{1} \\ b_o&l_{2} \\ 0& l_{3} \end{bmatrix}\begin{bmatrix} u\\y \end{bmatrix}

选择状态矩阵\overline{A}=\begin{bmatrix} l_{1} & 1 &0 \\ l_{2}& 0 &1 \\ l_{3}& 0&0 \end{bmatrix}进行特征根的计算,特征多项式:

SI-\overline{A}=\begin{bmatrix} s & 0 &0 \\ 0&s & 0\\ 0& 0&s \end{bmatrix}-\begin{bmatrix} l_{1} & 1 &0 \\ l_{2}& 0 &1 \\ l_{3}& 0&0 \end{bmatrix}

      =s^3+l_1s^2+l_2s+l_3

        选择观测器极点在左半平面内,为了方便调节,将极点选在-\omega _o上。-\omega _o称作观测器的带宽(特征根)。

s^3+l_1s^2+l_2s+l_3=[S-(-\omega _o)]^3

                                                         =s^3+3\omega _os^2+3\omega _o^2s+\omega _o^3

\therefore l_1=3\omega _o ,l_2=3\omega _o^2,l_3=\omega _o^3

        这样就可以做到只需要调整\omega _o就能够对观测器进行调节。

2.2状态误差反馈控制律的设计

        当设计的状态观测器能够较准确的估计出总扰动,即\widehat{x_3}=\widehat{f}\approx f。我们就令u=\frac{u_o-\widehat{f}}{b_o},则\ddot{y}=f+bu=f+b\frac{u_o-\widehat{f}}{b_o}=u_o,我们发现当把与输出u无关的参数全部包含到总扰动f中后,经过LESO的估计就能将其全部抵消。这样系统将转变为一个串联积分型,就可以采用最开始的PD控制器进行准确地控制。

u_o=K_p(r-\widehat{x_1})+K_d(\dot{r}-\widehat{x_2})+\ddot{r}

        式中r为目标值,\ddot{r}为前馈项,旨在提高系统对参考输入的跟踪性能。若不是阶跃输入信号(导数不为0),则PD控制器会产生稳态误差,加入前馈项就能减小稳态误差。绝大部分情况下可忽略此项。

        接下来对\ddot{y}=u_o=K_p(r-\widehat{x_1})+K_d(\dot{r}-\widehat{x_2})+\ddot{r}进行拉普拉斯变换得到:

        s^2Y=K_p\cdot E+K_d\cdot s\cdot E

        开环传递函数\frac{Y}{E}=\frac{K_p+Kd\cdot s}{s^{2}},则闭环传递函数为:

G_{(s)}=\frac{\frac{Y}{E}}{1+\frac{Y}{E}}=\frac{K_p+K_d\cdot s}{s^2+K_d\cdot s+K_p}

        对控制器进行极点配置,选取-\omega _c作为控制器带宽(极点):

s^2+K_d\cdot s+K_p=[s-(-\omega _o)]^2

                                     =s^2+2\omega _cs+\omega _c^2

\therefore K_p=\omega _c^2,K_d=2\omega _c

       这样就可以做到仅仅调整\omega _c,就能够对整个控制器进行调节。

         对于一个标准的二阶闭环传递函数G_{(s)}=\frac{\omega _n^2}{s^2+2\xi \omega _ns+\omega _n},上述的控制器闭环传函相当于\xi =1的情况(临界阻尼比),根据阻尼比与超调量之间的关系,此时控制器的超调量为0。这也就是LADRC算法没有超调量的原因。

2.3关于bo

        bo是输出补偿b的猜测值,我们可以根据所建立的关于系统的数学模型中输出u前的项来进行计算猜测,使其尽可能的解近实际的b。而猜测的bo与实际的b之间的偏差将会被加入到总扰动f中进行估计,所以更加准确的bo能够减小观测器的估计压力。

\ddot{y}=-\alpha \dot{y}+\beta y+\Delta u+d+b_o u

        式中f=-\alpha \dot{y}+\beta y+\Delta u+d\Delta u=bu-b_ou

2.4部分模型已知的线性扩张状态观测器(LESO)的设计

        对于一些系统来说,我们可以使用一些方法得到系统的部分模型,当我们把这些模型加入进LESO中后,能够有效的降低LESO的观测压力,在相同(甚至更低)的观测器带宽条件下获得更好的估计性能。若观测器的带宽过大,可能会导致观测器对实际的估计过于敏感,从而更易受到噪声影响。

        带入已知的模型,将上述式子写作

\ddot{y}=-a_1 \dot{y}-a_0 y+\Delta u+d+b_o u=-a_1 \dot{y}-a_0 y+{f}'+b_o u

其中,a0,a1已知,bo部分已知。{f}'=\Delta u+d为实际未知的扰动,仍然将总扰动记为f=a_1 \dot{y}+a_0 y+\Delta u+d

将含有扩张状态的状态空间方程写作:

\left\{\begin{matrix} \dot{x}=Ax+Bu+E{\dot{f}}'\\ y=Cx \end{matrix}\right.

此时,式子中各矩阵变为

A=\begin{bmatrix} 0 & 1 &0 \\ 0& 0 & 1\\ 0&-a_0 &-a_1 \end{bmatrix}B=\begin{bmatrix} 0\\b_o \\ -a_1b_o \end{bmatrix}​​​​​​,​​C=\begin{bmatrix} 1 &0 &0 \end{bmatrix}E=\begin{bmatrix} 0\\0 \\ 1 \end{bmatrix}

观测器为:

\left\{\begin{matrix} \dot{\widehat{x}}=(A-LC)\widehat{x}+Bu+Ly+E{\dot{f}}'\\ \widehat{y}=C\widehat{x}\end{matrix}\right.

使用与上面相同的方法进行特征根的计算,

SI-\overline{A} = \begin{bmatrix} S & 0 & 0 \\ 0 & S & 0 \\ 0 & 0 & S \end{bmatrix} - \begin{bmatrix} l_1 & 1 & 0 \\ l_2 & 0 & 1 \\ l_3 & -a_0 & -a_1 \end{bmatrix}

                                         =S^3 + l_1 S^2 - a_1 S^2 - a_1 l_1 S - a_0 S + l_2 S - a_0 l_1 - a_1 l_2 + l_3

将观测器极点选择在左半平面,为了方便调节,选择在-\omega _o

S^3 + l_1 S^2 - a_1 S^2 - a_1 l_1 S - a_0 S + l_2 S - a_0 l_1 - a_1 l_2 + l_3 = [S - (-\omega_o)]^3

=S^3 + (3\omega_o - a_1)S^2 + (3\omega_o^2 - a_1 \omega_o - a_0 + a_1^2)S + \omega_o^3 - 3a_1 \omega_o^2 + 3(a_1^2 - a_0) \omega_o + 2a_0 a_1 - a_1^3

可以得到:

l_1 = 3\omega_o - a_1 \\

l_2 = 3\omega_o^2 - a_1 \omega_o - a_0 + a_1^2

l_3 = \omega_o^3 - 3a_1 \omega_o^2 + 3(a_1^2 - a_0) \omega_o + 2a_0 a_1 - a_1^3

因为式子中除\omega _o为未知量,其余都为模型的已知参数,所以同样只需要调整\omega _o就能够对观测器进行调节。

3、LADRC参考代码

3.1无对象模型LADRC算法的Python实现

class LADRC:
    
    def __init__(self, ProcessOrder, Compensate, BandwidControlador, BandwidLESO, condicionInit,imprimirMat=1):

        self.u = 0
        self.h = 0.00001 
        self.nx = int(ProcessOrder)
        self.wc = BandwidControlador
        self.wo = BandwidLESO
        self.bo = Compensate
        self.zo = condicionInit
        self.Cg, self.Ac, self.Bc, self.Cc, self.Ee, self.zo, self.L,self.K,self.z = self.Parameter_Init(imprimirMat)


    def Parameter_Init(self, imprimirMat=1):
        
        n = self.nx + 1

        K = np.zeros([1, self.nx])
        for i in range(self.nx):
            K[0, i] = math.pow(self.wc, n - (i + 1)) * (
                    (math.factorial(self.nx)) / (math.factorial((i + 1) - 1) * math.factorial(n - (i + 1)))) #控制器带宽

        L = np.zeros([n, 1])
        for i in range(n):
            L[i] = math.pow(self.wo, i + 1) * (
                        (math.factorial(n)) / (math.factorial(i + 1) * math.factorial(n - (i + 1)))) #观测器带宽

        Cg = 1 / self.bo

        Ac = np.vstack((np.hstack((np.zeros([n - 1, 1]), np.identity(n - 1))), np.zeros([1, n])))
        Bc = np.vstack((np.zeros([self.nx - 1, 1]), self.bo, 0))
        Cc = np.hstack(([[1]], np.zeros([1, n - 1])))
        Ee = np.vstack((np.zeros((2, 1)), 1))
        zo = np.vstack(([[self.zo]], np.zeros([n - 1, 1])))
        z = np.zeros([n, 1])

        if imprimirMat == 1:
            print(f"K =\n {K}\n")
            print(f"L =\n {L}\n")
            print(f"Ac =\n {Ac}\n")
            print(f"Bc =\n {Bc}\n")
            print(f"Cc =\n {Cc}\n")
            print(f"Ee =\n {Ee}\n")
            print(f"z =\n {z}\n")
            print(f"zo =\n {zo}\n")

        return Cg, Ac, Bc, Cc, Ee, zo, L, K, z

    def LESO(self, u, y, z):
        
        return np.matmul(self.Ac, z) + self.Bc * u + self.L * (y - np.matmul(self.Cc, z))

    def Runkut4(self, F, z, h):
        
        k0 = h * F(z)
        k1 = h * F(z + 0.5 * k0)
        k2 = h * F(z + 0.5 * k1)
        k3 = h * F(z + k2)

        return z + (1 / 6) * (k0 + 2 * k1 + 2 * k2 + k3)

    def LADRC_Control(self, r, y):

        leso = partial(self.LESO, self.u, y) 
        self.z = self.Runkut4(leso, self.z, self.h) 

        u0 = self.K[0, 0] * (r - self.z[0, 0])  

        for i in range(self.nx - 1):
            u0 -= self.K[0, i + 1] * self.z[i + 1, 0] 

        self.u = (u0 - self.z[self.nx, 0]) * self.Cg

        return {'output':u0,'Z0':self.z[0,0],'Z1':self.z[1,0],'Z2':self.z[2,0]}

3.2部分模型已知LADRC算法的Python实现

class LADRC:

    def __init__(self, ProcessOrder, Compensate, BandwidControlador, BandwidLESO, condicionInit, ModelDisturbance, Disturbance0, Disturbance1,
                 imprimirMat=1):

        self.u = 0
        self.h = 0.00001 
        self.nx = int(ProcessOrder)
        self.wc = BandwidControlador
        self.wo = BandwidLESO
        self.bo = Compensate
        self.fh = ModelDisturbance
        self.zo = condicionInit
        self.a0 = Disturbance0
        self.a1 = Disturbance1
        self.Cg, self.Ac, self.Bc, self.Cc, self.Ee, self.zo, self.L, self.K, self.z = self.Parameter_Init(imprimirMat)

    def Parameter_Init(self, imprimirMat=1):
        
        n = self.nx + 1
        a0 = self.a0
        a1 = self.a1

        K = np.zeros([1, self.nx])
        for i in range(self.nx):
            K[0, i] = math.pow(self.wc, n - (i + 1)) * (
                    (math.factorial(self.nx)) / (math.factorial((i + 1) - 1) * math.factorial(n - (i + 1)))) #控制器带宽

        L = np.zeros([n, 1])
        for i in range(n):
            L[i] = math.pow(self.wo, i + 1) * (
                        (math.factorial(n)) / (math.factorial(i + 1) * math.factorial(n - (i + 1)))) #观测器带宽

        L[0] = L[0] - a1
        L[1] = L[1] - a1 * self.wo - a0 + a1 * a1
        L[2] = L[2] - 3 * a1 * self.wo * self.wo + 3  * self.wo * (a1 * a1 - a0) + 2 * a0 * a1 - math.pow(a1 , 3)  

        Cg = 1 / self.bo
        a0array = np.array([[a0]]) 
        a1array = np.array([[a1]]) 
        Ac = np.vstack((np.hstack((np.zeros([n - 1, 1]), np.identity(n - 1))), np.hstack((np.zeros((1, 1)), -a0array , -a1array))))
        Bc = np.vstack((np.zeros([self.nx - 1, 1]), self.bo, -a1array*self.bo))
        Cc = np.hstack(([[1]], np.zeros([1, n - 1])))
        Ee = np.vstack((np.zeros((2, 1)), 1 ))
        zo = np.vstack(([[self.zo]], np.zeros([n - 1, 1])))
        z = np.zeros([n, 1])

        if imprimirMat == 1:
            print(f"K =\n {K}\n")
            print(f"L =\n {L}\n")
            print(f"Ac =\n {Ac}\n")
            print(f"Bc =\n {Bc}\n")
            print(f"Cc =\n {Cc}\n")
            print(f"Ee =\n {Ee}\n")
            print(f"z =\n {z}\n")
            print(f"zo =\n {zo}\n")

        return Cg, Ac, Bc, Cc, Ee, zo, L, K, z

    def LESO(self, u, y, z):
        
        return np.matmul(self.Ac, z) + self.Bc * u + self.L * (y - np.matmul(self.Cc, z)) + self.Ee * self.fh

    def Runkut4(self, F, z, h):
        
        k0 = h * F(z)
        k1 = h * F(z + 0.5 * k0)
        k2 = h * F(z + 0.5 * k1)
        k3 = h * F(z + k2)

        return z + (1 / 6) * (k0 + 2 * k1 + 2 * k2 + k3)

    def LADRC_Control(self, r, y):

        leso = partial(self.LESO, self.u, y)  
        self.z = self.Runkut4(leso, self.z, self.h) 

        u0 = self.K[0, 0] * (r - self.z[0, 0])  

        for i in range(self.nx - 1):
            u0 -= self.K[0, i + 1] * self.z[i + 1, 0] 

        self.u = (u0 - self.z[self.nx, 0]) * self.Cg

        return {'output':u0,'Z0':self.z[0,0],'Z1':self.z[1,0],'Z2':self.z[2,0]}
### 关于LADRC在Simulink中离散化实现 #### LADRC简介 线性自抗扰控制器(Linear Active Disturbance Rejection Controller, LADRC)是一种先进的控制策略,能够有效处理不确定性和外部干扰的影响。这种控制器通过实时估计并补偿系统的总扰动来提高性能。 #### 离散化的必要性 为了使连续时间域内的LADRC适用于计算机控制系统,在实际工程应用中通常需要将其转换成离散形式。这不仅涉及到算法本身的离散化过程,还包括采样周期的选择以及数值积分方法的应用等问题[^1]。 #### MATLAB与Simulink中的离散化实现 对于希望利用MATLAB/Simulink平台来进行研究或教学目的的研究人员来说,可以参考开源项目提供的资源。这些资源提供了基于高志强教授提出的理论框架构建的具体实例,并且已经完成了从连续到离散模型的转变工作。用户可以直接下载相应的m文件和slx文件作为起点,进一步调整参数设置以满足特定需求[^2]。 具体而言,在Simulink环境中创建离散版本的LADRC主要包括以下几个方面的工作: - **定义状态变量更新方程**:根据所选的数值积分方案(如欧拉法、梯形法则等),编写用于描述系统内部状态随时间变化规律的状态空间表达式; - **配置采样时间和延迟环节**:合理设定每一步计算之间的时间间隔大小;如果存在传输滞后现象,则还需加入额外的一阶低通滤波器或其他类型的延时模块; - **设计观测器增益矩阵**:依据期望达到的跟踪精度指标选取合适的极点位置,进而求解得到扩展状态观测器ESO所需的反馈系数向量; - **连接输入输出端口**:确保整个闭环结构内各个组成部分之间的信号传递路径畅通无阻,特别是要注意区分受控对象本身及其加部分各自的接口特性差异。 ```matlab % 定义离散时间步长 dt 和其他必要的常数 dt = 0.01; % 假设采用固定步长为0.01秒 alpha = ... ; beta = ... ; % 初始化状态向量 x(k) 和误差 e(k) x_k = zeros(nx, 1); e_k = r - y; while t <= T_final % 计算新的控制作用 u(k),这里省略了具体的公式推导细节 u_k = ... % 更新被控对象的状态 x(k+1)=f(x(k),u(k)) x_next = A * x_k + B * u_k; % 将当前时刻的结果存储起来以便后续分析绘图 save_results(t,x_k,u_k); % 准备进入下一个迭代循环前做一些准备工作... x_k = x_next; k = k + 1; end ``` 上述代码片段展示了如何在一个简单的for/while循环里逐步推进仿真进程,其中涉及到了基本的状态预测、测量校正流程。当然,完整的程序还需要考虑更多边界条件判断逻辑等内容才能真正运行起来[^3]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值