С# - Zedgraph, построение последовательных данных слишком большой задержкой и временной задержкой

Я новичок в программировании на C# и пытаюсь написать приложение, которое является частью моей финальной диссертации.

У меня есть микропроцессор, который постоянно отправляет данные с датчика на мой компьютер через последовательный порт. Все, что я хочу, это построить эти данные с помощью Zedgraph.

Проблема в том, что график получил слишком большую задержку и временной лаг. Кажется, проблема возникает из-за того, что я постоянно обновляю весь график с очень высокой скоростью. Я застрял на этой проблеме через неделю и до сих пор не нашел решения. Я буду более чем счастлив, если кто-то может мне помочь.

Это мой код:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ZedGraph;
using System.IO.Ports;
using System.Threading;

namespace DynamicData
{
public partial class Form1 : Form
{
    private SerialPort port;
    private string buffer = "";

    private void connect()
    {
        port = new SerialPort("COM8", 115200, Parity.None, 8, StopBits.One);
        port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived);
        if (!port.IsOpen) port.Open();
    }

    public Form1()
    {
        InitializeComponent();
    }


    private void Form1_Load( object sender, EventArgs e )
    {
        connect();
        GraphPane myPane = zedGraphControl1.GraphPane;          
        RollingPointPairList list = new RollingPointPairList(500);
        LineItem curve = myPane.AddCurve( "Sensor", list, Color.Blue, SymbolType.None );

        myPane.XAxis.Scale.Min = 0;
        myPane.XAxis.Scale.Max = 10;
        myPane.YAxis.Scale.Min = 0;
        myPane.YAxis.Scale.Max = 300;
        myPane.XAxis.Scale.MinorStep = 0.5;
        myPane.XAxis.Scale.MajorStep = 1;

        zedGraphControl1.AxisChange();

    }


    private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        //sample data: ;100*100000:
        //sampling rate ~100Hz
        buffer += port.ReadExisting();

        //flush incomplete package
        while (buffer[0] != ';')
        {
            buffer = buffer.Remove(0, 1);
            if (buffer.Length < 1) break;
        }

        //got a complete package, go to data handling
        while (buffer.Contains(":"))
        {
            DataHandling();
        }
    }


    private void DataHandling()
    {
        string[] nameArray = buffer.Split(new[] { ";", ":", "*" }, StringSplitOptions.RemoveEmptyEntries);

        //plot sensor data vs. time
        draw(Convert.ToInt32(nameArray[0]), Convert.ToInt32(nameArray[1]));

        //remove handled package in buffer
        var index = buffer.IndexOf(":");
        buffer = buffer.Remove(0, index + 1);

    }

    double time = 0;
    private void draw(int sensor, int t)
    {
        //convert tick to sec (uP clock rate = 16MHZ)
        time = time + (t / 16000000.0);

        // Get the first CurveItem in the graph
        LineItem curve = zedGraphControl1.GraphPane.CurveList[0] as LineItem;

        // Get the PointPairList
        IPointListEdit list = curve.Points as IPointListEdit;
        list.Add(time, sensor);


        //Keep the X scale at a rolling 10 second interval, with one
        //major step between the max X value and the end of the axis
        Scale xScale = zedGraphControl1.GraphPane.XAxis.Scale;
        if (time > xScale.Max - xScale.MajorStep)
        {
            xScale.Max = time + xScale.MajorStep;
            xScale.Min = xScale.Max - 10.0;
        }

        //Display sensor data
        this.Invoke(new Action(() => { textBox1.Text = byte1.ToString(); }));

        axisChangeZedGraph(zedGraphControl1);

    }

    delegate void axisChangeZedGraphCallBack(ZedGraphControl zg);
    private void axisChangeZedGraph(ZedGraphControl zg)
    {
        if (zg.InvokeRequired)
        {
            axisChangeZedGraphCallBack ad = new axisChangeZedGraphCallBack(axisChangeZedGraph);
            zg.Invoke(ad, new object[] { zg });
        }
        else
        {
          //  zg.AxisChange();
            zg.Invalidate();
            zg.Refresh();
        }
    }

}
}

Спасибо за чтение!


person chuonghd    schedule 28.05.2013    source источник
comment
Я не знаю компонент ZedGraph, но мне кажется, что он здесь является узким местом. ZedGraph, вероятно, никогда не предназначался для обработки непрерывных обновлений. Я советую использовать другой компонент графа, предназначенный для этой задачи. Либо так, либо добавляйте результаты порциями (10, 20, 50 или, возможно, по 100 результатов одновременно) в ZedGraph.   -  person Casperah    schedule 28.05.2013
comment
Вы пробовали обновлять график медленнее? Возможно, новый поток можно было бы использовать для сна на некоторое время, проверки данных в буфере, а затем обновления графа?   -  person PeskyGnat    schedule 29.05.2013


Ответы (3)


Проблема в том, что вы вызываете invalidate для каждой точки, которую рисуете. Это приводит к очень высокой нагрузке на процессор. Я работаю над очень похожим проектом, USB-устройством, графиком данных в реальном времени. Я использую отдельный поток для сбора данных. Этот поток создает событие каждый раз, когда получает пакет данных. Данные помещаются в очередь. График обновляется по таймеру. Пример вы найдете здесь. В этом коде график обновляется каждые 50 мс, быстрее рисовать особо не нужно. В таймере я проверяю размер очереди и рисую больше или меньше точек, а затем вызываю invalidate. Я не знаю, хорошее ли это решение (всего 6 месяцев опыта в C#), но оно работает достаточно хорошо с 7500 баллами. Сначала вы должны попробовать использовать таймер для обновления графика.

person Olli_Li    schedule 03.06.2013

1). Создайте и отформатируйте кривую только один раз. сохранить его на уровне модуля.

2). При добавлении точки используйте curve.AddPoint();, затем zg.Refresh();

//this is just to add a point to the plot, the curve object should have already been created
private void draw(int sensor, int t)
    {
        //convert tick to sec (uP clock rate = 16MHZ)
        time = time + (t / 16000000.0);

        //curve should be a module-level variable already set up with proper formatting,
        //just no points yet
        curve.AddPoint(time, sensor);

        //Display sensor data
        this.Invoke(new Action(() => { textBox1.Text = byte1.ToString(); }));

        zg.AxisChange();
        zg.Refresh();

    }
person mike    schedule 22.12.2014

Вы также можете использовать backgroundworker, так как он очень эффективен для непрерывной обработки данных в режиме реального времени. Кроме того, я не знаю, может ли zedgraph справиться с высокой скоростью построения данных.

Если изменение структуры невозможно, просто ограничьте скорость построения графика. Скорее всего, при такой скорости передачи данные составляют 2000 в секунду, что zedgraph не может обработать.

Вот ссылка на backgroundworker: https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=net-5.0

person Nakarmi Simon    schedule 04.06.2021