Solved Using Qbuffer to store QVector
-
Hello Everyone,
Is it possible to use Qbuffer to store values of QVector?
The reason i need to do this is, need to plot data and the values are stored in qvector. However, there is a delay in plotting as I have connected the plot function using signals slots mechanism. so its not running smoothly. values are plotted and then qvector is filled again and then plotted and so on. I am 100% sure there are better ways to do this.
P.S: newbie alert :)
Thanks.
Espresso -
Hi,
Yes it's possible, you could also use a QQueue but what's your data source ? What are you using to do the plotting ?
-
Hi SGaist,
It is serial data coming from a device. It is processed and for displaying I am using qwt library. If you can spare some time, can you please elaborate as to how I can use buffer to store qvector data. I was looking into circular buffers as it seems promising.
As for using queues, Filling the queue will be done in a separate method and emptying the same queue for plotting will be done in a separate method. Will this work?
Many thanks for your reply.
Cheers,
Espresso -
What does you vector represent ? You could replace it with your ring buffer or QQueue.
That's the goal, it's generally used to pass data between two threads.
-
There are two vectors containing x and y values, which are to be plotted. x contains timestamps data was taken, y is data from sensor.
-
Then why not a QQueue with e.g. a QPair to contain your x and y values ?
-
@SGaist : Pseudo code is as:
class Plot{
//plots x,y using qwt lib//function receives x,y values from class sendData
//Stores the values in QPoint and then displays
};class sendData{
//gets data from serial
getSerial()
{
//read serial and store in qvector
//when qvector contains 1000 values send it to a processing function
arr* processData(qvector<int> data1, qvector<float>data2)
{
//do some processing and send 1000 values back using standard array.
}//append the 1000 values to qvector and send it to plotting class
for (int i = 0; i < qvector.length(); i++)
newQvector.append(std::array[i]);for (int i = 0; i < qvector.length(); i++)
{//send values to plot
thread.data1 = newQVector.at[i];
thread.data2 = TimeVector.at[i];
}}
};Now as the data is received real time and is implemented via signal slot. It means this method is called continuously and hence plot is not smooth due to the for loop. Please note that I need to store 1000 values and then send those to plotting method.
Can you please suggest improvements?
Cheers,
Espresso -
Don't try to plot huge amounts of data every second, you should batch them or depending on your use case consider OpenGL.
Also, check your data structures, can't you use only one ? Or at least data structures that make sense to avoid duplicating operation going back and forth.
Something that's a bit worrying:
thread.data1 = newQVector.at[i];
. Are you passing data to different threads directly ? -
@SGaist You are correct, I need to refactor as data structures need to be reduced. However I can not get my head around the idea of plotting values (1000) at the same time I receive them from a method in a separate class.
The plotting is not slow at all as plotting is done in a separate thread and data retrieval in a separate thread. Its like 1000 values are plotted and then** processing delay** and then 1000 values are plotted so on and so forth. I want to avoid the** processing delay** so that plotting is smooth. Something in the logic needs changing, i think.
Yes I am passing data to threads directly. Are you suggesting batch rendering with opengl?
Thanks for your time :)
P.S: processing delay = values are calculated and returned via a qvector containing 1000 values. This happens in a different thread from plotting thread.
-
No, I'm suggesting that you are playing with fire. Threading is a complex and vast topic and one of the crucial point is accessing data from several threads aka synchronization. Take a deep look at the subject before going further otherwise it will become a nightmare (no joke).
Before considering OpenGL ensure that your design is correct. If you need more power, then OpenGL might be a solution.
-
Thanks for your advice. I was looking into qwt oscilloscope example in order to understand threading. I have spent some days in order to understand this example. So far I have understood that samplingthread and signaldata classes are linked but i could not find the linkage between signaldata and plot class.
Below is class plot which is a display widget.
class Plot: public QwtPlot { Q_OBJECT public: Plot( QWidget * = NULL ); virtual ~Plot(); void start(); virtual void replot(); virtual bool eventFilter( QObject *, QEvent * ); public Q_SLOTS: void setIntervalLength( double ); protected: virtual void showEvent( QShowEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void timerEvent( QTimerEvent * ); private: void updateCurve(); void incrementInterval(); QwtPlotMarker *d_origin; QwtPlotCurve *d_curve; int d_paintedPoints; QwtPlotDirectPainter *d_directPainter; QwtInterval d_interval; int d_timerId; QwtSystemClock d_clock; };
Below is class samplingthread that sets frequency and amplitude obtained from other classes. (wheel and knob)
class SamplingThread: public QwtSamplingThread { Q_OBJECT public: SamplingThread( QObject *parent = NULL ); double frequency() const; double amplitude() const; public Q_SLOTS: void setAmplitude( double ); void setFrequency( double ); protected: virtual void sample( double elapsed ); private: virtual double value( double timeStamp ) const; double d_frequency; double d_amplitude; };``````
Below is the class signaldata, that gets the value from samplingthread and appends the data via instance method. How are the values in the instance method updated and shown on the plot class?
class SignalData { public: static SignalData &instance(); void append( const QPointF &pos ); void clearStaleValues( double min ); int size() const; QPointF value( int index ) const; QRectF boundingRect() const; void lock(); void unlock(); private: SignalData(); SignalData( const SignalData & ); SignalData &operator=( const SignalData & ); virtual ~SignalData(); class PrivateData; PrivateData *d_data; };``` Thank you for your time.
-
SignalData has a QReadWriteLock that gets locked for reading before the painting is done. That means that you can have as many threads as you want to read the data but nobody can write it during that time. The same holds for the write lock. That means that one thread can write to the variable and nobody can access it while writing.
-
Thanks. Just last question before I close this thread.
In the Oscilloscope example, I have tried to add marker points in the Plot::updateCurve() method. I want the markers to be displayed at the corresponding x and y values of input.
So far I have tried setting values using d_origin object (QwtPlotMarker) inside the Plot::updateCurve() but it does not work. The marker is displayed after the replot function is called whereas I want it to be displayed in continuous fashion, just like curve.
Cheers.
-
That point I don't remember, sorry. You can check with the QWT folks on their mailing list.