首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多重scipy.lti传递函数

多重scipy.lti传递函数
EN

Stack Overflow用户
提问于 2016-02-09 23:31:49
回答 2查看 7.5K关注 0票数 13

我有以下scipy.lti对象,它基本上是一个表示LTI系统的Laplace转换的对象:

代码语言:javascript
复制
G_s = lti([1], [1, 2])

如何将这样的传递函数与另一个传递函数相乘,例如:

代码语言:javascript
复制
H_s = lti([2], [1, 2])

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

我想我可以

代码语言:javascript
复制
I_s = lti(np.polymul([1], [2]), np.polymul([1, 2], [1, 2]))

但如果我想做:

代码语言:javascript
复制
#I_s = H_s / (1 + H_s) <---- Does not work since H_s is an lti object

有什么简单的方法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-05 03:47:34

根据“轻松”的定义,您应该考虑从lti派生您自己的类,对您的传递函数实现必要的代数操作。这可能是最优雅的方法。

以下是我对这个问题的看法:

代码语言:javascript
复制
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加法、乘法、除法、减法和否定;二进制类也定义为作为伙伴的整数和浮点数。

我测试过它,关于Dietrich的例子

代码语言:javascript
复制
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很好地等于

代码语言:javascript
复制
ltimul(
array([ 2.]),
array([ 1.,  2.,  3.,  6.])
)

GH/(1+GH)的最终结果不那么漂亮:

代码语言:javascript
复制
ltimul(
array([  2.,   4.,   6.,  12.]),
array([  1.,   4.,  10.,  26.,  37.,  42.,  48.])
)

因为我对传递函数不是很熟悉,所以我不确定这给出的结果和基于渐近的解决方案有多大的可能性,因为这个方法缺少了一些简化。我感到怀疑的是,lti的行为已经出乎意料:lti([1,2],[1,2])并没有简化它的参数,尽管我怀疑这个函数是常数1,所以我不想猜测这个最终结果的正确性。

无论如何,主要的消息是继承本身,所以上面的实现中可能出现的bug只会给您带来一些小小的不便。我对类的定义也很陌生,所以我可能没有遵循上述的最佳实践。

我最终在@ochurlaud指出之后重写了上面的内容,我原来的版本只适用于Python2。原因是/操作是由__div__/__rdiv__在Python2中实现的(并且是模棱两可的“古典除法”)。然而,在Python3中,/ (真正的除法)和// (地板除法)是有区别的,他们分别称__truediv____floordiv__ (以及它们的“右”对应)。即使是在Python2上,上述代码行中的__future__导入也会触发正确的Python3行为,因此上述两种方法都适用于这两个版本。由于层(整数)除法对我们的类没有多大意义,所以我们明确表示它不能使用//做任何事情(除非其他操作数实现它)。

我们还可以轻松地分别为+=/=等定义相应的+=__idiv__等本地操作。

票数 5
EN

Stack Overflow用户

发布于 2016-03-03 20:16:10

有趣的是,Scipy似乎没有提供这种功能。另一种方法是将LTI系统转换为Sympy rational函数。Sympy允许您轻松展开和取消多项式:

代码语言:javascript
复制
from IPython.display import display
from scipy import signal
import sympy as sy

sy.init_printing()  # LaTeX like pretty printing for IPython


def lti_to_sympy(lsys, symplify=True):
    """ Convert Scipy's LTI instance to Sympy expression """
    s = sy.Symbol('s')
    G = sy.Poly(lsys.num, s) / sy.Poly(lsys.den, s)
    return sy.simplify(G) if symplify else G


def sympy_to_lti(xpr, s=sy.Symbol('s')):
    """ Convert Sympy transfer function polynomial to Scipy LTI """
    num, den = sy.simplify(xpr).as_numer_denom()  # expressions
    p_num_den = sy.poly(num, s), sy.poly(den, s)  # polynomials
    c_num_den = [sy.expand(p).all_coeffs() for p in p_num_den]  # coefficients
    l_num, l_den = [sy.lambdify((), c)() for c in c_num_den]  # convert to floats
    return signal.lti(l_num, l_den)


pG, pH, pGH, pIGH = sy.symbols("G, H, GH, IGH")  # only needed for displaying


# Sample systems:
lti_G = signal.lti([1], [1, 2])
lti_H = signal.lti([2], [1, 0, 3])

# convert to Sympy:
Gs, Hs = lti_to_sympy(lti_G), lti_to_sympy(lti_H)


print("Converted LTI expressions:")
display(sy.Eq(pG, Gs))
display(sy.Eq(pH, Hs))

print("Multiplying Systems:")
GHs = sy.simplify(Gs*Hs).expand()  # make sure polynomials are canceled and expanded
display(sy.Eq(pGH, GHs))


print("Closing the loop:")
IGHs = sy.simplify(GHs / (1+GHs)).expand()
display(sy.Eq(pIGH, IGHs))

print("Back to LTI:")
lti_IGH = sympy_to_lti(IGHs)
print(lti_IGH)

产出如下:

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35304245

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档