C#实时绘制多个图表

C# Drawing multiple charts in real time

我有一个采集设备,可以读取数据并将其添加到缓冲区。这是在一个单独的线程中完成的。一旦这些数据出队,我设置了一个引发事件 OnDataRead() 的委托。

在我的信号监视器中,当接收到事件时,我想在多个图表中绘制数据(总共 16 个)。我成功绘制了第一个样本,但随后图表停止绘制数据,从第 16 个开始并逐步停止所有样本。这样做的正确方法是什么?我需要一个单独的线程吗?

接收带有数据的事件

    public void OnDataRead(object source, DataEventArgs e)
    {
        if (e.rawData.Length > 0)
        {
            AddData(e.rawData, e.numChannels, e.triggerEnabled);
        }
    }

在适当的图表中添加数据点

 private void AddData(float[] rawData, int numChannels, bool triggerEnabled)
    {
        //for (int i=0; i<chChannels.Count; i++)
       // {
            if (this.InvokeRequired)
            {
                SetAddDataCallback d = new SetAddDataCallback(AddData);
                this.Invoke(d, new object[] {rawData, numChannels, triggerEnabled})
                    ;
            }
            else
            {
                DateTime timeStamp = DateTime.Now;

                // Find the channel selected
                int channelIdx = 0; //boxChannelSelection.SelectedIndex;
                // Add new data points for the selected channel
                for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
                {
                    channelIdx = sampleIdx %(numChannels + 1);

                    if (triggerEnabled && (channelIdx != numChannels))
                    {
                        foreach (Series ptSeries in chChannels[channelIdx].Series)
                        {
                            AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
                        }
                    }
                    else if (!triggerEnabled)
                    {
                        foreach (Series ptSeries in chChannels[channelIdx].Series)
                        {
                            AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
                        }

                    }
                    }
                }
           // }
    }

在图表中绘制新数据点

 public void AddNewPoint(DateTime timeStamp, float yValue, int channel, System.Windows.Forms.DataVisualization.Charting.Series ptSeries)
        {

            ptSeries.Points.AddXY(timeStamp.ToOADate(), yValue);

            // Remove old datapoints if needed
            double removeBefore = timeStamp.AddSeconds((double)(8) * (-1)).ToOADate();
            while (ptSeries.Points[0].XValue < removeBefore)
            {
                ptSeries.Points.RemoveAt(0);
            }

            chChannels[channel].ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
            chChannels[channel].ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddSeconds(10).ToOADate();

            chChannels[channel].Invalidate();

在不同的线程中绘制图表中的数据是一种很好的方法。

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

数据将每 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);
           }
      }
 }