Results 1 to 11 of 11

Thread: Slow plotting of spectrogram

  1. #1
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Slow plotting of spectrogram

    Hello, i am new in qwt.
    My task is plotting data on the spectrogram that come by timer.
    For this purpose, I used the example "realtime" in qwt.
    At the moment, I'm drawing a spectrogram (data come every 50ms, size of frame 100 points) by adding a new area:
    QRect newArea(QPoint( pointX * 100 , pointY ),QSize(100,1));
    QRectF rect = QwtScaleMap::transform(
    canvasMap( QwtPlot::xBottom),
    canvasMap( QwtPlot::yLeft),
    newArea );
    canvas()->repaint(rect.toRect());
    But there is a problem with the speed of data rendering on spectrogram. The schedule is not drawn with the necessary speed.
    I do not draw on the full screen. Size of plot is 1000 points on x-axis by 500 on y-axis (but size can be 10000 points on x-axis by 5000 on y-axis).
    When drawing on the full screen the speed of data rendering on spectrogram decreases even more.

    How can I solve this problem?
    May be <qwt_plot glcanvas.h> can help me?
    I looked at the topic http://www.qtcentre.org/archive/index.php/t-25795.html. But I did not understand how to use the overload PlotSpectrogram :: renderImage.

    Here is my code that is responsible for plotting:

    1. incrementalplot.h:

    #include <qwt_plot.h>

    class QwtPlotSpectrogram;

    class IncrementalPlot : public QwtPlot
    {
    Q_OBJECT

    public:
    IncrementalPlot( QWidget *parent = NULL );
    virtual ~IncrementalPlot();
    QwtPlotSpectrogram *d_curve;

    void appendPoints( const double, const double );
    };


    2. incrementalplot.cpp:

    #include "incrementalplot.h"
    #include <qwt_plot.h>
    #include <qwt_plot_canvas.h>
    #include <qwt_raster_data.h>
    #include <qwt_matrix_raster_data.h>
    #include <qwt_plot_spectrogram.h>
    #include <qwt_painter.h>
    #include "color.h"

    class CurveData: public QwtMatrixRasterData
    {

    public:
    double *dataCscan;
    int numberOfScansInCscan;
    CurveData()
    {
    //size
    numColumns = 1000;
    numRaws = 500;
    numColors = 100;
    //counters
    numberOfScansInCscan = 0;
    //vector and matrix
    QVector <double> values(numColumns*numRaws,0);
    dataCscan = values.data();
    setValueMatrix( values, numColumns );
    //intervals
    setInterval( Qt::XAxis,QwtInterval( 0, numColumns, QwtInterval::ExcludeMaximum ) );
    setInterval( Qt::YAxis,QwtInterval( 0, numRaws, QwtInterval::ExcludeMaximum ) );
    setInterval( Qt::ZAxis, QwtInterval( 0, numColors ) );
    }
    //size variables
    int numColumns;
    int numRaws;
    int numColors;
    //task matrix size
    void setMatrixSize()
    {
    QVector <double> values(numColumns*numRaws,0);
    dataCscan = values.data();
    setValueMatrix( values, numColumns );
    }

    void clearNumber()
    {
    numberOfScansInCscan = 0;
    }

    public:
    //set new data
    void rasterDataUpdate()
    {
    if (numberOfScansInCscan == numColumns*numRaws) qDebug() << "limit exceeded";
    else
    {
    for (int i = 0; i < 100; i++)
    dataCscan [ i + numberOfScansInCscan ] = i;
    numberOfScansInCscan += 100;
    }
    }
    };

    IncrementalPlot::IncrementalPlot( QWidget *parent ):
    QwtPlot( parent ),
    d_curve( NULL )
    {
    if ( QwtPainter::isX11GraphicsSystem() )
    {
    canvas()->setAttribute( Qt::WA_PaintOnScreen, true );
    }
    //set curve
    d_curve = new QwtPlotSpectrogram();
    d_curve->setData( new CurveData() );
    //set colormap
    Color *color = new Color();
    d_curve->setColorMap(color);

    d_curve->attach( this );

    setAutoReplot( false );
    }

    IncrementalPlot::~IncrementalPlot()
    {
    delete d_curve;
    }

    //append new points on curve
    void IncrementalPlot::appendPoints( const double pointX, const double pointY)
    {
    CurveData *data = static_cast<CurveData *>( d_curve->data());
    data->rasterDataUpdate();
    const bool doClip = !canvas()->testAttribute( Qt::WA_PaintUnclipped );
    //repaint part of graph
    if ( doClip )
    {
    QRect newArea(QPoint( pointX * 100 , pointY ),QSize(100,1));
    QRectF rect = QwtScaleMap::transform(
    canvasMap( QwtPlot::xBottom),
    canvasMap( QwtPlot::yLeft),
    newArea );
    canvas()->repaint(rect.toRect());
    }
    }

    3. plot.h

    #include "incrementalplot.h"
    #include <qdatetime.h>

    class RandomPlot: public IncrementalPlot
    {
    Q_OBJECT

    public:
    RandomPlot( QWidget *parent );

    virtual QSize sizeHint() const;

    //counter and variables for coordinates
    int count;
    double x;
    double y;

    public Q_SLOTS:
    void stop();
    void resetCount();

    private Q_SLOTS:
    void appendPoint();
    };

    4. plot.cpp

    #include "plot.h"
    #include <qglobal.h>
    #include <qwt_plot_grid.h>
    #include <qwt_plot_canvas.h>
    #include <qwt_plot_layout.h>
    #include <qwt_scale_widget.h>
    #include <qwt_scale_draw.h>
    #include <qwt_plot_curve.h>
    #include "qwt_symbol.h"

    const unsigned int c_rangeMax = 1000;

    RandomPlot::RandomPlot( QWidget *parent ):
    IncrementalPlot( parent )
    {
    setFrameStyle( QFrame::NoFrame );
    setLineWidth( 0 );

    plotLayout()->setAlignCanvasToScales( true );

    QwtPlotGrid *grid = new QwtPlotGrid;
    grid->setMajorPen( Qt::gray, 0, Qt:otLine );
    grid->attach( this );

    setCanvasBackground( QColor( 29, 100, 141 ) );

    setAxisScale( xBottom, 0, c_rangeMax );
    setAxisScale( yLeft, 0, c_rangeMax/2 );

    //set coordinates and count
    count = 0; x = 0; y =0;

    //canvas
    QwtPlotCanvas *plotCanvas = qobject_cast<QwtPlotCanvas *>( canvas() );
    plotCanvas->setPaintAttribute( QwtPlotCanvas::BackingStore, false );
    replot();
    }

    QSize RandomPlot::sizeHint() const
    {
    return QSize( 540, 400 );
    }

    //set x and y position, append points on curve
    void RandomPlot::appendPoint()
    {
    if ( count % 10 == 0)
    {
    y++;
    x = 1;
    }
    else x++;
    IncrementalPlot::appendPoints(x - 1, y - 1);
    count++;
    }

    //do not use
    void RandomPlot::stop()
    {
    QwtPlotCanvas *plotCanvas = qobject_cast<QwtPlotCanvas *>( canvas() );
    plotCanvas->setPaintAttribute( QwtPlotCanvas::BackingStore, true );
    }

    //do not use
    void RandomPlot::resetCount()
    {
    count = 0;
    x = 0;
    y = 0;
    }

    5. mainwindow.h

    #include <qmainwindow.h>
    #include <qaction.h>

    class QPushButton;
    class RandomPlot;

    class MainWindow: public QMainWindow
    {
    Q_OBJECT
    public:
    MainWindow();
    RandomPlot *d_plot;
    // start button
    QPushButton *button;
    };

    6.mainwindow.cpp

    #include "plot.h"
    #include "mainwindow.h"
    #include <QPushButton>

    MainWindow::MainWindow()
    {
    //start button
    button = new QPushButton("Paint");
    button->show();
    //spectrogram
    d_plot = new RandomPlot( this );
    const int margin = 4;
    d_plot->setContentsMargins( margin, margin, margin, margin );

    setCentralWidget( d_plot );
    }

    7. main

    #include "mainwindow.h"
    #include <QApplication>
    #include <QTimer>
    #include <QPushButton>
    #include "plot.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow *w = new MainWindow;
    //w->resize(500,300);
    QTimer *time = new QTimer;
    time->setInterval(50);
    QObject::connect(w->button, SIGNAL(clicked()), time, SLOT(start()));
    QObject::connect(time, SIGNAL(timeout()), w->d_plot, SLOT(appendPoint()));
    w->show();
    return a.exec();
    }

    8. colormap

    #include<qwt_color_map.h>
    class Color: public QwtLinearColorMap
    {
    public:
    Color(): QwtLinearColorMap(Qt::white, Qt::darkRed)
    {
    //set color
    addColorStop(0.10,Qt::blue);
    addColorStop(0.25,Qt::darkBlue);
    addColorStop(0.40,Qt::green);
    addColorStop(0.55,Qt::darkGreen);
    addColorStop(0.70,Qt::yellow);
    addColorStop(0.80,Qt::darkYellow);
    addColorStop(0.90,Qt::red);
    }
    };

    I apologize for such a big post.
    Thank you for attention, Anton

  2. #2
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,311
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Slow plotting of spectrogram

    A spectrogram creates an image from your data, by iterating over all pixels of the image, requesting the value from the data object and mapping it to a RGB value using a QwtColorMap. When having an image of 1000x1000 pixels, this is a loop of 10e6 values. The time for blitting the image to screen is no relevant factor then - what answers your question regarding OpenGL as being no optimzation.

    So it is about the number of pixels and of course what happens for each pixel. For reducing the number of pixels I see 2 options:

    Qt Code:
    1. QwtPlotRasterData::pixelHint()
    2. Incremental image composition
    To copy to clipboard, switch view to plain text mode 
    The pixelHint is useful, when the resolution of the data is below the resolution of the screen. In this case the spectrogram needs to calculate RGB values in data resolution only and can fill the other pixels.
    When using QwtMatrixRasterData the pixelHint is automatically calculated from the rows/columns, but your code totally disables this optimization by blowing up the data to 1000x500 data pixels manually. As you wrote that you never have more than 100 points per line this alone slows down the image composition by factor 10.

    In general I would throw away your code completely - and restart with a simple implementation without any optimization. Use only one spectrogram ( your code disables multi threading as a side effect ) and one QVector <double>, that you modify whenever data comes in. Then have a look what performance you have - maybe by enabling DEBUG_RENDER in qwt_plot_spectrogram.cpp.

    Maybe compare your results with the debug output of the spectrogram example. The numbers of your application should be significantly better ( because of the raster hint ) - if not something is totally wrong in your code.

    Then when starting with optimizing I recommend not to use QwtMatrixRasterData as you can avoid having to copy the incoming data by putting your own type of QwtPlotRasterData on top of your values. By the way: try to avoid iterating of the points, better use memcpy or methods of QVector based on memcpy.

    I would expect, that with removing your "optimizations" you will already have a significant better performance. If this is still not good enough we can have a look at the incremental image composition.

    Uwe

  3. The following user says thank you to Uwe for this useful post:

    Anton1 (18th August 2016)

  4. #3
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Slow plotting of spectrogram

    Thank you for your quick response Uwe!
    It helped me to solve the problem with the performance.

    I have a question about displaying (plotting) data. Resolution of the data is much higher then the resolution of the screen.
    Usually the date consists of a lot of low values (5 - 10) and rare single high values (90 - 100). When we display data on spectrogram we often do not see this peak (high value).

    Is it possible to do not lose these single maximums on the spectrogram?

    I am looking for an analouge for QwtPlotSpectrogram for method "setPoint Attribute (QwtPlotCurve :: FilterPoints, false)" that used for QwtPlotCurve to don't loose peaks?

  5. #4
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,311
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Slow plotting of spectrogram

    Quote Originally Posted by Anton1 View Post
    Is it possible to do not lose these single maximums on the spectrogram?
    This is a problem of the nearest neighbor resampling. It is very fast, but of course might miss peaks.

    QwtPlotMatrixData offers another resampling algo - interpolating between the samples - but it might be too expensive for your use case and you lose the pixel hint optimization. Guess you need to find your own strategy, but in any case you would have to overload:

    Qt Code:
    1. virtual double QwtRasterData::value( double x, double y );
    To copy to clipboard, switch view to plain text mode 

    But be careful: this method is called for each pixel of the image. Doing expensive operations here will slow down the image composition.

    Uwe

  6. #5
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Slow plotting of spectrogram

    Hello!

    After I changed the display to the one with higher resolution (1920 Ñ… 1080) the spectrogram slowed down.

    So now I'd like to return to the approach you suggesed erlier "Incremental image composition". Do I understand it right that it is possible to plot only part of the spectrogram OR to add data to the spectrogram?

    I looked at the topic "Incremental Spectrogram".
    I do not understand how to properly reimplement method QwtPlotSpectrogram::renderImage.

    For example, I have a spectrogram, filling from left to right by columns. I want to render only new part of the picture (Today for display I use overloading method QwtRasterData::value and replot all picture).
    1. What triggers the method QwtPlotSpectrogram::renderImage? Repaint, replot etc.? Or do I need to call it myself?
    2. How to set the return value in an overloaded method?
    3. Do I need an analog for method QwtRasterData::value,that i used when call replot?
    4. Can you provide a brief description of how to make incremental spectrogram data plotting?

    Thank you in advance.

  7. #6
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,311
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Slow plotting of spectrogram

    The very first thing I recommend to do is - again - enable DEBUG_RENDER in qwt_plot_spectrogram.cpp and check the time needed for your image composition.
    What type of values have been reported ( of course in release mode ) ?

    Uwe

  8. #7
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Slow plotting of spectrogram

    I set enable DEBUG_RENDER in qwt_plot_spectrogram.cpp.
    If the spectrogram takes nearly full screen, there is the following result - renderImage QSize(1818, 909) 179
    If the spectrogram takes small part of screen, there is the following result - renderImage QSize(705, 80) 11
    Initial screen resolution is 1920x1080. The data size exceeds the size of the spectrogram.
    Can you say what should be done?
    Thank you in advance.

  9. #8
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,311
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Slow plotting of spectrogram

    Quote Originally Posted by Anton1 View Post
    QSize(1818, 909) 179
    QSize(705, 80) 11
    With the spectrogram example I can see on my box ( i7-3770T CPU @ 2.50GHz with 4 cores ) values like:


    • QSize(484, 343) 3
    • QSize(1804, 1075) 27


    As my system is far away from being a burner I guess we are talking about some slow embedded device on your side ?
    To compare the systems: could you check the numbers of the spectrogram example on your box ?

    --

    Concerning the "Incremental image composition":

    Qt Code:
    1. class YourSpectrogram: public QwtPlotSpectrogram
    2. {
    3. ....
    4.  
    5. protected:
    6. virtual QImage renderImage(
    7. const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    8. const QRectF &area, const QSize &imageSize ) const override
    9. {
    10. if ( m_image.isNull() )
    11. {
    12. m_image = QwtPlotSpectrogram::renderImage(
    13. xMap, yMap, area, imageSize );
    14. }
    15. else
    16. {
    17. // find the new area, not being part of the previous image
    18. // and the width/height in pixels
    19.  
    20. subArea = ...;
    21. subImageSize = ...
    22.  
    23. QImage subImage = QwtPlotSpectrogram::renderImage(
    24. xMap, yMap, subArea, subImageSize );
    25.  
    26. // shift the pixels in m_image and copy in those from subImage
    27. m_image = ...
    28. }
    29.  
    30. return m_image;
    31. }
    32.  
    33. private:
    34. QImage m_image;
    35. };
    To copy to clipboard, switch view to plain text mode 
    HTH,
    Uwe

    PS: if you have a good example for a waterfall plot that could be used as an example ( no huge data files ) you could send me your slow implementation. I would do the optimized implementation then.

  10. #9
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Slow plotting of spectrogram

    Hello Uwe!
    In the spectrogram example I see values like: renderImage QSize(1745, 910) 36.
    My computer have parameters i7-3770 CPU @ 3.40GHz with 4 cores.
    I'm working on a model for a waterfall plot, I think that I can send it to you early next week.
    Thank you in advance.

  11. #10
    Join Date
    Aug 2016
    Posts
    6
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Slow plotting of spectrogram

    Good day, Uwe.
    I've done program that could be an example after some changes.
    I give a link to the archive: https://cloud.mail.ru/public/LPcx/a7VbvrFGx
    Now the program is running slowly, but I hope that it is possible to optimize.
    Thank you in advance.

  12. #11
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,311
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Slow plotting of spectrogram

    Not sure what this tarball is supposed to be - looks like some downstripped version of your application, but without doing anything. To be honest I was interested in some simple data factory, that can be used for a waterfall plot - and this part is unfortunately missing.

    But at least it shows the implementation of your SpectrogramData::value(), that explains why you have a worse image composition performance than the spectrogram example. Regardless of any further optimization I recommend to speed this one up. As it is called for every pixel it is worth to spend some time on writing it in a performant way.

    Uwe

Similar Threads

  1. MINI2440 ARM9, QGraphicsView Plotting slow
    By abhinit in forum Qt for Embedded and Mobile
    Replies: 0
    Last Post: 28th April 2011, 14:25
  2. Spectrogram
    By Ronayn in forum Qwt
    Replies: 4
    Last Post: 25th April 2011, 20:14
  3. get min and max value from spectrogram
    By rambo83 in forum Qwt
    Replies: 1
    Last Post: 2nd December 2009, 14:25
  4. qwt spectrogram example
    By rambo83 in forum Qwt
    Replies: 2
    Last Post: 17th November 2009, 21:13
  5. Spectrogram too slow
    By a_kaa in forum Qwt
    Replies: 2
    Last Post: 9th January 2009, 16:57

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.