Click here to Skip to main content
14,733,890 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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();
        }
    }

}
}
Posted
Comments
Member 10741366 22-Jul-14 9:39am
   
can you share the source code..?

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.
   
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.
   
v2
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.
   
Comments
Member 10741366 22-Jul-14 9:38am
   
can you share the source code
lukeer 23-Jul-14 1:51am
   
I don't have it. I just described what needs to be done.
If you have a specific problem in your code not behaving as expected, tell us what exactly doesn't work.
A new question could help with that. It' a great way to show what part of your code needs to be tuned.
And drop me a note here so I get informed when you're done postin your question.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900