Performance 如何在Python中高效地从串行端口读取、编码和存储数据?

Performance 如何在Python中高效地从串行端口读取、编码和存储数据?,performance,python-3.x,serialization,matplotlib,serial-port,Performance,Python 3.x,Serialization,Matplotlib,Serial Port,该程序的目的是:从串行端口读取串行数据,将其转换为int并将其存储到列表中。稍后将使用matplotlib实时处理和打印这些数据 问题是: 创建列表的时间太长(可能需要几秒钟) 分钟)。 ps:列表的大小为n=1024 在花了那么多时间创建列表后,我得到了以下信息: “(…) 文件“C:\Users\ianmc\AppData\Local\Programs\Python\Python35-32\lib\site packages\matplotlib\lines.py”,第645行,在recac

该程序的目的是:从串行端口读取串行数据,将其转换为int并将其存储到列表中。稍后将使用matplotlib实时处理和打印这些数据

问题是:

  • 创建列表的时间太长(可能需要几秒钟) 分钟)。
    ps:列表的大小为n=1024
  • 在花了那么多时间创建列表后,我得到了以下信息:
    “(…)
    文件“C:\Users\ianmc\AppData\Local\Programs\Python\Python35-32\lib\site packages\matplotlib\lines.py”,第645行,在recache中
    raise RUNTIMERROR('xdata和ydata的长度必须相同')
    运行时错误:扩展数据和ydata的长度必须相同“

    可能情节争论的长度不同,但为什么呢

  • 守则:

    import serial
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    
    dt = 0.01
    Fs = 44000.0                     # sample rate
    timestep = 1.0/Fs                # sample spacing (1/sample rate)
    n = 1024                         # size of the array data (BUFFER SIZE)
    t = np.arange(0, (n/100), dt)    # t range
    w = 10000                        # frequency of the input
    
    #initialize data list
    data = [0] * n
    
    #initialize magnitude list
    magnitude = [0] * (n//2)
    
    # open and prepare serial port
    ser = serial.Serial('COM4', 9600, timeout=8,
                        parity=serial.PARITY_EVEN, rtscts=1)
    
    
    # calculates the fft dB
    def createMagnitudeDB(magnitude):
        magnitudeDB = 20 * (math.log(magnitude,10))
        return magnitudeDB
    
    def update(data):
        # update the curves with the incoming data
        timeCurve.set_ydata(data[0])
        freqCurve.set_ydata(data[1])
        return timeCurve, freqCurve,
    
    def generateData():
        # simulate new data coming in
        while True:
    
            # THE EFFICIENCY PROBLEM IS IN THIS FOR
            # Read data from arduino
            for i in range(n):     #while you are taking data
                PreData = ser.readline()
                data.append(int(PreData))
    
    
            # fft computing and normalization
            magnitude = np.fft.fft(data)/n
            magnitude = np.abs(magnitude[range(n//2)])
    
            # calculates the fft dB
            magnitude_dB = [createMagnitudeDB(x) for x in magnitude]
    
            yield (data, magnitude)
    
    
    fig = plt.figure()
    
    # create time graph axis
    timeGraph = plt.subplot(2, 1, 1)
    timeGraph.set_ylim(-200, 200)
    timeGraph.set_xlim([0, n])
    timeGraph.set_xlabel('Time')
    timeGraph.set_ylabel('Amplitude')
    
    # create frequency graph axis
    freqGraph = plt.subplot(2, 1, 2)
    freqGraph.set_ylim([0, 70])
    freqGraph.set_xlim([0, (Fs/2)])
    freqGraph.set_xlabel('Freq (Hz)')
    freqGraph.set_ylabel('Magnitude')
    
    
    #get frequency range
    k = np.arange(n)
    T = n/Fs
    freq = k/T               # two sides frequency range
    freq = freq[range(n//2)] # one side frequency range
    
    # plot the curves
    timeCurve, = timeGraph.plot(np.linspace(0, 1, n),'b')
    freqCurve, = freqGraph.plot(freq, magnitude,'g')
    
    # animate the curves
    ani = animation.FuncAnimation(fig, update, generateData,
                                  interval = 10, blit=True)
    
    # open window
    plt.show()
    
    # close serial connection
    ser.close()
    
    另一条信息:如果不使用串行端口,而是生成自己的数据,则程序工作正常,如下所示:

    def generateData():
        # simulate new data coming in
        while True:
    
            nse = np.random.randn(len(t))
            r = np.exp(-t/0.05)
            cnse = np.convolve(nse, r)*dt
            cnse = cnse[:len(t)]
            data =  100*np.sin(2*np.pi*t) + 500*cnse
    
    
            # fft computing and normalization
            magnitude = np.fft.fft(data)/n
            magnitude = np.abs(magnitude[range(n//2)])
    
            # calculates the fft dB
            magnitude_dB = [createMagnitudeDB(x) for x in magnitude]
    
            yield (data, magnitude)
    
    唯一的区别是generateData函数和不使用open/close串行命令,这就是为什么我不理解另一个代码上的“xdata和ydata必须是相同长度”错误(两个代码上的数据长度相同)

    编辑:

    该程序通过蓝牙从正在读取模拟引脚的arduino接收数据。我测量了arduino的读取时间,读取每个值需要“0.015毫秒”。读取和打印每个值需要“3.1ms”。计算机读取每个值的时间为“100ms”


    这意味着创建列表需要n*100(ms),即n是列表的元素数。我可以使用的最小“n”是256,创建列表需要25.6秒。这对于实时图形来说太长了。

    将1024个项目添加到列表并不需要几秒钟。从您的设备读取1024行数据可能需要几秒钟或几分钟,但我认为我们对此无能为力

    generateData
    中,您将项目附加到
    data
    中,但从不删除它们,因此
    data
    的增长没有限制。我猜您希望在循环的每次迭代中从一开始就重新创建
    数据

    # Read data from arduino
    data = []
    for i in range(n):     #while you are taking data
        PreData = ser.readline()
        data.append(int(PreData))
    
    问题1: 从外部很难判断您的数据采集需要多长时间,这是“太长”还是正常。串行连接的速度是每秒9600位,但我们不知道您读取了多少位。您可以使用
    time
    模块(
    start=time.time()。在这种情况下,也可以在每次读取数据后更新图形

    然而,真正的问题可能在于,您试图每10毫秒调用一次
    generateData()
    (在
    animation.FuncAnimation(…,interval=10,…)
    中指定)。这可能会导致问题,因为数据获取肯定需要更长的时间。也就是说,即使一次只读取一位,读取1024位也需要大约100毫秒。 因此,它可能有助于将间隔设置为更合理的数字,或者根本不使用
    FuncAnimation
    ,只需在读取数据后绘制数据即可

    问题2: 问题是,您使用长度为
    n
    timeCurve,=timeGraph.plot(np.linspace(0,1,n))的数组初始化
    时间图
    此时,数组数据中已经有
    n
    零。在第一次迭代中,附加从串行端口读取的另一个
    n
    编号。因此,在这一点上,
    data
    2*n
    长的

    现在的问题是,您只更新绘图的ydata(
    timeCurve.set_ydata(数据[0])
    ),因此x轴仍有
    n
    值(在开始时隐式设置),这与要设置到该绘图y轴的
    2*n
    值不匹配

    解决方案:

  • 第一个选项是在每次迭代中重新初始化数据,使其始终具有
    n
    条目

  • 第二个选项是通过以下方式更新绘图:

    timeCurve.set_data(np.arange(len(data[0])), data[0])
    
    将x和y数据都设置为相同长度的数组


  • 我测量了读取时间,它从“0.06秒”到“0.16秒”不等,平均值约为0.1秒。追加时间是打印“0.000000秒”。我不知道我是否做错了什么,或者是速度太快了。这意味着如果我创建一个包含1024个数字的列表,需要1024*0.1=102.4s才能创建该列表。这是一个巨大的延迟,使得无法绘制实时图形。即使我将“n”更改为256,也会有25.6s的延迟。我认为无法绘制每次我读取一个数据时都要用图形表示,因为要计算FFT,我需要一个数字序列。我用一些关于计时的新信息更新了帖子。问题实际上是串行端口的读取时间。波特率的增加能让事情变得更好吗?如果数据读取需要约0.1秒,这将完全符合我的预测。Appe将数据发送到列表确实是一个非常快速的操作,不能用
    时间准确测量,所以不用担心。您是否确实尝试了脚本并测量了创建列表的102秒?增加波特率可能会起作用。请注意,设备必须设置为该波特率,设置过高的波特率可能会使其变得不重要无法与设备通信。所有这些问题实际上都是针对您的配置的,我认为您应该创建一个新的(无任何matplotlib打印)然后问一个关于它的新问题,具体说明你的确切硬件。所以可能不是回答这样一个问题的最佳地点,但是如果你选择在这里发布,请确保使用
    arduino
    bluetooth
    标记。我刚刚预测的102。但是无论如何,谢谢你,我会按照你的建议去做。这可能是因为我使用bluetooth来接收数据吗串行数据?pr