【问题标题】:decrease algorithm time on python program calculation减少python程序计算的算法时间
【发布时间】:2020-12-06 11:13:57
【问题描述】:

我有 python 算法 计算 filters (low_pass,high_pass...) ,在我的程序中我正在从实时设备读取数据,我需要对其进行处理,并将其传输回设备。 每个数据块每 10 毫秒出现一次,所以在这个时候我必须计算尽可能多的过滤器。 我的算法

def do_calculation(self,indata,outdata):
  for i in range(0,len(indata)):
    val=self.a0*indata[i]
    val+=self.a1*self.xn1 
    val+=self.a2*self.xn2 
    val-=self.b1*self.yn1 
    val-=self.b2*self.yn2
    outdata[i]= val
    self.xn2 = self.xn1
    self.xn1 = indata[i]
    self.yn2 = self.yn1
    self.yn1 = outdata[i]

我在开始读/写之前计算的系数(a0,a1,a2,b1,b2)。

我使用从设备获得的每个输入从 Main 函数调用此函数,对其进行处理,然后使用 outdata 将其写回设备。 indata 是这样的 512 大小的列表 列表[[x0,x1][x1,x2].....[x510,x511]]

有什么方法可以提高此功能的性能?或者也许 python 对它有很大的限制。 目前,每个过滤器都需要 2 或 3(有些过滤器甚至需要 5)毫秒,我想减少它,以便在 10 毫秒的范围内创建更多过滤器。 p>

感谢您的帮助!

【问题讨论】:

  • 好吧,根据 indata 的数据类型,您可以直接对其进行迭代:for i in indata : 如果是 numpy.darray 会更快,否则如果是列表,您可以将其转换为numpy.darray 并做到这一点
  • 你能描述一下你的算法吗?代码看起来就像您只是在应用一个滑动窗口(@98​​7654323@、xn2indata[i-1:i+1]y),但在 self 上存储数据的目的尚不清楚。这会在新的indata 上重复调用吗?同一个对象可以同时处理多个indata,还是有一个明确定义的indatas 序列? self.a1self.a2self.b1self.b2do_calculation 的调用期间或之间进行更改吗?
  • 我对变量调用 val 进行了一些计算,并使用了我在每次需要保存的迭代中初始化过滤器对象(低通、高通...)时定义的一些系数上一个计算并在下一个计算中使用它。我最终的输出数据将是预期的过滤器。 (a0,a1,a2,b1,b2 )在所有计算过程中保持不变。
  • 一个简单的改进是将a0, ... 和xn1 加载到局部变量中,并且只在循环前后对self 属性进行读/写。但是,取决于您的代码当前有多慢(请在您的问题中澄清)以及它应该有多快(请在您的问题中澄清),但这还不够。根据每个 indata/outdata 切片的大小(请在您的问题中澄清)使用 numpy 进行矢量化操作可能是有益的或有害的。可能是您需要一个编译器,例如PyPy 的 JIT、Cython 的 AOT 或完全编译的语言。
  • 常量的典型值? - 他们都是花车吗?小于 1?消极的?整数?这会极大地影响时间。

标签: python algorithm performance real-time python-3.7


【解决方案1】:

下面的第三个版本do_calculation3比你的版本快一倍

class C():
    def __init__(self):
        self.a0 = .1
        self.a1 = .02
        self.a2 = -.3
        self.b1 = .2
        self.b2 = -.25
        self.xn1 = -.1
        self.xn2 = .11
        self.yn1 = .12
        self.yn2 = -.001
        self.ab = [self.a0, self.a1, self.a2, -self.b1, -self.b2]
        self.xy = [self.xn1, self.xn2, self.yn1, self.yn2]

    def do_calculation(self,indata,outdata):
      for i in range(0,len(indata)):
        val=self.a0*indata[i]
        val+=self.a1*self.xn1 
        val+=self.a2*self.xn2 
        val-=self.b1*self.yn1 
        val-=self.b2*self.yn2
        outdata[i]= val
        self.xn2 = self.xn1
        self.xn1 = indata[i]
        self.yn2 = self.yn1
        self.yn1 = outdata[i]

    def do_calculation2(self,indata,outdata):
        xy = self.xy
        ab = self.ab
        for i, ini in enumerate(indata):
            val = sum((n * m for n, m in zip(ab, [ini] + xy)))
            outdata[i] = val
            xy = [ini, xy[0], val, xy[2]]
        self.xy = xy

    def do_calculation3(self,indata,outdata):
        j,k,l,m,n = self.ab
        xn1, xn2, yn1, yn2 = self.xn1, self.xn2, self.yn1, self.yn2
        for i, ini in enumerate(indata):
            outdata[i] = val = j*ini + k*xn1 + l*xn2 + m*yn1 + n*yn2
            xn1, xn2, yn1, yn2 = ini, xn1, val, yn1
        self.xn1, self.xn2, self.yn1, self.yn2 = xn1, xn2, yn1, yn2


c = C()
dati = list((1/x if x else 0) for x in range(512))
dato = [0 for _ in dati]
c.do_calculation(dati, dato)

c2 = C()
dati2 = list((1/x if x else 0) for x in range(512))
dato2 = [0 for _ in dati2]
c2.do_calculation2(dati2, dato2)

c3 = C()
dati3 = list((1/x if x else 0) for x in range(512))
dato3 = [0 for _ in dati3]
c3.do_calculation3(dati3, dato3)

assert dato == dato2
assert dato == dato3

#%%
print('\n## do_calculation\n')
c = C()
dati = list((1/x if x else 0) for x in range(512))
dato = [0 for _ in dati]
%timeit c.do_calculation(dati, dato)

print('\n## do_calculation2\n')
c2 = C()
dati2 = list((1/x if x else 0) for x in range(512))
dato2 = [0 for _ in dati2]
%timeit c2.do_calculation2(dati2, dato2)

print('\n## do_calculation3\n')
c3 = C()
dati3 = list((1/x if x else 0) for x in range(512))
dato3 = [0 for _ in dati3]
%timeit c3.do_calculation3(dati3, dato3)

时间

## do_calculation

887 µs ± 35.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

## do_calculation2

1.49 ms ± 417 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

## do_calculation3

332 µs ± 83.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多