C#实时图表桌面应用程序太慢了

时间:2014-11-08 02:30:33

标签: c# multithreading charts serial-port real-time

我正在从实施桌面应用程序的人手中接管 C#代码,以便从串行端口中读取实时数据并显示它在图表中(使用图表类)。

代码似乎正在运行,但非常慢。它似乎是在4秒内(0.25Hz)更新图表一次。但是,我可以看到它是多线程的并且没有延迟命令,所以我不明白为什么它运行得如此之慢。图表的更新会减慢它吗?理想情况下,我希望实现每秒1000个数据点(1kHz),将其显示在实时保存到硬盘,其中每个数据点的大小约为 30个字节。

我花了几天时间来理解代码,但是它太麻烦了,无法全部写在一个文件中,没有任何评论。 我的目标是每秒读取1000个数据点是否真实/可实现?

我还考虑重新编写代码(而不是尝试修复代码),考虑到它只有 2,500行长。任何提示将不胜感激。另外,如果我重写代码,该应用程序可能更适合哪种语言

3 个答案:

答案 0 :(得分:1)

我开发了一些代码,我得到了显着的性能提升,它可能对你有用。这是我做的 -

第1步:我首先要确定哪一个是瓶颈,drawing/rendering of the chart

serial port

步骤2:如果您找到了渲染 - 然后在表单/图表设置中添加它,它将绘制得更快。但首先请仔细检查以确保您不在远程桌面模式下。

 <!-- language: c# -->

    // No double buffering for remote, only local
    public bool OptimizeOfLocalFormsOnly(System.Windows.Forms.Control chartControlForm)
    {
     if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
     {
              SetUpDoubleBuffer(chartControlForm);
              return true;
     }
     return false;

    }

    public static void SetUpDoubleBuffer(System.Windows.Forms.Control chartControlForm)
    {

       System.Reflection.PropertyInfo formProp = 
       typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",         System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);    
       formProp.SetValue(chartControlForm, true, null); 
    }

答案 1 :(得分:0)

我假设你使用winform应用程序:

使用serialPort组件:

  1. 配置其properties :( BaudRate,DataBits,StopBits,Parity ...)
  2. 利用其event(DataReceived)来收集您的输入。
  3. 您可以循环发送命令并收集输入/在图表组件上绘制它们大致如下:

    while(/*some condition*/)
    {
      serialPort.Write(/* your command */);
    
      // you have to think of response time
      // so implement something that waits a bit before calling the port again
      // I would do it using timers
    
      int tick= Environment.TickCount;
      while(Environment.TickCount - tick <= 100) // wait 100 milliseconds
      { 
        Application.DoEvents();
      }
    
    }
    
    // collect the data as:
    private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
      // use according to your needs, for example
      string data = "";
      int readByte;
      int available;
    
      available = serialPort.BytesToRead;
      if(available >= 30) // 30 bytes as stated in your question
      {
        for(int i=0; i<30; i++)
        {
          readByte = serialPort.ReadByte();
          data += String.Format("{0:2X}", readByte);
        }
    
        // you can call some methods to save/display your collected data from here
        save_to_file(data);
        display_to_chart(data);
      }
    
    }
    

答案 2 :(得分:0)

我开发了一个类似的应用程序,我在那里显示16个图表* 256个样本/秒。将数据存储在缓冲区中并创建一个单独的线程来更新图表。

读取新数据时,数据存储在列表或数组中。由于它是实时数据,因此也会在此处生成时间戳。使用获取的数据的采样率:timeStamp = timeStamp + sampleIdx / sampleRate;

public void OnDataRead(object source, EEGEventArgs e)
        {
            if ((e.rawData.Length > 0) && (!_shouldStop))
            {
                lock (_bufferRawData)
                {
                    for (int sampleIdx = 0; sampleIdx < e.rawData.Length; sampleIdx++)
                    {
                        // Append data
                        _bufferRawData.Add(e.rawData[sampleIdx]);

                       // Calculate corresponding timestamp
                      secondsToAdd = (float) sampleIdx/e.sampleRate;

                    // Append corresponding timestamp
                    _bufferXValues.Add( e.timeStamp.AddSeconds(secondsToAdd));
                    }
                }

然后,创建一个每N ms睡眠的线程(100ms适合我2秒显示数据,但如果我想显示10秒,我需要增加线程的500ms睡眠时间)

 //Create thread
 //define a thread to add values into chart
 ThreadStart addDataThreadObj = new ThreadStart(AddDataThreadLoop);
 _addDataRunner = new Thread(addDataThreadObj);
 addDataDel += new AddDataDelegate(AddData);

 //Start thread
 _addDataRunner.Start();

最后,更新图表并使线程每N ms休眠

 private void AddDataThreadLoop()
    {
        while (!_shouldStop)
        {
            chChannels[1].Invoke(addDataDel);

            // Sleeep thread for 100ms
            Thread.Sleep(100); 
        }
    }

AddData方法只读取存储在缓冲区中的X(时间戳)和Y值,并使用ptSeries.Points.AddXY(xValue,yValue)将其添加到图表中