减少实时绘图数据的有效方法

时间:2015-04-17 22:05:55

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

我正在开发Windows Forms(VC ++ 2010)中的科学应用程序,它控制相对较新的电子设备。我通过用C编写的附加包装库来控制它。在初始设置所有参数之后,该应用程序触发设备中的测量。然后,它以极高的速率向我的应用程序发送超过200k的int样本的巨大数据 - 让我们假设它是每秒50个数据集。

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

我的想法(数据在值= 127附近振荡):

  1. 选择每个(200 000/750)点

  2. 选择750点
  3. 将数据分组并计算平均值

  4. 对数据进行分组并选择最大值或最小值(基于整体群组展示位置 - 如果其中大部分位于127以上 - 请选择最小值,否则为最大值)。

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

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

    这是我的第一篇文章,所以请告知我帖子的风格是否有什么问题。

1 个答案:

答案 0 :(得分:1)

我开发了一个应用程序,它从16个通道读取256Hz(256个样本/秒)的数据,并将其显示在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 ms休眠

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