New LightningChart User

A forum dedicated to WinForms version of LightningChart Ultimate.

Moderator: Queue Moderators

Post Reply
EquiGym
Posts: 2
Joined: Tue Jan 24, 2023 4:45 pm

New LightningChart User

Post by EquiGym » Tue Jan 24, 2023 5:35 pm

Hello,
First time poster, new LightningChart user.

My current project pulls data from an ECG device. but bursts sample readings with a nano second epoc time stamp.
So sample frequency needs to be derived from timestamps. not a problem here.
Burst data at 72 sample blocks aprox every 540ms. From epoc time stamp difference, resulting in aprox 128 sample frequency or 7.7ms sample rate.
My problem is understanding how to translate burst data to a smooth sweeping/scrolling sample output in the chart per derived SF.

The use of SampleGenerator within examples makes it difficult to understand how to develop a suto SampleGererator of my own that consumes data from within the application. so far I have developed something that steps through the data at the sample rate using something like:
C#

Code: Select all

		for (var i = 0; i <= np0; i++)
		{
			tics = StF * Sec_nSec_const * TSEDBuf(i); // SampleInterval to Tics
			Thread.Sleep(new TimeSpan(tics));
			DisplayData(BufS(i))
		}
StF = System.Diagnostics.Stopwatch.Frequency
TSEDBuf() = TimeStamp Difference Buffer. Corresponds to current timestamp of the sample to be displayed - previous timestamp
BufS() = sample buffer, datatype single

the above has a bad jitter effect in the actual sample rate. using 7.7ms sample rate can result in as much as a 9ms SR.
The problem, of course, the chart will lag behind. and of course no longer displaying real-time data

The confusion stems from a strange, at this point in my understanding, correlation between SampleFrequiency and xLength.
So far I have found, to get a display of 72 samples at 128hz within the viewable chart, I have found:
xLength = samplecount/samplefrequiency
_xLength = 72 / 128
result: xLength = 0.5625

So, 2 real questions:
How to regenerate a data display at a frequency per sample.
How to setup the chart to display a sweeping/scrolling set number of samples at a particular sample rate.

Thank you,
Greg.

ArctionKestutis
Posts: 552
Joined: Mon Mar 14, 2016 9:22 am

Re: New LightningChart User

Post by ArctionKestutis » Wed Jan 25, 2023 1:54 pm

You shouldn't use Timer' tick event handlers to push realtime (streaming) data to the chart. This will have extra delays and run out of synchrony or overflow. It is not good idea to use Tread.Sleep() for similar reason, especially if it is UI thread.

In many cases (especially if data streaming is intensive) the best approach is to build multi-thread application. The idea is to have background thread to collect data from hardware (especially if it is bulky like in your case) and use another thread to create smooth scrolling/sweeping of Chart. This chart updating thread should not aim to push every point to chart, but instead check how much time past since last update, calculate number of new points need to be added (based on sampling frequency) and only push this number of points to the chart.

It is critical to remember that all the LightningChart properties should be updated in the UI Thread. How correctly use LightningChart in multitread application described in this article. There you will also find examples from our Demo as well as from our website.

Please note that if you have fixed sampling rate data, you should use SampleDataBlockSeries or SampleDataSeries.

Hope this helps.

EquiGym
Posts: 2
Joined: Tue Jan 24, 2023 4:45 pm

Re: New LightningChart User

Post by EquiGym » Thu Jan 26, 2023 4:59 pm

A little more information:
Yes, multithreading is well utilized throughout the application. Data collection and processing are done on background threads.
Data display is also on its own thread. All UI updates are made to the UI thread. Both chart updates and data display.
The article you suggested was already studied and applied.
Also used SampleDataBlockSeries, and now SampleDataSeries. as it seems putting 1 sample to the chart periodically at 7.7ms to achieve a smooth sweep/scroll. Stepping or block update is not wanted by the customer.
It seems I mislead. The use of thread.sleep was a fail for reasons I pointed out in the OP. But no use of timer.tick event, except for a maybe a timeout tester.
On the other hand, applying your suggestion of a periodic adjustment could work.

This leads back to the original question:
How to setup the chart to display a sweeping/scrolling set number of samples at a particular sample rate from data already collected.

ArctionKestutis
Posts: 552
Joined: Mon Mar 14, 2016 9:22 am

Re: New LightningChart User

Post by ArctionKestutis » Mon Jan 30, 2023 9:43 am

Demo's (Interactive Examples App) ExampleThreadMultiChannel demonstrates idea quite close to that you are looking.
Please check ThreadLoop() method.
1) you need to set reference/initial time and check how much time passed in that background thread-loop. Based on sampling frequency and time past, you calculate how many points should be copied/generated:

Code: Select all

_now = DateTime.Now.Ticks; //Get current time stamp.

long currentSampleIndex =
    (long)(TimeSpan.FromTicks(_now - _startTicks).TotalSeconds * _samplingFrequency); //Get sample index at this time

int sampleBundleToGenerate = (int)(currentSampleIndex - _samplesOutput);
2) If sample sampleBundleToGenerate > 0, then you read/copy/generate data from the block

Code: Select all

    for (int channelIndex = 0; channelIndex < _channelCount; channelIndex++)
    {
        multiChannelData[channelIndex] = new double[sampleBundleToGenerate];

        //Generate random data
        for (int sample = 0; sample < sampleBundleToGenerate; sample++)
        {
            //multiChannelData[channelIndex][sample] = YMin + _rand.NextDouble() * yRange;
            multiChannelData[channelIndex][sample] = dataBlock[channelIndex][_samplesOutput+ sample];
        }
    }
3) Once new data is copied, you add those to the Chart/Series (in Main UI Thread)

Code: Select all

    _samplesOutput += sampleBundleToGenerate;
             
    if (this.IsHandleCreated)
        Invoke(_chartUpdate, (object)multiChannelData);
Hope this helps.

Post Reply