Real Time Data Monitoring

Hi All:

I am writing a project to analyze data from a device in real time. The idea is to pick up the signal from a sensor through serial port in 20Hz and to do some calculation on the data received, and plot out the result on the form.

I use a background worker to read data from the serial port and do the calculation within a Do Loop. There is no problem on this. My problem is that when I try to use GDI+ to plot the results on the form, data are not refreshed instantly on the form. I use a Collection of Single to store the data for plotting.

Questions are:

1. Can Vb2005 do the job Or VC2005 is better

2. Is there a control I can use to plot instant data

3. Can I synchronize two threads I tried to let two background workers to run at the same time, but I noticed that only one is running, the other one is waiting.

Any suggestions would be very much appreciated.



Answer this question

Real Time Data Monitoring

  • Goodway

     

    Don't worry about shifting at all. That's very memory and compute intensive.

    Keep an index to the current data point. When you reach the array boundary reset the index to 0. This is what is meant by a circular buffer.

    You don't have to shift anything instead you increment an integer index.

     

     

     



  • forummember

    Hi SJWhiteley:

    "a collection is probably not the best way to store the data "

    Could you give a clue of the best way to store the data. I tried to use a Collection or a Quere to store the data, by adding an item in the beginning position and removing an item from the end to keep the number of items fixed. I searched the web. Someone uses Circular Buffer for this purpose. I am wondering how it is achieved.

    Many thanks.


  • Michael Brooks

    How fast are you refreshing the screen 100mS, 50ms, 20mS What speed do you want

    VB will be fine, but you do have diminishing return. Depending on the quantity of data points, a collection is probably not the best way to store the data (it may be a cool mechanism, but more than likely, inappropriate). You won't much, if any, performance increase using C++ over VB using GDI+. Go ahead and try it: do some benchmarks for yourself.

    Have a search on the net for activeX controls, or .NET controls that graph data: some free, the better ones you will have to buy. Or do it yourself.

    Separate your data acquisition from display. A timer is typically the best way to perform data refresh on a regular basis: depending on the data rate, and what the user is expecting, a rate of 100mS update down to 30mS may be appropriate for an HMI type display.

    (the form timer doesn't cut it, though. You'll have to use a multimedia timer, or a thread/system timer).

    If you use your data acquisition thread to format and store the data in a format that is immidiately usable by the GDI graphical commands you will gain better performance (since the DAQ routine will be only manipulatng several dozen data points instead of the GDI routines manipulating several thousand - or 100's of thousands - of data points - which don't change - every refresh cycle).



  • zjs

    Thanks.

    The data is received in 20Hz and I want to display 3 minutes data on the plot, therefore, about 3600 data points to be refreshed every 50ms. I did not refresh the form each time, but use the code to clear and plot the data:

    Dim bm As Image= New Bitmap(PictureBox.Width, PictureBox.Height)

    Dim gr As Graphics

    gr = Graphics.FromImage(bm)

    Dim Rect As New RectangleF

    gr.Clear(Color.White)

    For i = 0 To WorkQ.Count - 1 ' (3600 data poitns)

    x = x - unitX

    y = (maxUnit - WorkQ.Item(i)) * unitY

    Rect.X = x

    Rect.Y = y

    gr.FillEllipse(Brushes.Red, Rect)

    Next i

    PictureBox.BackgroundImage = bm


  • Sebastien Donche

     

    Drawline is one of the graphics routines from gdi+ that must be wrapped for .NET.

    I've used that to do graphing of line two pixels wide. It made for great points.

    If I remember correctly it took about 30 milliseconds to plot 650 points

    with this code:

     start = GetTickCount()
            For i As Short = 0 To 649
                a.PlotPoint(i, (Math.Sin(i / 57.3) * 100) + 100)
            Next
            Stoptime = GetTickCount - start

    Here is the graphics class I was calling:

     

    g = pb1.CreateGraphics()
            a = New GraphClass(g)


        End Sub

        Private Sub cbGo_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbGo.Click

            Static dtNow As DateTime = DateTime.Now


            a.SetupFrame()
            start = GetTickCount()
            For i As Short = 0 To 649
                a.PlotPoint(i, (Math.Sin(i / 57.3) * 100) + 100)
            Next
            Stoptime = GetTickCount - start

     

        End Sub
     
        Private Sub cbExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbExit.Click
            End
        End Sub

        Public Class GraphClass
            Protected Gain As New Single
            Private Intersection As Point = New Point(FrameCoord.HorizontalDisplacement, FrameCoord.X_Axis_VertLoc)
            Protected g As Graphics ' picture box graphic
            Protected AxisColor As Color = System.Drawing.ColorTranslator.FromOle(&HFF00)
            Protected AxisPen As Pen

            Public Sub New(ByVal obj As Graphics)

                ' this graphics is derived from a picture box object in the substantiator
                Gain = 1.0
                g = obj
                AxisPen = New Pen(AxisColor, 2)
            End Sub

            Public Sub SetupFrame()

                Dim pY_Begin As New Point(FrameCoord.HorizontalDisplacement, FrameCoord.Y_Axis_Start)
                Dim pY_End As New Point(FrameCoord.HorizontalDisplacement, FrameCoord.X_Axis_VertLoc)
                Dim pX_Begin As Point = Intersection
                Dim pX_End As New Point(FrameCoord.Y_Axis_XEnd, FrameCoord.X_Axis_VertLoc)

                ' Draw line to screen.
                Drawline(AxisPen, pY_Begin, pY_End)
                Drawline(AxisPen, pX_Begin, pX_End)


                For i As Short = FrameCoord.HorizontalDisplacement + 50 To FrameCoord.Y_Axis_XEnd Step 50
                    Drawline(Pens.BlanchedAlmond, New Point(i, FrameCoord.X_Axis_VertLoc - 10), New Point(i, FrameCoord.X_Axis_VertLoc))
                Next

                For i As Short = FrameCoord.X_Axis_VertLoc - 50 To FrameCoord.Y_Axis_Start Step -50
                    Drawline(Pens.BlanchedAlmond, New Point(FrameCoord.HorizontalDisplacement, i), New Point(FrameCoord.HorizontalDisplacement + 10, i))
                Next


            End Sub

            Public Sub PlotPoint(ByVal X As Integer, ByVal Y As Integer, Optional ByVal pn As Pen = Nothing)

                Dim xp As Integer = (-Y + FrameCoord.X_Axis_VertLoc) * Gain
                If pn Is Nothing Then
                    g.DrawLine(AxisPen, New Point(X + Intersection.X, xp), New Point(X + 1 + Intersection.X, xp + 1))
                Else
                    g.DrawLine(pn, New Point(X + Intersection.X, xp), New Point(X + 1 + Intersection.X, xp + 1))
                End If
            End Sub

            Public Sub Drawline(ByVal P As Pen, ByVal StartPoint As Point, ByVal EndPoint As Point)
                If P Is Nothing Then
                    g.DrawLine(AxisPen, StartPoint, EndPoint)
                Else
                    g.DrawLine(P, StartPoint, EndPoint)
                End If

            End Sub

        End Class

     

     

    Keep in mid that the code is also computing a sine at the same time.

    I even remembered that there are 57.3 degrees in a radian!

     I almost forget to mention that my machine is a 3.2 ghz hyperthreaded machine.

     



  • PLCweaver

     

     

    Thank you handsome....

    You just taugh me something....... It never occurred to me to store an array of points.

    That's a really groovy idea.   



  • Mieux

    Hi Jiao,

    I can probably answer part of your questions.

    1. If you are using GDI+ in the managed code, then VC2005 and VB2005 should do the same job.

    2. Not sure.

    3. Should be able to but I am not very familiar with that.

    By the way, have you tried to look at Form.invalidate and Form.Update method to refresh the drawing.

    John


  • Fagutish

    Hi ReneeC:

    If an array is used, I have to shift the whole array items one by one when new data is added:

    dim data(100) as array

    for i=100 to 1 step -1

    data(i)=data(i-1)

    next

    data(0)=0.16 'new coming data

    If I use a Collection, all data items are shifted automatically if an item is inserted at 0 position. I just need to remove the item at position 100. Am I right


  • George Bolsch

    Hi cgraus:

    I am new on GDI+, could you advise the proper way to plot the points.

    Many thanks.


  • Il-Sung

    SetPixel is the method you want to just plot a single point.



  • licheca

    What Renee said .

    Additionally, you could redimension the array if your point count got too big, or you wanted to increase the storage capacity dynamically (most of the applications I've worked/work on I don't know how many points I'll need, so I use this method).

    Also, for refreshing, you won't need to 'plot' the whole array: just the points that are added. Of course, if the application is minimized, resized, ec. you'll need to redraw everything.

    You are correct about the collection: it does save time adding points to it, however, that isn't an 'expensive' action. Retrieving and plotting needs to be as fast as possible. In that case, I would probably store an array of Points, rather than an array of single values, since those singles will need converting to points each and every time you need to plot (if you are plotting points, that is). Also, since memory is cheap, if you may need to readjust the point values (rescale, etc.) you may want to store two arrays: an array of the real world values and an array of points.

    Basically, you won't get something for nothing: the simplicity of the collection if offset by a time consuming retrieval and plotting. You can gain speed at the expense of memory - but you have to keep a check on it and know that you are consuming those resouces like a glutton, and will eventually run out, or will hinder performance.



  • Sedigh

    An array



  • prasannadotnet

    Does this draw more than a dot If it's drawing a dot, surely FillEllipse is a point of considerable cost



  • Herwin Grauel

    Public Class Form1

     

        Protected Const Bufsize As Short = 1000

        Protected Buf(Bufsize-1) As Single
        Protected Index As Short

     

     

        Private Sub StoreDataPoint(ByVal InVal As Single, Optional ByVal Start As Boolean = False)

             

            If (Start Or (Index > Bufsize-1)) Then Index = 0

     

            Buf(Index) = InVal

            Index += 1

     

     

        End Sub

     

    StoreDataPoint manages the data acquisition for you. Index and the buffer is acessible to everyone, when you are not acquiring or processing it, other routines have access to it to. The nice thing about this is that there no shifting and data storage is only a few machine instructions. Setting Start resets the buffer to zero. Index always tells you where the usable data is. It's behind Index in the buffer. It is a good idea to use Start though.

     



  • Real Time Data Monitoring