我有以下scipy.lti对象,该对象基本上是代表LTI系统的Laplace变换的对象:

G_s = lti([1], [1, 2])

如何将这种传递函数与另一个传递函数相乘,例如:
H_s = lti([2], [1, 2])

#I_s = G_s * H_s <---- How to multiply this properly?

我想我能做
I_s = lti(np.polymul([1], [2]), np.polymul([1, 2], [1, 2]))

但是,如果我想做的话:
#I_s = H_s / (1 + H_s) <---- Does not work since H_s is an lti object

有简单的方法可以做到这一点吗?

最佳答案

根据您对“easy”的定义,应考虑从lti派生自己的类,并在传递函数上实现必要的代数运算。这可能是最优雅的方法。

这是我对此主题的看法:

from __future__ import division

from scipy.signal.ltisys import TransferFunction as TransFun
from numpy import polymul,polyadd

class ltimul(TransFun):
    def __neg__(self):
        return ltimul(-self.num,self.den)

    def __floordiv__(self,other):
        # can't make sense of integer division right now
        return NotImplemented

    def __mul__(self,other):
        if type(other) in [int, float]:
            return ltimul(self.num*other,self.den)
        elif type(other) in [TransFun, ltimul]:
            numer = polymul(self.num,other.num)
            denom = polymul(self.den,other.den)
            return ltimul(numer,denom)

    def __truediv__(self,other):
        if type(other) in [int, float]:
            return ltimul(self.num,self.den*other)
        if type(other) in [TransFun, ltimul]:
            numer = polymul(self.num,other.den)
            denom = polymul(self.den,other.num)
            return ltimul(numer,denom)

    def __rtruediv__(self,other):
        if type(other) in [int, float]:
            return ltimul(other*self.den,self.num)
        if type(other) in [TransFun, ltimul]:
            numer = polymul(self.den,other.num)
            denom = polymul(self.num,other.den)
            return ltimul(numer,denom)

    def __add__(self,other):
        if type(other) in [int, float]:
            return ltimul(polyadd(self.num,self.den*other),self.den)
        if type(other) in [TransFun, type(self)]:
            numer = polyadd(polymul(self.num,other.den),polymul(self.den,other.num))
            denom = polymul(self.den,other.den)
            return ltimul(numer,denom)

    def __sub__(self,other):
        if type(other) in [int, float]:
            return ltimul(polyadd(self.num,-self.den*other),self.den)
        if type(other) in [TransFun, type(self)]:
            numer = polyadd(polymul(self.num,other.den),-polymul(self.den,other.num))
            denom = polymul(self.den,other.den)
            return ltimul(numer,denom)

    def __rsub__(self,other):
        if type(other) in [int, float]:
            return ltimul(polyadd(-self.num,self.den*other),self.den)
        if type(other) in [TransFun, type(self)]:
            numer = polyadd(polymul(other.num,self.den),-polymul(other.den,self.num))
            denom = polymul(self.den,other.den)
            return ltimul(numer,denom)

    # sheer laziness: symmetric behaviour for commutative operators
    __rmul__ = __mul__
    __radd__ = __add__

这定义了ltimul类,即lti加上加,乘,除,减和取反;二进制的也定义为整数,并以浮点数作为伙伴。

我测试了for the example of Dietrich:
G_s = ltimul([1], [1, 2])
H_s = ltimul([2], [1, 0, 3])
print(G_s*H_s)
print(G_s*H_s/(1+G_s*H_s))

虽然GH等于
ltimul(
array([ 2.]),
array([ 1.,  2.,  3.,  6.])
)

GH/(1 + GH)的最终结果不太漂亮:
ltimul(
array([  2.,   4.,   6.,  12.]),
array([  1.,   4.,  10.,  26.,  37.,  42.,  48.])
)

由于我对传递函数不是很熟悉,因此我不确定与基于Sympy的解决方案产生相同结果的可能性有多大,原因是此函数缺少一些简化。我怀疑lti已经表现出意外的行为:即使我怀疑此函数为常数1,lti([1,2],[1,2])也不简化其参数。因此,我宁可不猜测最终结果的正确性。

无论如何,主要的信息是继承本身,因此上述实现中可能存在的错误希望仅会带来一点不便。我也不太熟悉类定义,因此我可能没有遵循上面的最佳实践。

我最终在@ochurlaud pointed out之后重写了上面的内容,因为我的原始版本仅适用于Python2。原因是/操作是由Python 2中的__div__/__rdiv__实现的(并且是模棱两可的"classical division")。但是,在Python 3中,/(真除法)和//(底除法)之间是有区别的,它们分别称为__truediv____floordiv__(以及它们的“正确”对等物)。在上面的代码行中最先导入__future__会触发正确的Python 3行为,即使在Python 2上也是如此,因此以上内容在两个Python版本上均适用。由于下层(整数)除法对于我们的类而言意义不大,因此我们明确表示它无法使用//进行任何操作(除非其他操作数实现了此操作)。

还可以轻松地分别为__iadd____idiv__等定义相应的+=/=等。

关于python - scipy.lti乘积传递函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35304245/

10-10 19:37