我正在从实施桌面应用程序的人手中接管 C#代码,以便从串行端口中读取实时数据并显示它在图表中(使用图表类)。
代码似乎正在运行,但非常慢。它似乎是在4秒内(0.25Hz)更新图表一次。但是,我可以看到它是多线程的并且没有延迟命令,所以我不明白为什么它运行得如此之慢。图表的更新会减慢它吗?理想情况下,我希望实现每秒1000个数据点(1kHz),将其显示在实时并保存到硬盘,其中每个数据点的大小约为 30个字节。
我花了几天时间来理解代码,但是它太麻烦了,无法全部写在一个文件中,没有任何评论。 我的目标是每秒读取1000个数据点是否真实/可实现?
我还考虑重新编写代码(而不是尝试修复代码),考虑到它只有 2,500行长。任何提示将不胜感激。另外,如果我重写代码,该应用程序可能更适合哪种语言?
答案 0 :(得分:1)
我开发了一些代码,我得到了显着的性能提升,它可能对你有用。这是我做的 -
第1步:我首先要确定哪一个是瓶颈,drawing/rendering of the chart
或 serial port
步骤2:如果您找到了渲染 - 然后在表单/图表设置中添加它,它将绘制得更快。但首先请仔细检查以确保您不在远程桌面模式下。
<!-- language: c# -->
// No double buffering for remote, only local
public bool OptimizeOfLocalFormsOnly(System.Windows.Forms.Control chartControlForm)
{
if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
{
SetUpDoubleBuffer(chartControlForm);
return true;
}
return false;
}
public static void SetUpDoubleBuffer(System.Windows.Forms.Control chartControlForm)
{
System.Reflection.PropertyInfo formProp =
typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
formProp.SetValue(chartControlForm, true, null);
}
答案 1 :(得分:0)
我假设你使用winform应用程序:
使用serialPort
组件:
properties
:( BaudRate,DataBits,StopBits,Parity ...)event
(DataReceived)来收集您的输入。您可以循环发送命令并收集输入/在图表组件上绘制它们大致如下:
while(/*some condition*/)
{
serialPort.Write(/* your command */);
// you have to think of response time
// so implement something that waits a bit before calling the port again
// I would do it using timers
int tick= Environment.TickCount;
while(Environment.TickCount - tick <= 100) // wait 100 milliseconds
{
Application.DoEvents();
}
}
// collect the data as:
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// use according to your needs, for example
string data = "";
int readByte;
int available;
available = serialPort.BytesToRead;
if(available >= 30) // 30 bytes as stated in your question
{
for(int i=0; i<30; i++)
{
readByte = serialPort.ReadByte();
data += String.Format("{0:2X}", readByte);
}
// you can call some methods to save/display your collected data from here
save_to_file(data);
display_to_chart(data);
}
}
答案 2 :(得分:0)
我开发了一个类似的应用程序,我在那里显示16个图表* 256个样本/秒。将数据存储在缓冲区中并创建一个单独的线程来更新图表。
读取新数据时,数据存储在列表或数组中。由于它是实时数据,因此也会在此处生成时间戳。使用获取的数据的采样率: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);
}
}
AddData方法只读取存储在缓冲区中的X(时间戳)和Y值,并使用ptSeries.Points.AddXY(xValue,yValue)将其添加到图表中