c++ - QCustomPlot 海量数据绘图

标签 c++ multithreading qt real-time-data qcustomplot

我正在尝试使用 qcustomplot 类在我的 Qt Gui 程序上绘制一些串行数据。当我尝试绘制低采样频率数据(例如 100 个数据/秒)时,我没有遇到任何问题。该图表真的很酷,并且可以顺利地绘制数据。但在每秒 1000 个数据的高采样率下,绘图仪会成为串行读取功能的瓶颈。它会减慢串行速度,与设备之间有 4-5 秒的巨大延迟。简单地说,绘图仪无法达到数据流速度。那么,有什么我不知道的常见问题或有什么建议吗?

我认为这些场景,

1- 将整个程序划分为 2 或 3 个线程。例如,串行部分在一个线程中运行,绘图部分在另一个线程中运行,两个线程与 QSemaphore 进行通信

qcustom 绘图的 2- fps 受到限制。但应该有一个解决方案,因为 NI LABVIEW 可以毫无延迟地绘制多达 2k 数据

3-设计一个新的USB协议(protocol)虚拟串口设备。现在,我使用 ft232rl 串口转 USB 转换器。

4-更改编程语言。 C# 或 java 中实时绘图的情况和类支持如何? (我知道这就像一个 child 说的,但这是在其他语言中体验的借口)

我的串口设备发送数据功能(实验用的是foo设备,没有认真编码)简单来说就是:

void progTask()
{

DelayMsec(1); //my delay function, milisecond

//read value from adc13
Adc13Read(adcValue.ui32Part);

sendData[0] = (char)'a';
sendData[1] = (char)'k';
sendData[2] = adcValue.bytes[0];
sendData[3] = (adcValue.bytes[1] & 15);

Qt程序读取函数是:

//send test data
UARTSend(UART6_BASE,&sendData[0],4);
}

union{
unsigned char bytes[2];
unsigned int intPart;
unsigned char *ptr;
}serData;

void MedicalSoftware::serialReadData()
{

    if(serial->bytesAvailable()<4)
    {
     //if the frame size is less than 4 bytes return and 
     //wait to full serial receive buffer
     //note: serial->setReadBufferSize(4)!!!!
     return;
    }

QByteArray serialInData = serial->readAll();

//my algorithm
if(serialInData[0] == 'a' && serialInData[1] == 'k')
{
    serData.bytes[0] = serialInData[2];
    serData.bytes[1] = serialInData[3];

}else if(serialInData[2] == 'a' && serialInData[3] == 'k')
{
    serData.bytes[0] = serialInData[0];
    serData.bytes[1] = serialInData[1];
}
else if(serialInData[1] == 'a' && serialInData[2] == 'k')
{
    serial->read(1);
    return;
}else if(serialInData[0] == 'k' && serialInData[3] == 'a')
{
    serData.bytes[0] = serialInData[1];
    serData.bytes[1] = serialInData[2];

}

plotMainGraph(serData.intPart);

serData.intPart = 0;
}

qcustom绘图设置功能是:

void MedicalSoftware::setGraphsProperties()
{
//MAIN PLOTTER
ui->mainPlotter->addGraph();
ui->mainPlotter->xAxis->setRange(0,2000);
ui->mainPlotter->yAxis->setRange(-0.1,3.5);
ui->mainPlotter->xAxis->setLabel("Time(s)");
ui->mainPlotter->yAxis->setLabel("Magnitude(mV)");
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime());
timeTicker->setTimeFormat("%h:%m:%s");
ui->mainPlotter->xAxis->setTicker(timeTicker);
ui->mainPlotter->axisRect()->setupFullAxesBox();

QPen pen;
pen.setColor(QColor("blue"));
ui->mainPlotter->graph(0)->setPen(pen);

dataTimer = new QTimer;
}

最后是绘图函数:

void MedicalSoftware::plotMainGraph(const quint16 serData)
{
static QTime time(QTime::currentTime());
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if(key-lastPointKey>0.005)
{

    double value0 = serData*(3.3/4096);
    ui->mainPlotter->graph(0)->addData(key,value0);
    lastPointKey = key;
}
ui->mainPlotter->xAxis->setRange(key+0.25, 2, Qt::AlignRight);
counter++;

        ui->mainPlotter->replot();
        counter = 0;

}

最佳答案

快速回答:

你尝试过吗:

ui->mainPlotter->replot(QCustomPlot::rpQueuedReplot);

根据文档,它可以在进行大量重新绘制时提高性能。

更长的答案:

我对您的代码的感觉是,您正在尝试尽可能频繁地重新绘制以获得“实时”绘图。但如果您使用的是带有桌面操作系统的 PC,则不存在实时性这样的东西。

您应该关心的是:

  • 确保读写串口的代码不会延迟太多。 “太多”是针对所连接的硬件来解释的。如果它确实对时间至关重要(这似乎是您的情况),您必须优化读/写函数并最终将它们单独放在一个线程中。这甚至可以为此线程保留完整的硬件 CPU 核心。
  • 确保图表的刷新速度足以满足人眼的需要。您不需要在每次收到单个数据点时都进行完整的重新绘制。

在您的情况下,您每秒收到 1000 个数据,这意味着每毫秒 1 个数据。这非常快,因为这超出了大多数桌面操作系统的默认计时器分辨率。这意味着在调用“serialReadData()”时,您可能会拥有多个数据点,并且您可以通过减少调用频率来优化它(例如,每 10 毫秒调用一次,每次读取 10 个数据点)。然后,您可以每 30 毫秒调用一次“replot()”,这将每次添加 30 个新数据点,与您的代码相比,每 30 毫秒跳过大约 29 个 replot() 调用,并为您提供约 30fps。


1- to devide whole program to 2 or 3 thread. For example, serial part runs in one thread and plotting part runs in another thread and two thread communicates with a QSemaphore

将 GUI 与串行部分分成 2 个线程是很好的,因为这样可以防止 GUI 中的瓶颈阻止串行通信。您也可以跳过使用信号量,而仅依赖 Qt 信号/槽连接(以 Qt::QueuedConnection 模式连接)。

4- to change programming language. What is the situation and class support in C# or java for realtime plotting? (I know it is like a kid saying, but this is a pretex to be experienced in other languages)

在最好的情况下,更改编程语言不会改变任何内容,也不会损害您的性能,尤其是当您使用未编译为 native CPU 指令的语言时。 另一方面,更改绘图库可能会改变性能。您可以查看Qt ChartsQwt 。我不知道它们与 QCustomPlot 相比如何。

关于c++ - QCustomPlot 海量数据绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42742033/

相关文章:

c++ - 如何将焦点设置在特定的小部件上

c++ - QT官方文档中为什么使用static_cast

c++ - 判断下面函数是否判断数组是否升序排列

c++ - 显式类型转换和多个简单类型说明符

java - 鉴于 jdk1.6 及更高版本中的 HashMaps 导致多线程问题,我应该如何修复我的代码

java - 如何临时将现场线程设为本地

java - 没有volatile的线程安全

c++ - 关于带有函数和数据的static关键字的问题

c++ - 哪些适用于 Windows 的 C++11 编译器支持新的类型特征,例如 "is_nothrow_move_constructible"?

c++ - 类型*元素容器的qt排序