C# - Zedgraph,绘制串行数据太多延迟和时滞 [英] C# - Zedgraph, plotting serial data too much delay and time lag

查看:137
本文介绍了C# - Zedgraph,绘制串行数据太多延迟和时滞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C#编程的新手并试图编写一个应用程序,这是我最后论文的一部分。



我有一个微处理器,可以连续发送数据来自传感器通过串口连接到我的电脑。我想要的就是使用Zedgraph绘制这些数据。



问题是图表有太多的延迟和时滞。似乎问题发生是因为我以非常高的速率不断更新整个图表。我在一周内坚持这个问题仍然没有找到解决方案。如果有人可以帮助我,我会非常高兴。



这是我的代码:

I'm new to C# programming and trying to write an application which is part of my final thesis.

I have a microprocessor that continuously send data from a sensor to my computer via serial port. All I want is to plotting this data using Zedgraph.

The problem is that the graph got too much delay and time lag. It seems the problem happens because I continuously update the whole graph at a very high rate. I have stucked on this problem in a week and still dont find out a solution. I'll be more than happy if someone can help me out.

This is my code:

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();
        }
    }

}
}

推荐答案

你'可能需要编写自己的控件或找到一个专门用于高速渲染数据的控件。



ZedGraph是一个通用图形解决方案,不是为你设计的正在做。



如果可能,请不要连续更新图表。让它每隔一段时间重新绘制一次数据时间快照视图。
You're probably going to have to write your own control or find a control dedicated to rendering data at high speeds.

ZedGraph is a general purpose graphing solution not designed for what you're doing.

If at all possible, don't update the graph continuously. Have it repaint every once in a while for a "snapshot in time" view of the data.


根据输入数据的速率,无法使用C#zedgraph,或者你当一个垃圾收集器或任何其他复杂的人认为维持C#和.Net4652.8版本需求时,你会看到图形上的漏洞。

您的串口将产生无效的中断,需要管理填充缓冲区



我的2 cts建议:



1)翻译C#Zedgraph用C ++编写的包。打开水平分屏。在右侧窗格中有Zedgraph的C#源代码,在左侧开始用C ++翻译它。为什么选择C ++?

许多C ++编译器可以为嵌入式操作系统(windows,Linux等)生成代码,这些代码也可以在桌面上运行

作为第一个Zgraph 1996年初是用C ++编写的,如果你有时间浏览,你可以找到它似曾翻译

毕竟,对于这样一个小小的显示任务,PC可以被替换(在批量生产中)一个小板子



2)你的C#不能实时运行,它通过伪代码解释器运行,就像第一个标记化的Basic,或Wirth的p代码。

请告诉你的老师按下重物的自动盒的重置按钮,然后将钱带到超市。他将在屏幕上看到一个嵌入式Linux初创公司。现实生活也许就在那里。

但是对于你的教育,C#,java等都很棒。请耐心等待,不要急于求成。
Depending of the rate of your input data, the C# zedgraph could not be used, or you'll see holes on your graphics when a "garbage collector" or any other sophisticated think to maintain alive the C# and the .Net "4652.8 version" demand..
Your serial port will generate not served interrupts, will need to manage filling buffers

my 2 cts advice :

1) Translate the C# Zedgraph package in C++. Open an horizontal split screen. On the right pane have the C# source of Zedgraph, and on the left start to translate it in C++. Why C++ ?
Many C++ compilers can generate code for embedded OS's (windows, Linux, etc..) which run also on the Desktops
As the 1-st Zgraph in early 1996 was in C++ if you have time to browse, you can find it "déjà translated"
After all, for such a little displaying task a PC can be replaced (in "mass production") by a little board

2) Your C# can't be run in real-time, it runs through a pseudo code interpreter as was the first tokenized Basic, or the Wirth's p-code.
Please tell your teacher to push the reset button of the automatic box that weighs items and takes his money to supermarket. He will see an embedded linux startup on the screen.. The real life is perhaps there.
But for your education, C#, java, etc, are excellent. Be patient, do not rush.


通常,每秒重绘一次图表是非常顺利的。



因此创建你的自己控制。从控制 [ ^ ]。覆盖其 OnPaint() [ ^ ]方法来绘制你的一切需要它只是一些 DrawLine() [ ^ ]和很多简单的几何来计算属于哪里。



创建一堆成员变量来描述什么在任何给定的时间绘制。你不知道你的控件何时会发生重绘。 OnPaint()使用这些变量, port_DataReceived()更新它们(可能不直接,但通过调用 DataHandling()或其他任何方式)。 />


放置一个系统。 Windows.Forms.Timer [ ^ ]。 .NET中有更多的计时器,但是这个计时器是出于UI的目的(它偶尔会丢弃一个勾选 [ ^ ]事件或其他,如果UI仍然忙碌)。将计时器设置为每秒触发四次。在tick事件中,只需调用 this.Invalidate() [ ^ ]。它将告诉应用程序您的控件需要重绘。在OnPaint()运行之前,没有办法告诉它何时会被重绘。



您可以通过使用成员变量进一步调整它每次收到新值时设置的bool _hasChanged ,每次重绘后重置并检查 Tick 事件处理程序以检查是否确实需要重绘。所以你可以保存一些不必要的绘图。



有了这个计时器的东西,你可以继续使用ZedGraph,因为重绘频率会大大降低。
Usually, redrawing a graph four times per second is smooth enough.

Therefore create your own control. Derive it from Control[^]. Override its OnPaint()[^] method to draw everything you need It's just some DrawLine()[^]s and a lot of simple geometry to compute what belongs where.

Create a bunch of member variables sufficing to describe what to draw at any given time. You won't know when exactly a redraw happens to your control. OnPaint() uses these variables, port_DataReceived() updates them (maybe not directly, but through calling DataHandling() or whatever).

Put a System.Windows.Forms.Timer[^] in your class. There are more flavours of timers in .NET, but this one is made for UI purposes (it occasionally drops one Tick[^] event or the other if UI is busy anyway). Set the timer to fire four times a second. In the tick event, simply call this.Invalidate()[^]. It will tell the application that your control needs to be redrawn. There's no way to tell when it actually will be redrawn until OnPaint() runs.

You can further tweak that by by using a member variable bool _hasChanged that you set everytime new values have been received, reset after every redraw and check in the Tick event handler to check if redrawing is actually necessary. So you might save some unnecessary drawing.

With this timer stuff, you could as well keep using ZedGraph since the redraw frequency will be significantly lowered.


这篇关于C# - Zedgraph,绘制串行数据太多延迟和时滞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆