我有一个采集设备,可以读取数据并将其添加到缓冲区。这是在一个单独的线程中完成的。一旦这个数据出列,我就设置了一个提升事件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();
答案 0 :(得分:0)
在不同的线程中绘制图表中的数据是一种很好的方法。
读取新数据时,数据存储在列表或数组中。由于它是实时数据,因此也会在此处生成时间戳。使用获取的数据的采样率: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);
}
}
}