C# - 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();
}
}
}
}
Спасибо за чтение!
3 ответа
Проблема в том, что вы звоните invalidate
с каждой точкой, которую вы рисуете. Это приводит к очень высокой загрузке процессора. Я работаю над очень похожим проектом, USB-устройством, в режиме реального времени отображая данные. Я использую отдельный поток для сбора данных. Этот поток создает событие каждый раз, когда получает пакет данных. Данные помещаются в очередь. График обновляется таймером. Вы найдете пример здесь. В этом коде график обновляется каждые 50 мс, на самом деле нет необходимости рисовать быстрее. В таймере я проверяю размер очереди и рисую больше или меньше точек, а затем вызываю invalidate
, Я не знаю, если это хорошее решение (всего 6 месяцев опыта в C#), но оно работает довольно хорошо с 7500 баллов. Вы должны сначала попытаться использовать таймер для обновления графика.
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();
}
Вы также можете использовать backgroundworker, поскольку он очень эффективен для обработки непрерывных графиков данных в реальном времени. также я не знаю, может ли zedgraph обрабатывать высокую скорость построения данных. если изменение структуры не является вариантом, просто ограничьте скорость, с которой график строится, скорее всего, с той скоростью передачи данных, которую строят, 2000 в секунду, которую zedgraph не может обработать. вот ссылка
https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=net-5.0