ASE Home Page Products Download Purchase Support About ASE
ChartDirector General
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  get sample every 2.8 ms in realtimezoomscroll project
Posted by jill on Aug-10-2018 18:19
I want to set my sample every 2.8 ms instead of 250ms in chart
I see these line

// We need the currentTime in millisecond resolution
        double currentTime = Chart::chartTime2(m_nextDataTime.toTime_t())
                + m_nextDataTime.time().msec()/250*0.25;



static const int DataInterval = 250;
// Set up the data acquisition mechanism. In this demo, we just use a timer to get a
    // sample every 250ms.
    QTimer *dataRateTimer = new QTimer(this);
    dataRateTimer->start(DataInterval);
    connect(dataRateTimer, SIGNAL(timeout()), SLOT(onDataTimer()));


To get a sample every 2.8 ms I should change both of these?
What does 250*0.25 do?

  Re: get sample every 2.8 ms in realtimezoomscroll project
Posted by Peter Kwan on Aug-11-2018 00:04
Hi jill,

To change the sampling period, just change the DataInterval to the period you want.

The "double currentTime = Chart::chartTime2(....) .....;" is just a part of the random number generator in the sample code. In your real code, you would need to remove the random number generator and use your own code to get the real data. For example, your code can be like:

void RealTimeZoomScroll::onDataTimer()
{
     //Use your own code to obtain the currentTime, dataA, dataB and dataC
     ............

     //this demo, if the data arrays are full, the oldest 5% of data are discarded.
     if (m_currentIndex >= sampleSize)
     {
          m_currentIndex = sampleSize * 95 / 100 - 1;

          for(int i = 0; i < m_currentIndex; ++i)
          {
              int srcIndex = i + sampleSize - m_currentIndex;
              m_timeStamps[i] = m_timeStamps[srcIndex];
              m_dataSeriesA[i] = m_dataSeriesA[srcIndex];
              m_dataSeriesB[i] = m_dataSeriesB[srcIndex];
              m_dataSeriesC[i] = m_dataSeriesC[srcIndex];
          }
      }

      // Store the new values in the current index position, and increment the index.
      m_timeStamps[m_currentIndex] = currentTime;
      m_dataSeriesA[m_currentIndex] = dataA;
      m_dataSeriesB[m_currentIndex] = dataB;
      m_dataSeriesC[m_currentIndex] = dataC;
      ++m_currentIndex;
}


The sample code uses QTimer to read the data in the main thread. If your sampling rate is very high and needs to be accurate, you should consider to put the data sampling in a separate thread. You may refer to the "Multi-Threading Real Time Chart" sample code for an example:

https://www.advsofteng.com/tutorials/extra.html

Also, note that for 2.8ms, it needs accuracy for a fraction of a millisecong (eg. 100us precision). Common operating system (such as Windows/Linux/Mac OS X) cannot achieve this precision for "user mode" code. If you really need microsecond precision, it is likely you need to low level kernel mode drivers.


In practice, high precision data are usually obtained using hardware sampling. For example, for audio, the sampling rate is 44100Hz, or 22.7us per sample. The audio hardware and driver will sample the data accurately, then put it in a buffer. The user mode code can then periodically (eg. once per 50ms) read the data from the buffer. That means the QTimer only needs to sample at 50ms. Each time the onDataTimer is execute, it will read all the buffered data from the sound driver.


(One of our client actually used the above method to create a "oscilloscope". He used a USB sound card as an A/D converted. The sensors were connected to the microphone input of the sound card. He then used Qt code to read the analog input periodically from the sound card, and plot them on a realtime chart.)


Regards
Peter Kwan

  Re: get sample every 2.8 ms in realtimezoomscroll project
Posted by jill on Aug-11-2018 01:56
In this example you said:
https://www.advsofteng.com/tutorials/real_time_chart_multithread/real_time_chart_multithread.html

Use Multi thread and It put data in a buffer?right?

  Re: get sample every 2.8 ms in realtimezoomscroll project
Posted by jill on Aug-11-2018 14:02
I use Raspberry pi ,and read Data in thread from USB port serial like:
void MyThread::run() {

    qDebug("Thread id inside run %d", (int)QThread::currentThreadId());

    int fd, value;


    if ((fd = serialOpen ("/dev/ttyACM0", 230400)) < 0) {
        fprintf (stderr, "Unable to open serial device: %sn", strerror (errno)) ;
    }

    while (serialDataAvail(fd) > -2) { // fix condition!
        value = serialGetchar (fd) ;
           emit signalValueUpdated(value);

        }
    serialClose(fd);
}

The sampling rate is 349 samples per second or 2.8 ms
If I use msleep in thread , data will be lost
If I  add directly data to packet.series0 = value;
Can I access 2.8ms or need to change the timer or sleep time?

Also I want to add current time ,not elapsedTime
If I set m_timeStamps like before :

m_nextDataTime = QDateTime::currentDateTime();
double currentTime = Chart::chartTime2(m_nextDataTime.toTime_t()) + m_nextDataTime.time().msec() / 250 * 0.25;
m_nextDataTime = m_nextDataTime.addMSecs(DataInterval);
packet.elapsedTime = currentTime;

is it work?

  Re: get sample every 2.8 ms in realtimezoomscroll project
Posted by Peter Kwan on Aug-11-2018 16:37
Hi jiff,

For your case, it is OK not to use msleep as serialGetchar is already a blocking call, that is, it will automatically "sleep" until data are available.

It seems your code is emitting the signalValueUpdated to another thread. In this case, by default, Qt will use the queued connection. See:

http://doc.qt.io/archives/qt-4.8/threads-qobject.html

With a queued connection, the signal will be processed after some delay, which can be from 0ms to over 10ms. Dueo to the delay, the timestamp obtained in the signal handler does not reflect the timestamp of the data. It is better the obtain the timestamp directly when reading the data. It is like:

QDateTime qtimestamp;
double timeStamp;

while (serialDataAvail(fd) > -2) { // fix condition!

    value = serialGetchar (fd) ;
    qtimestamp = QDateTime::currentDateTime();
    timeStamp = Chart::chartTime2(qtimestamp.toTime_t()) + qtimestamp.time().msec() / 1000.0;

     emit signalValueUpdated(timeStamp, value);
}


With the above code, the timestamp is obtained immediately after getting the data, so it will be much more accurate. In our own multi-threading example, we also obtain the timestamp in the data acquisition thread, not in the charting thread.

Regards
Peter Kwan