Я впервые здесь что-то задаю, поэтому я надеюсь, что задаю следующий вопрос «правильно». Если нет, дайте мне знать, и я дам дополнительную информацию.

Я использую один скрипт Python для чтения и записи 4000 Гц последовательных данных в файл CSV.

Структура файла CSV следующая: (в этом примере показано начало файла)

Time of mSure Calibration: 24.10.2020 20:03:14.462654
Calibration Data - AICC: 833.95; AICERT: 2109; AVCC: 0.00; AVCERT: 0 
Sampling Frequency: 4000Hz
timestamp,instantaneousCurrentValue,instantaneousVoltageValue,activePowerValueCalculated,activePowerValue
24.10.2020 20:03:16.495828,-0.00032,7e-05,-0.0,0.0
24.10.2020 20:03:16.496078,0.001424,7e-05,0.0,0.0
24.10.2020 20:03:16.496328,9.6e-05,7e-05,0.0,0.0
24.10.2020 20:03:16.496578,-0.000912,7e-05,-0.0,0.0

Данные будут записываться в этот CSV, пока активен сценарий чтения последовательных данных. Таким образом, в какой-то момент это может стать огромным файлом. (Данные записываются кусками по 8000 строк = каждые две секунды)

Вот моя проблема: я хочу отобразить эти данные в реальном времени. Например, обновляйте график каждый раз, когда данные записываются в файл CSV. Построение должно выполняться из другого сценария, чем сценарий чтения и записи последовательных данных.

Что работает: 1. Создание файла CSV. 2. Построение готового CSV-файла с помощью другого скрипта - на самом деле неплохо :-)

У меня есть этот скрипт для черчения:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Data Computation Software for TeensyDAQ - Reads and computes CSV-File"""

# region imports
import getopt
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import pathlib
from scipy.signal import argrelextrema
import sys
# endregion

# region globals
inputfile = ''
outputfile = ''
# endregion

# region functions
def main(argv):
    """Main application"""

    # region define variables
    global inputfile
    global outputfile
    inputfile = str(pathlib.Path(__file__).parent.absolute(
    ).resolve())+"\\noFilenameProvided.csv"
    outputfile = str(pathlib.Path(__file__).parent.absolute(
    ).resolve())+"\\noFilenameProvidedOut.csv"
    # endregion

    # region read system arguments
    try:
        opts, args = getopt.getopt(
            argv, "hi:o:", ["infile=", "outfile="])
    except getopt.GetoptError:
        print('dataComputation.py -i <inputfile> -o <outputfile>')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print('dataComputation.py -i <inputfile> -o <outputfile>')
            sys.exit()
        elif opt in ("-i", "--infile"):
            inputfile = str(pathlib.Path(
                __file__).parent.absolute().resolve())+"\\"+arg
        elif opt in ("-o", "--outfile"):
            outputfile = str(pathlib.Path(
                __file__).parent.absolute().resolve())+"\\"+arg
    # endregion

    # region read csv
    colTypes = {'timestamp': 'str',
                'instantaneousCurrent': 'float',
                'instantaneousVoltage': 'float',
                'activePowerCalculated': 'float',
                'activePower': 'float',
                'apparentPower': 'float',
                'fundReactivePower': 'float'
                }
    cols = list(colTypes.keys())
    df = pd.read_csv(inputfile, usecols=cols, dtype=colTypes,
                     parse_dates=True, dayfirst=True, skiprows=3)
    df['timestamp'] = pd.to_datetime(
        df['timestamp'], utc=True, format='%d.%m.%Y %H:%M:%S.%f')
    df.insert(loc=0, column='tick', value=np.arange(len(df)))
    # endregion

    # region plot data
    fig, axes = plt.subplots(nrows=6, ncols=1,  sharex=True, figsize=(16,8))
    fig.canvas.set_window_title(df['timestamp'].iloc[0]) 
    fig.align_ylabels(axes[0:5])

    df['instantaneousCurrent'].plot(ax=axes[0], color='red'); axes[0].set_title('Momentanstrom'); axes[0].set_ylabel('A',rotation=0)
    df['instantaneousVoltage'].plot(ax=axes[1], color='blue'); axes[1].set_title('Momentanspannung'); axes[1].set_ylabel('V',rotation=0)
    df['activePowerCalculated'].plot(ax=axes[2], color='green'); axes[2].set_title('Momentanleistung ungefiltert'); axes[2].set_ylabel('W',rotation=0)
    df['activePower'].plot(ax=axes[3], color='brown'); axes[3].set_title('Momentanleistung'); axes[3].set_ylabel('W',rotation=0)
    df['apparentPower'].plot(ax=axes[4], color='brown'); axes[4].set_title('Scheinleistung'); axes[4].set_ylabel('VA',rotation=0)
    df['fundReactivePower'].plot(ax=axes[5], color='brown'); axes[5].set_title('Blindleitsung'); axes[5].set_ylabel('VAr',rotation=0); axes[5].set_xlabel('microseconds since start')
    
    plt.tight_layout()    
    plt.show()
    # endregion

# endregion


if __name__ == "__main__":
    main(sys.argv[1:])

Мои мысли о том, как решить мою проблему:

  1. Измените мой сценарий построения так, чтобы он постоянно читал файл CSV и строил график, используя функцию анимации matplotlib.
  2. Использование каких-то потоковых функций для чтения CSV в потоке. Я читал о библиотеке streamz, но понятия не имею, как ее использовать.

Любая помощь высоко ценится!

С уважением, Саша

ИЗМЕНИТЬ 31.10.2020:

Поскольку я не знаю средней продолжительности и того, как долго ждать помощи, я стараюсь добавить больше информации, которая может привести к полезным комментариям.

Я написал этот сценарий для непрерывной записи данных в файл CSV, который имитирует мой настоящий сценарий без необходимости во внешнем оборудовании: (Случайные данные создаются и форматируются в формате CSV с использованием таймера. Каждый раз, когда появляется 50 новых строк, данные записываются в файл CSV)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv
from random import randrange
import time
import threading
import pathlib
from datetime import datetime, timedelta

datarows = list()
datarowsToWrite = list()
outputfile = str(pathlib.Path(__file__).parent.absolute().resolve()) + "\\noFilenameProvided.csv"
sampleCount = 0

def startBatchWriteThread():
    global outputfile
    global datarows
    global datarowsToWrite
    datarowsToWrite.clear()
    datarowsToWrite = datarows[:]
    datarows.clear()
    thread = threading.Thread(target=batchWriteData,args=(outputfile, datarowsToWrite))
    thread.start()

def batchWriteData(file, data):
    print("Items to write: " + str(len(data)))
    with open(file, 'a+') as f:
        for item in data:
            f.write("%s\n" % item)

def generateDatarows():
    global sampleCount
    timer1 = threading.Timer(0.001, generateDatarows)
    timer1.daemon = True
    timer1.start()
    datarow = datetime.now().strftime("%d.%m.%Y %H:%M:%S.%f")[:] + "," + str(randrange(10)) + "," + str(randrange(10)) + "," + str(randrange(10)) + "," + str(randrange(10)) + "," + str(randrange(10)) + "," + str(randrange(10))
    datarows.append(datarow)
    sampleCount += 1

try:
    datarows.append("row 1")
    datarows.append("row 2")
    datarows.append("row 3")
    datarows.append("timestamp,instantaneousCurrent,instantaneousVoltage,activePowerCalculated,activePower,apparentPower,fundReactivePower")
    startBatchWriteThread()
    generateDatarows()
    while True:
        if len(datarows) == 50:
            startBatchWriteThread()
except KeyboardInterrupt:
    print("Shutting down, writing the rest of the buffer.")
    batchWriteData(outputfile, datarows)
    print("Done, writing " + outputfile)

Затем сценарий из моего первоначального сообщения может отображать данные из файла CSV.

Мне нужно отобразить данные по мере их записи в файл CSV, чтобы увидеть данные более или менее в реальном времени.

Надеюсь, это сделает мою проблему более понятной.

0
AlpenFlizzer 28 Окт 2020 в 13:02

1 ответ

Лучший ответ

Для гуглеров: я не смог найти способ достичь своей цели, как описано в вопросе.

Однако, если вы пытаетесь отобразить данные в реальном времени, поступающие с высокой скоростью по последовательной связи (4000 Гц в моем случае), я рекомендую проектировать ваше приложение как единую программу с несколькими процессами.

Проблема в моем частном случае заключалась в том, что когда я пытался построить и вычислить входящие данные одновременно в одном потоке / задаче / процессе / чем угодно, моя скорость последовательного приема снизилась до 100 Гц вместо 4 кГц. Решение с многопроцессорной обработкой и передачей данных с использованием модуля quick_queue между процессами я смог решить проблему.

В итоге у меня была программа, которая получает данные от Teensy через последовательную связь с частотой 4 кГц, эти входящие данные буферизировались в блоки по 4000 сэмплов, а затем данные отправлялись в процесс построения графика, и, кроме того, блок был записан в CSV. -файл в отдельной теме.

Best, S

0
AlpenFlizzer 21 Дек 2020 в 12:49