【问题标题】:Effective way of reducing data for real-time plot实时绘图减少数据的有效方法
【发布时间】:2015-06-24 22:53:43
【问题描述】:

我正在 Windows 窗体 (VC++ 2010) 中开发科学应用程序,它控制相对较新的电子设备。我通过用 C 编写的附加包装库来控制它。在初始设置所有参数后,此应用程序会触发设备中的测量。然后,它以显着的速度向我的应用程序发送超过 20 万个 int 样本的海量数据——假设它每秒发送 50 个数据集。

现在,我需要使用 Windows 窗体图表以实时速度绘制我的数据。以大约 30 FPS 的速率在图表内绘制 750 个样本将是完美的。我遇到的问题在于在不损失情节可靠性的情况下快速减少数据库的算法。

我的想法(数据在 value = 127 附近波动):

  1. 只需选择每 (200 000/ 750) 个点即可选择 750 个点

  2. 对数据进行分组并计算平均值

  3. 对数据进行分组并选择最大值或最小值(基于整体组的位置 - 如果它们中的大多数都高于 127 - 选择最小值,否则选择最大值)。

考虑到我必须以实时速度绘制数据并且绘图不应错过任何重要信号(看起来像一种变窄的调制正弦波)的点,这些解决方案中的哪一个(如果有)是最好的)?有没有更好的方法?

最后一个问题:考虑到我总是有相同的收集数据缓冲区(设备只是用新数据不断覆盖这个缓冲区),我是否应该考虑使用指向我的巨大数据缓冲区或数据副本的指针表作为绘图数据?

这是我的第一篇文章,所以如果文章风格有任何问题,请告诉我。

【问题讨论】:

    标签: c++ winforms visual-c++ plot real-time


    【解决方案1】:

    我开发了一个应用程序,它以 256Hz(256 个样本/秒)的频率从 16 个通道读取数据,并将其显示在 16 个不同的图表中。实时绘制所有数据的最佳方法是使用单独的线程来更新绘图。这是可能对您也有用的解决方案(在 c# 中)。

    读取新数据时,数据存储在列表或数组中。由于是实时数据,所以这里也会生成时间戳。使用采集数据的采样率: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 毫秒休眠一次

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

    数据将每 100 毫秒添加到图表中

    private void AddData()
        {
            // Copy data stored in lists to arrays
            float[] rawData;
            DateTime[] xValues;
    
                if (_bufferRawData.Count > 0)
                {
                    // Copy buffered data in thread-safe manner
                    lock (_bufferRawData)
                    {
                        rawData = _bufferRawData.ToArray();
                        _bufferRawData.Clear();
                        xValues = _bufferXValues.ToArray();
                        _bufferXValues.Clear();
                    }
    
                    for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
                    {
                            foreach (Series ptSeries in chChannels[channelIdx].Series)
                                // Add new datapoint to the corresponding chart (x, y, chartIndex, seriesIndex)
                                AddNewPoint(xValues[sampleIdx], rawData[sampleIdx], ptSeries);
               }
          }
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-18
      • 2020-05-06
      • 2011-10-04
      • 2014-06-29
      • 1970-01-01
      相关资源
      最近更新 更多