QCustomPlot使用心得四:动态曲线和绘图效率测试
转自:https://blog.csdn.net/yxy244/article/details/100099876
一、先看官方例子
https://www.qcustomplot.com/index.php/demos/realtimedatademo:
头文件添加:
1 QTimer dataTimer; 2 private slots: 3 void realtimeDataSlot();
构造函数里:
QCustomPlot* customPlot = ui->customPlot_7; customPlot->addGraph(); customPlot->graph(0)->setPen(QPen(QColor(40, 110, 255)));//曲线1蓝色 customPlot->addGraph(); customPlot->graph(1)->setPen(QPen(QColor(255, 110, 40)));//曲线2红色 //坐标轴使用时间刻度 QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); timeTicker->setTimeFormat("%h:%m:%s"); customPlot->xAxis->setTicker(timeTicker); //四边安上坐标轴 customPlot->axisRect()->setupFullAxesBox(); //设置y轴范围 customPlot->yAxis->setRange(-1.2, 1.2); // 使上下轴、左右轴范围同步 connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange))); connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange))); //定时器连接槽函数realtimeDataSlot connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); dataTimer.start(0); // 间隔时间 0ms表示尽可能快的触发
realtimeDataSlot函数:
1 2 void MainWindow::realtimeDataSlot() 3 { 4 QCustomPlot* customPlot = ui->customPlot_7; 5 static QTime time(QTime::currentTime()); 6 7 double key = time.elapsed()/1000.0; // 开始到现在的时间,单位秒 8 static double lastPointKey = 0; 9 if (key-lastPointKey > 0.002) // 大约2ms添加一次数据 10 { 11 // 添加数据到graph 12 customPlot->graph(0)->addData(key, qSin(key)+qrand()/(double)RAND_MAX*1*qSin(key/0.3843)); 13 customPlot->graph(1)->addData(key, qCos(key)+qrand()/(double)RAND_MAX*0.5*qSin(key/0.4364)); 14 //记录当前时刻 15 lastPointKey = key; 16 } 17 // 曲线能动起来的关键在这里,设定x轴范围为最近8个时刻 18 customPlot->xAxis->setRange(key, 8, Qt::AlignRight); 19 //绘图 20 customPlot->replot(); 21 //计算帧数 22 static double lastFpsKey; 23 static int frameCount; 24 ++frameCount; 25 if (key-lastFpsKey > 2) // 每2秒求一次平均值 26 { 27 //状态栏显示帧数和数据总数 28 ui->statusBar->showMessage( 29 QString("%1 FPS, Total Data points: %2") 30 .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) 31 .arg(customPlot->graph(0)->data()->size()+customPlot->graph(1)->data()->size()) 32 , 0); 33 lastFpsKey = key; 34 frameCount = 0; 35 } 36 }
滚动曲线的关键是改变轴范围,调用
void QCPAxis::setRange (double position, double size, Qt::AlignmentFlag alignment )
第一个参数是轴所在位置,size定义轴范围的数据点个数,第三个是轴的对齐方式,可以是Qt::AlignLeft、Qt::AlignRight或Qt::AlignCenter。
在这里每次添加数据后调用一次setRange(key, 8, Qt::AlignRight),最新的数据的key值当做轴显示在右边,原来最左边的数据被挤了出去,看起来曲线整体向左移了,因为x轴设置为时间刻度,所以显示的范围是8秒。
二、绘图性能测试
官网的例程有个不好的地方,曲线刷新太频繁了,现实中显示器刷新率一般60Hz,而电影一般才24帧,所有没必要每添加一个数据就刷新一次,可以采用定时刷新,控制帧数在60帧内就行了,这里做个测试,看看QCustomPlot的性能如何。
博主的电脑CPU是渣渣的I5 6200U,直接先看测试结果:
(1)1条曲线性能很好,每帧10万点还能保持60fps,1百万的时候有50多的fps
(2)5条曲线每帧50万点数据大概有四五十fps
(3)20条曲线的时候fps下降得厉害,每帧10多万点就40的fps,加到每帧200万点就只有26fps了
(4)窗口尺寸对性能影响巨大,绘制5条曲线,在小尺寸下能保持60fps,但是拉大后fps下降得厉害
结论:
绘制动态曲线,在曲线数很少的情况下效率很高,即使百万级也不卡顿,曲线数多了会影响性能;窗口尺寸对性能影响很大,尺寸越大性能下降得厉害。
添加数据和重绘分开,使用定时重绘,重绘时调用customPlot->replot(QCustomPlot::rpQueuedReplot),而不是replot(),这样就可以避免多次重复的绘制。
上述测试代码:
界面两个spinbox,两个button
头文件
1 QTimer rePlotTimer; 2 QTimer dataTimer; 3 bool m_start; 4 int m_countGraph; 5 private slots: 6 void timeToAddData(); 7 void timeToRePlot(); 8 void on_pushButton_clicked(); 9 void on_btn1_clicked();
开始按钮槽函数:
1 void MainWindow::on_btn_start_clicked() 2 { 3 QCustomPlot* customPlot = ui->customPlot_7; 4 5 if(!m_start) 6 { 7 customPlot->clearGraphs();//清除所有graph 8 m_countGraph = ui->spinBox1->value(); 9 QPen pen; 10 pen.setWidth(1); 11 //添加曲线 12 for(int i=0;i<m_countGraph;i++) 13 { 14 customPlot->addGraph(); 15 //颜色随机 16 pen.setColor(QColor(qrand()%150+100,qrand()%150+100,qrand()%150+100)); 17 customPlot->graph(i)->setPen(pen);// 18 } 19 //设置y轴范围 20 customPlot->yAxis->setRange(-1, m_countGraph*2); 21 //设置x轴范围 22 int size = ui->spinBox2->value(); 23 customPlot->xAxis->setRange(0, size, Qt::AlignRight); 24 //定时添加和刷新数据 25 rePlotTimer.start(16); // 间隔16ms刷新一次 26 dataTimer.start(5); // 间隔时间5ms添加一次数据 27 m_start = true; 28 ui->btn_start->setText("停止"); 29 } 30 else 31 { 32 rePlotTimer.stop(); // 停止重绘 33 dataTimer.stop(); // 停止添加数据 34 m_start = false; 35 ui->btn_start->setText("开始"); 36 } 37 }
添加数据按钮槽函数:
void MainWindow::on_btn_adddata_clicked() { QCustomPlot* customPlot = ui->customPlot_7; //x轴范围点数 int size = ui->spinBox2->value(); for(int i=0;i<customPlot->graphCount();i++)//添加x轴范围的点数,使波形占满画面 { for(int j=0;j<size;j++) { customPlot->graph(i)->addData(customPlot->graph(i)->dataCount(),qrand()/(double)RAND_MAX + i*2); } } }
定时添加数据:
void MainWindow::timeToAddData() { QCustomPlot* customPlot = ui->customPlot_7; QTime time= QTime::currentTime(); qsrand(time.msec()+time.second()*1000);//种子 for(int i=0;i<customPlot->graphCount();i++) { for(int j=0;j<10;j++)//每次添加10个数据 { customPlot->graph(i)->addData(customPlot->graph(i)->dataCount(),qrand()/(double)RAND_MAX + i*2); } } }
定时重绘:
1 void MainWindow::timeToRePlot() 2 { 3 static QTime time(QTime::currentTime()); 4 double key = time.elapsed()/1000.0; // time elapsed since start of demo, in seconds 5 6 QCustomPlot* customPlot = ui->customPlot_7; 7 int size = ui->spinBox2->value(); 8 9 customPlot->xAxis->setRange(customPlot->graph(0)->dataCount(), size, Qt::AlignRight); 10 //重绘 11 customPlot->replot(QCustomPlot::rpQueuedReplot); 12 //customPlot->replot(); 13 static double lastFpsKey; 14 static int frameCount; 15 ++frameCount; 16 if (key-lastFpsKey > 1) // 每1s求一次值 17 { 18 int displaySize = ui->spinBox2->value();//单条显示点数 19 int datasize = customPlot->graph(0)->data()->size();//单条数据总数 20 int graphCount= m_countGraph;//曲线条数 21 long displaytotal=displaySize*graphCount;//显示总数 22 long datatotal=datasize*graphCount;//数据总数 23 QString str_displaytotal; 24 QString str_datatotal; 25 //显示的总数不会超过实际点数 26 if(displaytotal > datatotal) 27 { 28 displaytotal = datatotal; 29 } 30 //显示点数加单位更直观 31 if(displaytotal>=1e6)//百万级 32 { 33 str_displaytotal = QString("%1百万").arg(displaytotal/1000000.0,0,'f',2); 34 } 35 else if(displaytotal>=1e4)//万级 36 { 37 str_displaytotal = QString("%1万").arg(displaytotal/10000.0,0,'f',2); 38 } 39 else 40 { 41 str_displaytotal=QString("%1").arg(displaytotal); 42 } 43 //总数加单位更直观 44 if(datatotal>=1e6)//百万级 45 { 46 str_datatotal = QString("%1百万").arg(datatotal/1000000.0,0,'f',2); 47 } 48 else if(datatotal>=1e4)//万级 49 { 50 str_datatotal = QString("%1万").arg(datatotal/10000.0,0,'f',2); 51 } 52 else 53 { 54 str_datatotal=QString("%1").arg(datatotal); 55 } 56 ui->statusBar->showMessage( 57 QString("FPS:%1,显示总数:%2*%3=%4,数据总数:%5*%6=%7") 58 .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) 59 .arg(displaySize) 60 .arg(graphCount) 61 .arg(str_displaytotal) 62 .arg(datasize) 63 .arg(graphCount) 64 .arg(str_datatotal) 65 , 0); 66 lastFpsKey = key; 67 frameCount = 0; 68 } 69 }
三、使能opengl
QCustomPlot有opengl功能,想试下GPU加速绘图的效果。
按照提示添加 DEFINES += QCUSTOMPLOT_USE_OPENGL到pro文件,
代码里开启:customPlot->setOpenGl(true);
但是编译报错误
网友提示还要.pro里加入
1 win32:LIBS += -lOpengl32\ 2 -lglu32 \ 3 -lglut
调试输出显示是否开启了opengl
qDebug()<<"opengl:"<<customPlot->openGl();
glut库要下载的,dll和lib添加到相应路径,有兴趣的试一下吧,博主就没试了。