PDA

View Full Version : Incremental Spectrogram...



uppu
18th November 2009, 13:04
Hi friends,

My problem:
1) Draw a spectrogram for too big quantity data.
2) Initial window size(resolution) is fixed.
2) The actual window size would be growing continuously along x-axis.
3) The New data will be available at certain intervals of time say for every one minute.
4) meanwhile some curves have to be drawn over this spectrogram.

My idea is :
1) Render the spectrogram for the only available window at a time.
2) When a new data comes, render only new data image, as we have already rendered the previous data.


The idea sounds cool (?) I started implementing same,
1) I started a QTimer and set the interval as per the need.
2) call QwtPlotSpectrogram::setData(QwtRasterData());
3) while setting the new data in the timeout event, I would consider
both previous data and the new data at that interval.
3) This works fine initially, but later when the data becomes too much, performance sucks :(

That is because
1) Each time I call QwtPlotSpectrogram::setData(), it will re-render the complete image for the time(0) till the current time. that means
2) If I render the data for two hours the complete two hours data has to be re-rendered every time I (re) set the new data.

MyQuestion:
1) Is there a way in QwtPlotSpectrogram to improve the performance by rendering only the new data to end of the previous image?

2) Is there any other idea to solve the original problem?

I saw the realtime_plot example but it renders a curve incrementally, but in this case it is a spectrogram, so it wont apply here :(

somebody (Uwe: you would know it better), please reply?

uppu
18th November 2009, 15:28
friends, from the diskussions in the forum so far, I understand I should use the
QwtRasterData:: boudingRect()

this would optinmize my rendering to some extent...

How to evaluate the amount of rectangle for my data?

Should I consider the x-axis maximum length and the data resolution and according to these 2 factors, I should return the new boundingRect?


UWE:: please reply?

Uwe
19th November 2009, 08:48
Derive from QwtPlotSpectrogram and reimplement YourSpectrogram::renderImage().

For the first image render for the complete area ( calling QwtPlotSpectrogram::renderImage() ) and store image + area. For the following images only render the additional area and merge it manually with the previous image.

Uwe

uppu
20th November 2009, 07:52
Uwe, thank you for your answer.

I was trying to implement this login, but couldn't get the idea about how to implement it.

For instance,
1) when the window is resized the image is rerendered, in such cases, if I Cache the previous image, it would effect the image quality.

2) If I incrementaly append the image, I was wondering how would it effect zooming? Would zooming work normalli still?

3) Is there a way to set the effective rectangle size so that only that part of the image is renderred?

uppu
8th December 2009, 15:40
Uwe,

I render the part of the new data and append it to my own cached image,

What I did was , every time I call
"QwtSpectrogram::renderImage()"

I adjust the "area" that I pass to this method according to the data available.

and obtain the new image and according to this image width, I would move the offset in the cached image, and before moving the offset I am appending tthis new image to the cached image.

I see, after some time the the image rendered goes ahead of its corresponding time axis range. :(

Uwe..Please reply..if you wont reply...i've to rewrite everything on my own

uppu
9th December 2009, 09:11
Uwe, Sorry It was my mistake.. I got it already

m15ch4
19th August 2010, 20:49
uppu could you share your code?

m15ch4

AndiTheCoder
7th April 2011, 12:05
Hello everyone!

This is the very first time I write on a forum, so please excuse me for any mistakes, thank you!

I thought my question will fit best to this thread.

I need help with the QwtPlotSpectrogram.

For background:
I need a QwtPlotSpectrogram with a pixel size of ca. 660x220 pixels.
This spectrogram is fed every 8ms (125Hz) with new data (by the QwtRastaData::value(x, y) function).
So the plot shall grow within 10 seconds over the given pixel width (660 pixels).

And here is the problem. The performance is very bad. It takes about 18 seconds (or longer :( ) to draw the whole spectrogram every 8ms.

I tested different things since two weeks!

- I have reimplemented the QwtPlotSpectrogram::renderImage to render not the whole image every time; only new data (I changed the y-x-loop; only 20 pixels per line to paint). but the replot() of the plot takes still to long time.
So I gave the canvas()->repaint() function a smaller QRect to paint the same are which is represented by the renderImage y-x-loop. Without any success.
(the size of the rectangle doesn't matter, the time it takes is approx. always the same)

- I tried to start the replot() function in a thread. But it is not allowed by Qt.

- I commented all content of the renderImage function, so the y-x-loop is not called any longer. So no data information was painted on the plot (is clear) but the strange things is:
the replot() function will take still a long time. Why??

Is there any possibility to draw a spectrogram with this size in such a short time? And if YES, how?
Or better: is it possible to draw only parts of a spectrogram? (only new data) -> how to get the repaint() function with a given QRect syncronized with y-x-loop of the renderImage function?

A thing I will not really understand is the caching. How does it work with the spectrogram? Is there any chance to get this what I need?

So lots of things I ask! If you have the time and desire please wrote back!

I will thank you in advance for your answers!!

Best regards

P. S. I am using the version 5.2.1 of the qwt library and Ubuntu 9.04 (32bit)

Uwe
8th April 2011, 07:13
And here is the problem. The performance is very bad. It takes about 18 seconds (or longer :( ) to draw the whole spectrogram every 8ms.
Always decouple the refresh rate of the plot from the sample rate, what means to start a timer with a reasonable interval ( 8ms is completely unrealistic and nobody needs this ) where you plot all samples, that have been collected in the meantime.

Collecting the samples could be done in a thread. See the oscilloscope example ( Qwt 6 ).


I have reimplemented the QwtPlotSpectrogram::renderImage to render not the whole image every time;
Reducing the number of pixels will have a linear effect. If it is possible it is a good idea to improve the performance.


I tried to start the replot() function in a thread. But it is not allowed by Qt.
But rendering the image is something, that can be done by several threads. See QwtPlotSpectrogram::setRenderThreadCount() in Qwt 6.


Is there any possibility to draw a spectrogram with this size in such a short time?
No and it is completely pointless to try so.

For human eyes a refresh rate of 50 Hz is fine - a rate of 25 Hz is still o.k. But in your situation of a growing spectrogram - where only a small part of the image is changing - I don't see the requirement for more than something like 5Hz.



Or better: is it possible to draw only parts of a spectrogram?

Yes it is and I would expect, that you could have very high refresh rates this way - but first get the other things right before you start with optimizations like this.

Uwe

AndiTheCoder
9th April 2011, 09:11
Hello Uwe,

thank you for your very fast and very good answers!

I will look at the examples in qwt6.

I think I understand what you mean. I have to collect the data first with my sample rate (= 8ms) in a buffer and than for example every 40ms (25Hz) this data have to be painted at once.

All right. this is possible with a "normal" QwtPlotCurve. There I can draw() data from and to. But how to do this with a spectrogram?

In the past I started with the data_plot example. And there for refreshing the plot the replot() function is called inside the timerEvent() funktion every time-event. So I have taken this approach for my development.

In the oscilloscope example of qwt6 I can use things better for me. Thank you for that!

All right, I will see what I can do with your suggestions.

When will the qwt6 be finished? Or is the rc5 stable enough?

Thank you Uwe and have a nice weekend!!

Andreas

Uwe
11th April 2011, 06:46
All right. this is possible with a "normal" QwtPlotCurve. There I can draw() data from and to. But how to do this with a spectrogram?

Derive from QwtPlotSpectrogram and introduce a QImage, where you collect your increasing values. Whenever you want to add new values call QwtPlotSpectrogram::renderImage with a painter initialized with your image and for the new area only.

Then overload YourPlotSpectrogram::renderImage returning parts of your image instead of rendering it ( don't call this one for the image composition above ).

When you want to paint new parts of your spectrogram on screen do something like this:


QRectF newArea = ...; //
QRectF rect = QwtScaleMap::transform(
spectrogram->canvasMap( QwtPlot::xBottom),
spectrogram->canvasMap( QwtPlot::yLeft ),
newArea );
plot->canvas()->repaint( rect );



When will the qwt6 be finished? Or is the rc5 stable enough?

Use SVN trunk - this is planned to be the final version of Qwt 6.

Uwe

AndiTheCoder
13th April 2011, 13:47
Hello Uwe,

good news! I have separated sampling (with threading!) from refreshing the plot(s) and it runs very good!

I have not to draw only parts of a curve because the sampling data are saved in the yData of the QwtPlotCurve directly. So every replot() (by now only with 25Hz) all sampled data will be displayed at once. So there is also enough time to update the (whole) spectrogram with 25Hz.

The step updating to Qwt6 is not easy for me. Many functions I use aren't available any more (e. g. QwtPlot::print(); also the QwtPlotSpectrogram class has changed).

But thank you very much for helping me! And if I will have another problem I will post it in this forum.

Thanks and Servus :)

Andreas