[英]Effective way of reducing data for real-time plot
我正在Windows窗體(VC ++ 2010)中開發科學應用程序,它可以控制相對較新的電子設備。 我通過用C編寫的其他包裝庫來控制它。在初始設置所有參數之后,此應用程序將觸發設備中的測量。 然后,它以很高的速率向我的應用程序發送了超過20萬個int樣本的海量數據-假設它是每秒50個數據集。
現在,我需要使用Windows Forms圖表實時繪制數據。 最好以大約30 FPS的速率在圖表內繪制750個樣本。 我遇到的問題在於快速減少數據庫而又不損失繪圖可靠性的算法。
我的想法(數據在值127附近波動):
僅選擇每(200 000/750)點即可選擇750點
分組數據並計算平均值
對數據進行分組,然后選擇最大值或最小值(基於整個組的放置-如果它們中的大多數大於127-選擇最小值,否則選擇最大值)。
考慮到我必須以實時速度繪制數據並且在出現任何重要信號(看起來像一種變窄的調制正弦波)的地方,不要遺漏斑點,這些解決方案中的哪一個(如果有)是最好的? 有沒有更好的辦法?
最后一個問題:考慮到我始終具有相同的收集數據緩沖區(設備只是不斷用新數據覆蓋該緩沖區),我是否應該考慮將指向大型數據緩沖區或數據副本的指針表用作繪圖數據?
這是我的第一篇文章,因此,如果有任何錯誤,請告知我。
我開發了一個應用程序,可以從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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.