locked
calculate average for updating data RRS feed

  • Question


  • From the Program below, I able the read the last 2nd line for every second from the bw.txt file. Take note that bw.txt will updated by another software every second, so the data read using my program will vary every second.

    From here, I want to calculate the average value for the data i read every second. The example below show how the bw.txt will keep updating. The arrow indicate data i read in every 1 second.

    bw.txt :
    1second .....2 second..........3second
    ------------------------------------------
    1 ..................1....................1
    2->............... 2....................2
    3...................3->.................3
    .....................4....................4 ->
    ...........................................5
    ------------------------------------------
    I want to calculate average for this data every second.
    1second : 2/1 =2
    2second : (2+3)/2 =2.5
    3second : (2+3+4)/3 =3
    How can i do it??? Please help me!!

    /* visual basic 2005
    read the last 2nd line of notepad & display the whole line on label2 */

    ---------------------------------------------------------------------------------------------
     Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerRetrieveMSG.Tick
            Dim iFound As Object
            Dim sLine As Object
            Dim hFile As Short
            Dim sBuffer As String
            Dim sLines() As String
            Dim sCols() As String
            Dim sValue As String

            ' Replace these constants with
            ' correct file names and
            Const LogFile As String = "C:\bw.txt"

            ' number of bytes to read from end of file
            Const BytesToRead As Short = 256

            ' Create buffer to contain last few lines of file
            sBuffer = Space(BytesToRead)

            hFile = FreeFile()
            FileOpen(hFile, LogFile, OpenMode.Binary)
            ' Move file pointer to End-of-File - BytesToRead
            Seek(hFile, LOF(hFile) - BytesToRead)
            ' Fill sBuffer with data
            FileGet(hFile, sBuffer)
            FileClose(hFile)

            'Get array of lines from sBuffer
            sLines = Split(sBuffer, vbCrLf)
            ' Get second-to-last line from sLines array
            sLine = sLines(UBound(sLines) - 1)
            ' Split line into array of values
            sCols = Split(sLine)
            ' "Both" column is fifth element
            ' (array is 0-based)
            sValue = sCols(0)
     
            Err.Clear()

       End Sub
     ------------------------------------------------------------------------------------------
    Saturday, April 14, 2007 9:51 AM

Answers

  • If your timer's interval is 1 second, then the value/sec average would look like this (I'm assuming sValue is the value that's being added) (Static means the variable and its value are retained):


    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerRetrieveMSG.Tick

    Dim zNewValue as Long =0
    Dim zAVG as Double = 0

    Static zTotalValue as long =0
    Static zTickCount as long =0

    Long.TryParse(sValue, zNewValue)

    zTotalValue += zNewValue
    zTickCount += 1

    zAVG = zTotalValue / zTickCount

    End Sub
    Saturday, April 14, 2007 10:29 AM

All replies

  • If your timer's interval is 1 second, then the value/sec average would look like this (I'm assuming sValue is the value that's being added) (Static means the variable and its value are retained):


    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerRetrieveMSG.Tick

    Dim zNewValue as Long =0
    Dim zAVG as Double = 0

    Static zTotalValue as long =0
    Static zTickCount as long =0

    Long.TryParse(sValue, zNewValue)

    zTotalValue += zNewValue
    zTickCount += 1

    zAVG = zTotalValue / zTickCount

    End Sub
    Saturday, April 14, 2007 10:29 AM
  • Thank you nogChoco! Your code can run properly and get what I want. Appreciate it!

    Good Day!
    Saturday, April 14, 2007 1:51 PM
  • As extension from case in this post, I would like to create a live graph which is something similar to a monitoring graph. The X- axis indicate the time (s) and the Y-axis will show to zAVG value (bps). How can i do it so that the graph will automatic plot every second the zAVG updated? Please help me out! thanks vy much...

    Saturday, April 14, 2007 4:01 PM
  • add the values to a point array, then plot the values in a panel, form, user control (recommended)...

     

    Set the Y value to the value you want, the X value to the time. You'll ned to scale it of course, suitable to the plotting region (you can do this using graphical transforms, but I've stopped doing that as the actual calculations are much quicker).

     

    Once you have an array of points, plot them using the drawlines method of a graphics object...just to show off what can be done Smile Here's a little something I've been working on.

     

     Each line is a fixed array of points, populated on a periodic basis.

     

    What you may want to do with your average, though, is create a moving average, because by the time you get to a certain point, the sum will completely outweigh any new data that you add.

    Saturday, April 14, 2007 4:36 PM
  • Thanks Mr. SJWhiteley for your opinion. Actually I am quite new to VB, I don't really know how to do it in this case. Can you help me to write some code on it? I just need very simple live graph only. Yours graph was too great for me Wink Hope you can help me out on this.

    Thank You

    Good Day!

    Saturday, April 14, 2007 4:44 PM
  • Hi again, irvineyan

    I've got a half-finished one in a network-traffic monitoring app I was building, but I've integrated the graph a bit too much with the rest of it, for it to be re-usable straightaway. I was planning on making a standalone control out of it, but I can't promise when or whether I'd get that done. Example of what my graph looks like - the thin dotted line is the average-line.

    I can give you some of the ideas I put into it, though:

    --- because it's easier to have a fixed size for the graph, the graphpoints were actually computed as "percentages of the maximumvalue"  (full height of graph = maximumvalue seen during trackingperiod = 100%), so that a change in the maximumvalue would allow easy repositioning of the previous points.

    --- I used a "Queue" which is a special type of collection which has easy .Enqueue / .Dequeue methods to put new ticks in and remove old ticks.

    --- that Queue's size was determined by a TimeSpanTrackedByGraph variable and a GraphUpdateInterval, so for example: if the TimeSpanTrackedByGraph is 10seconds, and the GraphUpdateInterval is 1 second, then there would be 10 items in the Queue.


    I'm sure there already are free standalone graphing controls available around the web, though - sites like the CodeProject have lots of custom controls available for download (it requires registration, but that's free).








    Saturday, April 14, 2007 5:03 PM
  • To Mr nogChoco,

    Yes, cool man your project! The example graph is the one I wanna do. I am rushing for submission. This is really hard for me to figure out. Can you just show me the code how can i implement on my case?  I really appreciate for you opinion and helping.
    Good Day!
    Saturday, April 14, 2007 5:30 PM
  • The actual drawing is just one line of code - I'll show you the paint event code of my graph to prove it. All you need to do, is build an array of points and feed that to the Graphics.DrawCurve method (the bolded line in the example).

    Building the points is pretty straightforward. If you have a datavalue, then

    Dim zPoint as Point
    zPoint.X = Control.Width / TotalNumberOfDataValues * DataValueIndex
    zPoint.Y = Control.Height / 100 * DataValue_AsPercentageOfMaximum

    (Control = the control on which you're drawing the graph)
    (DataValueIndex = 1 for first point, 2 for second point, and so on...)

    Here's the code of my graph's paint event:

      Private Sub SpeedGraphLabel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            If theCurvePoints Is Nothing Or theFillCurvePoints Is Nothing Or theZeroLinePoints Is Nothing Then Exit Sub
            If sgBrush_FillCurve Is Nothing Or sgBrush_Curve Is Nothing Or sgBrush_ZeroLine Is Nothing Then Exit Sub
            sgReadyForNewPaint = False
           
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
            e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            e.Graphics.CompositingMode = Drawing2D.CompositingMode.SourceOver
            e.Graphics.CompositingQuality = Drawing2D.CompositingQuality.HighQuality

            Dim zPen As Pen = Nothing
            'Draw FillCurve
            e.Graphics.FillClosedCurve(sgBrush_FillCurve, theFillCurvePoints)
            'Draw AVGLine
            zPen = New Pen(sgBrush_AVGLine, Thickness_AVGLine)
            zPen.DashPattern = DashPattern_AVGLine
            e.Graphics.DrawLines(zPen, theAVGLinePoints)
            'Draw GraphCurve
            zPen = New Pen(sgBrush_Curve, Thickness_Curve)
            e.Graphics.DrawCurve(zPen, theCurvePoints)
            'Draw ZeroLine
            zPen = New Pen(sgBrush_ZeroLine, Thickness_ZeroLine)
            e.Graphics.DrawLines(zPen, theZeroLinePoints)

            sgReadyForNewPaint = True
        End Sub

    If you're new to VB.NET, then I would strongly recommend taking a little time to learn how to use Graphics to paint on controls (or Bitmaps). It's very easy and you will gain a lot of programming power from it:  Graphics and Drawing in Windows Forms
    Saturday, April 14, 2007 5:59 PM
  • Thanks very much! really thanks a lot!
    I will try to figure it out on how to implement it.
    If any question i will post to you again.
    See you. Have a nice day...Wink
    Saturday, April 14, 2007 6:39 PM
  • You're welcome - have a nice day too
    Saturday, April 14, 2007 6:43 PM
  • Here's a quick plotting routine (However, obviously beaten to the punch):

     

    Code Snippet

     

    Public Class Form1

    Private Data(0 To 999) As Single

    Private Average(0 To 999) As Single

    Private WriteIndex As Integer

    Private Points() As PointF

    Private PointsAverage() As PointF

    Private Rnd As New Random

    Private PointsToPlot As Integer = 100

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    ' Set the timer

    Timer1.Interval = 100

    Timer1.Enabled = True

    ' Make sure there's points to plot

    ReDim Points(0 To PointsToPlot - 1)

    ReDim PointsAverage(0 To PointsToPlot - 1)

    Me.DoubleBuffered = True

    Me.BackColor = Color.AliceBlue

    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

    ' All drawing is done here

    e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

    e.Graphics.DrawCurve(Pens.Navy, Points)

    e.Graphics.DrawCurve(Pens.DarkRed, PointsAverage)

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    ' Add Data Point

    Data(WriteIndex) = Rnd.Next(-1000, 1000) / 1000.0F

    Call CalculateAverage(WriteIndex)

    WriteIndex += 1

    If WriteIndex >= Data.Length Then WriteIndex = 0

    ' Calculate the average

    Call CalculatePoints()

    Me.Invalidate()

    End Sub

    Private Sub CalculateAverage(ByVal index As Integer)

    ' Index to count backwards from the

    ' current Write Index

    Dim count As Integer = index

    If count < 0 Then count = Data.Length - 1

    '

    ' Calculate he total of the previous

    ' number of points

    Dim total As Double

    For i As Integer = 0 To PointsToPlot - 1

    total += Data(count)

    count -= 1

    If count < 0 Then count = Data.Length - 1

    Next

    ' Set the average for this value

    Average(index) = Convert.ToSingle(total / PointsToPlot)

    End Sub

    Private Sub CalculatePoints()

    ' Index to count backwards from the

    ' current Write Index

    Dim count As Integer = WriteIndex - 1

    If count < 0 Then count = Data.Length - 1

    ' Running Pixel X Location

    Dim x As Single = ClientSize.Width - 1

    ' X Increment Value

    Dim increment As Single = 1.0F * ClientSize.Width / PointsToPlot

    ' Y Scaling Factor: not -ve value

    ' since the ZERO point is top left

    Dim yscale As Single = -0.5F * ClientSize.Height

    For i As Integer = 0 To PointsToPlot - 1

    ' Set the X Positions

    Points(i).X = x

    PointsAverage(i).X = x

    ' Set the Y Position

    Points(i).Y = Data(count) * yscale + ClientSize.Height / 2.0F

    PointsAverage(i).Y = Average(count) * yscale + ClientSize.Height / 2.0F

    x -= increment

    count -= 1

    If count < 0 Then count = Data.Length - 1

    Next

    End Sub

    End Class

     

    Saturday, April 14, 2007 6:43 PM
  • To Mr. Stephen J Whiteley :

    Thank  you for provide me the plotting routine. It was useful! Thanks once again.


    Good day!

    Saturday, April 14, 2007 6:57 PM