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

本文关键字:应用程序 桌面 实时 | 更新日期: 2023-09-27 18:29:34

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

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

我花了几天时间来理解代码,但它太麻烦了,无法理解,所有代码都写在一个文件中,没有注释我每秒读取1000个数据点的目标是否现实/可实现

我还考虑重新编写代码(而不是试图修复它),因为它只有大约2500行长。任何提示都将不胜感激。此外,如果我重写代码,什么语言可能更适合这个应用程序

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

我开发了一些代码,在这些代码中我获得了显著的性能改进,这可能对您有用。以下是我所做的-

步骤1:我首先识别哪个是瓶颈,drawing/rendering of the chart

serial port

第二步:如果你找到了它的渲染——然后把它添加到你的表单/图表设置中,它会画得更快。但首先要仔细检查以确保您没有处于远程桌面模式。

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

我假设您使用的是winform应用程序:

使用serialPort组件:

  1. 配置其properties:(波特率、DataBits、StopBits、奇偶校验…)
  2. 使用它的event(DataReceived)来收集您的输入

您可以在循环中发送命令,并收集输入/在图表组件上绘制它们,大致如下:

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

我开发了一个类似的应用程序,显示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毫秒睡眠一次的线程(100毫秒适合我显示2秒的数据,但如果我想显示10秒,我需要将线程的睡眠时间增加到500毫秒)

 //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毫秒休眠一次

 private void AddDataThreadLoop()
    {
        while (!_shouldStop)
        {
            chChannels[1].Invoke(addDataDel);
            // Sleeep thread for 100ms
            Thread.Sleep(100); 
        }
    }

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