Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

3.6.3 连续时间线性系统

在上一节中,我们使用odeint( )对质量-弹簧-阻尼系统的微分方程组进行了数值积分,并且进行了PID控制模拟。该系统的微分方程为:。通过拉普拉斯变换可以将微分方程化为容易求解的代数方程:ms2 X(s)+bsX(s)+kX(s)=F(s)。其中F(s)是f(t)的拉普拉斯变换,X(s)是x(t)的拉普拉数变换,而n次微分变成了sn。F(s)是输入信号,而X(s)是输出信号,将等式改写为输入除以输出的形式,就得到了系统的传递函数P(s):

连续时间系统的传递函数是两个s的多项式的商。通过连续时间系统的传递函数,很容易计算某输入信号对应的输出信号。在下面的例子中,使用signal模块计算质量-弹簧-阻尼系统对阶跃信号以及正弦波信号的响应输出。❶创建lti对象,可以使用控制理论中的多种形式表示连续时间线性系统,这里使用的是传递函数分子和分母多项式的系数。多项式的系数与numpy.poly1d的约定相同,即下标为0的元素是最高次项的系数。❷调用lti.step( )方法计算系统的阶跃响应。T参数为计算响应的时间数组。❸调用signal.lsim( )计算系统对正弦波信号的响应,它的第一个参数为lti对象,也可以直接传递(numerator, denominator)。U参数为保存输入信号的数组。step( )和lsim( )计算结果中的第二项为系统的输出信号,这里忽略其余的输出。

图3-33显示阶跃响应最终稳定在x=0.05处,这时的kx=1。

图3-33 系统的阶跃响应和正弦波响应

    m, b, k = 1.0, 10, 20
    
    numerator = [1]
    denominator = [m, b, k]
    
    plant = signal.lti(numerator, denominator) ❶
    
    t = np.arange(0, 2, 0.01)
    _, x_step = plant.step(T=t) ❷
    _, x_sin, _ = signal.lsim(plant, U=np.sin(np.pi*
t), T=t) ❸

传递函数的代数运算可以表示由多个连续时间系统组成的系统,例如两个系统的级联的传递函数是各个系统的传递函数的乘积。而传递函数由分子和分母两个多项式构成,因此传递函数的四则运算可以使用NumPy的poly1d相关的函数实现。下面的SYS类通过定义__mul__、__add__、__sadd__、__div__等魔法方法,让它支持四则运算。

❶feedback( )方法计算与之对应的反馈系统的传递函数。在图3-34中,P是被控制的系统,C是控制器,C的输入信号是目标信号与实际输入的差xr -x。我们从xr到x的传递函数就是这个反馈系统的传递函数。根据图示可以列出如下拉普拉斯变换之后的代数方程:

图3-34 反馈控制系统框图

整理可得:

如果将C(s)·P(s)看作系统Y(s),那么可以得出反馈系统的传递函数为:

❷为了让SYS对象能作为step( )、lsim( )等函数的第一个表示系统的参数,需要定义__iter__( )魔法方法返回传递函数的分子与分母的多项式系数。

    from numbers import Real
    
    def as_sys(s):
    if isinstance(s, Real):
            return SYS([s], [1])
        return s
    
    class SYS(object):
        def __init__(self, num, den):
            self.num = num
            self.den = den
    
        def feedback(self): ❶
            return self / (self + 1)
    
        def __mul__(self, s):
            s = as_sys(s)
            num = np.polymul(self.num, s.num)
            den = np.polymul(self.den, s.den)
            return SYS(num, den)
    
        def __add__(self, s):
            s = as_sys(s)
            den = np.polymul(self.den, s.den)
            num = np.polyadd(np.polymul(self.num, s.den),
                             np.polymul(s.num, self.den))
            return SYS(num, den)
    
        def __sadd__(self, s):
            return self + s
    
        def __div__(self, s):
            s = as_sys(s)
            return self *
 SYS(s.den, s.num)
    
        def __iter__(self): ❷
            return iter((self.num, self.den))

下面我们用SYS类计算使用PI控制器控制质量-弹簧-阻尼系统时的阶跃响应。PI控制器的传递函数为:

注意上节中介绍的PI控制器是离散时间的,使用累加器近似计算积分器的输出,而本节采用连续时间系统的系统响应模拟控制系统。

❶质量-弹簧-阻尼系统的传递函数为plant,❷PI控制器的传递函数为pi_ctrl,为了step( )不抛出LinAlgError异常,这里将PI控制器的传递函数的分母常数项设置为一个非常小的值。❸计算反馈系统的传递函数feedback。由图3-35可以看出Ki为0时,系统的输出位移与目标位移之间存在一定的差距,Kp越大差距越小,但是会出现过冲现象。适当调节Kp与Ki可以减弱过冲现象,但是仍然会有超过目标位移的时刻。

图3-35 使用PI控制器的控制系统的阶跃响应

    M, b, k = 1.0, 10, 20
    plant = SYS([1], [M, b, k]) ❶
    
    pi_settings = [(10, 1e-10), (200, 1e-10),
                   (200, 100),  (50, 100)]
    
    fig, ax = pl.subplots(figsize=(8, 3))
    
    for pi_setting in pi_settings:
        pi_ctrl = SYS(pi_setting, [1, 1e-6]) ❷
        feedback = (pi_ctrl *
 plant).feedback( ) ❸
        _, x = signal.step(feedback, T=t)    
        label = "$K_p={:d}, K_i={:3.0f}$".format(*
pi_setting)
        ax.plot(t, x, label=label)
    
    ax.legend(loc="best", ncol=2)
    ax.set_xlabel(u"时间(秒)")
    ax.set_ylabel(u"位移(米)")

为了计算施加于质量的控制力,可以将误差信号传递给lsim( )计算控制器的输出:

    _, f, _ = signal.lsim(pi_ctrl, U=1-x, T=t)

为了彻底消除过冲现象,需要使用PID控制,PID控制器的传递函数为:

下面计算PID控制器构成的反馈系统的阶跃响应。由于PID控制器需要对输入信号进行微分,而阶跃输入信号会导致PID的输出中包含脉冲输出,即时间无限短、值无限大的信号。

    kd, kp, ki = 30, 200, 400
    pid_ctrl = SYS([kd, kp, ki], [1, 1e-6])
    feedback = (pid_ctrl *
 plant).feedback( )
    _, x2 = signal.step(feedback, T=t)

为了让PID控制器的输出在限定的范围之内,可以在反馈系统之前添加一个低通滤波器,一阶低通滤波器的传递函数为:。添加低通滤波器之后,PID控制器的输入就是连续信号了,如图3-36所示。

图3-36 带低通滤波器的反馈控制系统框图

    lp = SYS([1], [0.2, 1])
    lp_feedback = lp *
 (pid_ctrl *
 plant).feedback( )
    _, x3 = signal.step(lp_feedback, T=t)

由于PID控制器的传递函数的分子阶数高于分母阶数,因此无法使用lsim( )计算。我们可以把x_r当作系统的输入,把f当作输出,通过下面的方程计算从x_r到f的传递函数:

F(s)=(Xr (s)·LP(s)-F(s)·P(s))·C(s)

得到的传递函数为:

下面根据上面的公式计算带低通滤波器的控制系统中控制器的输出:

    pid_out = (pid_ctrl *
 lp) / (pid_ctrl *
 plant + 1)
    _, f3 = signal.step(pid_out, T=t)

图3-37显示了上述PI控制、PID控制以及带低通滤波的PID控制等系统中滑块的位移以及控制力。由于PID控制的控制力存在脉冲信号,因此无法在图中正确显示。由位移曲线可以看出低通+PID控制可以有效抑制过冲现象。

图3-37 滑块的位移以及控制力