QCustomPlot大量的数据绘图

时间:2017-03-11 23:45:24

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

我正在尝试使用qcustomplot类在我的Qt Gui程序上绘制一些串行数据。当我尝试绘制100个数据/秒的低采样频率数据时,我没有遇到任何麻烦。该图非常酷,并且正在顺利地绘制数据。但在高达1000data /秒的采样率下,绘图仪成为串行读取功能的瓶颈。它减速连续有一个巨大的延迟,如设备之间4-5秒。直截了当,绘图仪无法达到数据流速度。那么,是否有任何我不知道的常见问题或任何建议?

我认识这些风俗,

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

qcustom图的2 fps是有限的。但应该有一个解决方案,因为NI LABVIEW可以毫不拖延地绘制高达2k的数据

3-在usb协议中设计一个新的虚拟串行设备。现在,我正在使用ft232rl串口转换为usb转换器。

4-改变编程语言。用于实时绘图的C#或java中的情境和类支持是什么? (我知道这就像一个孩子说的,但这是在其他语言中体验的借口)

我的串口设备发送数据功能(实验中没有严重编码的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;

}

1 个答案:

答案 0 :(得分:1)

快速回答:

你试过了吗?

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

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

更长的回答:

我对你的代码的感觉是,你正在尝试重新绘制,以便获得“实时”情节。但如果您使用的是具有桌面操作系统的PC,则不会有实时的事情。

你应该关心的是:

  • 确保读取/写入串行端口的代码不会延迟太多。关于连接的硬件,“太多”将被解释。如果它真的具有时间关键性(这似乎是你的情况),你必须优化你的读/写函数,并最终将它们放在一个线程中。这可以为该线程保留一个完整的硬件CPU核心。
  • 确保图表图表的刷新速度足以让人眼看到。每次收到单个数据点时都不需要进行完全重新绘制。

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

  

1-将整个程序分配给2或3个线程。例如,串行部分   在一个线程中运行并绘制部分在另一个线程和两个线程中运行   线程与QSemaphore进行通信

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

  

4-改变编程语言。什么是情况和阶级   在C#或java中支持实时绘图? (我知道这就像个孩子   说,但这是在其他语言中经验丰富的pretex)

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