Streaming data in IGOR PRO | LabJack
 

Streaming data in IGOR PRO

10 posts / 0 new
Last post
Gigaseal
Gigaseal's picture
Streaming data in IGOR PRO

I'm trying to stream data to IGOR PRO. I have used IGOR for a while and like the online analysis and easy visualizations I have written for this platform, so I'm not inclined to switch.

But, getting a LabJack U6 might force me, since I can't get streaming data to work.
Setting up everything seems to work, and I can read single analog values from the ports, as well as set values to the out ports.
For streaming I have tried the following code:

err=LJ_eGet(LJref,LJ_ioSTART_STREAM,ch,freq,placeholder)
do

err=LJ_eGet(LJref, LJ_ioGET_STREAM_DATA, ch, numscans,data)
while(i<length)

The data should contain the stream data, but I can't seem to write to an array. Data can only be of the variable type, it can't be a wave since that results in a labjack error.

What am I doing wrong?

LabJack Support
labjack support's picture
Our current Igor Pro XOP

Our current Igor Pro XOP doesn't support stream mode. We will need to look into updating the XOR to add eGetPtr which will support using arrays for the x1 parameter and is pointer safe.

Gigaseal
Gigaseal's picture
That is a serious bummer. I

That is a serious bummer. I would wish I knew that beforehand and wouldn't have wasted my time on this.

Would streaming work in Matlab? I could try to put something together, although I am not as proficient anymore in Matlab....

Alternatively, is there a workaround? Maybe reading single values and reading out the internal clock to get the timing?

Thanks!

LabJack Support
labjack support's picture
Stream mode works in MATLAB.

Stream mode works in MATLAB. Take a look at the examples here, which include a stream example:

https://labjack.com/support/software/examples/ud/matlab

You could use command-response mode (standard communications) to get readings and use the Igor Pro timing immediately after the reading for a timestamp. Command-response mode is typically used for scan rates of 100 scans/second or lower, but depending on analog input configuration, system performance and language can work up to 1000 scans/second. Stream mode is for 100 to 50k scans/second rates. Regarding Igor Pro, there are some "Timing" methods. There is the ticks method with 1/60 of a second precision, and StartMSTimer() and StopMSTimer() which has a microsecond timer. I'm going off documentation for this information.

You could configure the LabJack timers for the system timer (mode 10 and mode 11), and group your analog/digital readings with the timer reads that has the U3 time. Though typically with command-response mode speeds, using the language's timing (mentioned in previous paragraph) is adequate and less complicated.

The above are immediate solutions. We could also look into updating the XOR on our site and add the functionality that supports reading arrays for streaming. I can probably get around to that sometime this week.

Gigaseal
Gigaseal's picture
It is for a behavior setup,

It is for a behavior setup, so I would really need more than 100 samples/ second. 1000/sec might work, so I'll have a go at that in Igor and see how the timings work out.

If you have an updated version of the XOP, that would be great. I'll make sure to make my code flexible to also work with a possible feature in the XOP to accommodate streaming.

Please keep me posted on any progress on the XOP level.

Many thanks!

LabJack Support
labjack support's picture
The IgorPro download has been

The IgorPro download has been updated.  The eGetPtr function is now available in the updated XOP for stream mode and a U6 stream example was added. Let us know if you run into issues with it.

https://labjack.com/support/software/examples/ud/igor-pro-windows-ud

 

Gigaseal
Gigaseal's picture
This level of customer

This level of customer service is beyond awesome!

Thank you so much, the code is working perfectly and is adaptable to my needs. I will play a bit more with some variants, but it is looking very promising for my goals.

Many thanks! -Laurens

Gigaseal
Gigaseal's picture
Unfortunately I have

Unfortunately I have encountered some serious hiccups in the code that I can't seem to sort out. Igor keeps crashing when I try to stream more than one channel. I can't figure out what I'm doing wrong, but I have the feeling it goes wrong somewhere with the requested number of scans from the Labjack. If someone has some insight in this, here is my code:

Function Stream(channels,length)
    string channels    //String or stringlist with channels (Use AIN and FIO, e.g. AIN1;FIO5;AIN0
    variable length    //length defined ms

    dfref olddf = GetDataFolderDFR()
    setdatafolder root:Packages:Labjack
    NVAR LJref,sampling,readspersecond            //Sampling is defined per channel!
    variable NrCh,err,t,i,j,buffertime
    string str,ch
    NrCh = itemsinlist(channels,";")
    variable numScansRequested = sampling/readspersecond*NrCh        // This is the length of one chunk
    Variable numReads = length/(1/sampling)/numScansRequested*NrCh    // We read the data in chunks, numReads is how many chunks there are

    setdatafolder olddf
    Killwaves /Z datawave, ConcatData
    buffertime = 1                                    // 1 second buffer configured
    // Check whether we can make this sampling rate theoretically:
    if(sampling*NrCh>5e4)
        print("Error! Sampling rate is too high. Maximal 50kHz combined for all channels.")
        return(0)
    endif
    // General configuration of the stream:
    // Setting the scanfrequency. This is how many times per second each channel is read.
    err = LJ_AddRequest(LJref, LJ_ioPUT_CONFIG, LJ_chSTREAM_SCAN_FREQUENCY, sampling, 0, 0)
    ShowError(err)
    // Setting the buffer in the Labjack. Samplingrate * Number of channels * buffertime
    err = LJ_AddRequest(LJref, LJ_ioPUT_CONFIG, LJ_chSTREAM_BUFFER_SIZE,sampling*NrCh*Buffertime, 0, 0)
    ShowError(err)
     // Configure reads to wait for requested amount of data (wait mode LJ_swSLEEP).
    err = LJ_AddRequest(LJref, LJ_ioPUT_CONFIG, LJ_chSTREAM_WAIT_MODE, LJ_swSLEEP, 0, 0)
    ShowError(err)
    // Clear any configuration of streaming channels that might be present:
    err = LJ_AddRequest(LJref, LJ_ioCLEAR_STREAM_CHANNELS, 0, 0, 0, 0)
    ShowError(err)

    for(i=0;i<NrCh;i+=1)    // Loop through the channels requested to configure them
        ch = stringfromlist(i,channels)
        if(stringmatch(ch,"AIN*"))
            // Setting the resolution of the streaming channel
            err = LJ_AddRequest(LJref, LJ_ioPUT_CONFIG, LJ_chAIN_RESOLUTION, 0, 0, 0)
            ShowError(err)
            // Setting the range of the streaming channel (+/- 10 V)
             err = LJ_AddRequest(LJref, LJ_ioPUT_AIN_RANGE, str2num(ch[3,4]), LJ_rgBIP10V, 0, 0)
            ShowError(err)
            // Adding the stream
            err = LJ_AddRequest(LJref, LJ_ioADD_STREAM_CHANNEL, str2num(ch[3,4]), 0, 0, 0) //Single ended
            ShowError(err)
        elseif(stringmatch(ch,"FIO*"))

        endif
    endfor
    // Execute the list of requests.
    err = LJ_GoOne(LJref);
    ShowError(err)
    // Get all the results just to check for errors.
    variable ioType=0,channel=0,value=0,x1=0,userData=0
    Variable LJE_NO_MORE_DATA_AVAILABLE = LJ_StringToConstant("LJE_NO_MORE_DATA_AVAILABLE")
    Variable LJE_MIN_GROUP_ERROR = LJ_StringToConstant("LJE_MIN_GROUP_ERROR")
    err = LJ_GetFirstResult(LJref, ioType, channel, value, x1, userData)
    ShowError(err)
    do
        err = LJ_GetNextResult(LJref, ioType, channel, value, x1, userData)
        if( err != LJE_NO_MORE_DATA_AVAILABLE )
            ShowError(err)
        endif
    while(err < LJE_MIN_GROUP_ERROR)
    // Start the Stream
    err = LJ_eGet(LJref, LJ_ioSTART_STREAM, 0, 0, value)
    ShowError(err)


    // The actual scan rate is dependent on how the desired scan rate divides into
    // the LabJack clock.  The actual scan rate is returned in the value parameter
    // from the start stream command.
    Printf "Actual Sampling Rate per channel = %.3f\r", value
    Printf "Actual Total Sampling Rate = %.3f\r", NrCh*value
    // Preallocating some waves. Two for the data and two for backlogs and one for samples read:
    make /O/D/N=(numReads) commBackLogWave=9999, UDBackLogWave=999, SampRead=0
    Make /O/D/N=(NumScansRequested) dataWave    // This is the length of one chunk
    make /O/D/N=0 allDataWave // allDataWave is where we store all samples. Will be concatenated
    variable commBacklog,udBacklog


    for( i=0;i<numReads;i+=1 )//Can be parallelized
        // Read the data.
        // Note that the array we pass must be sized to hold enough SAMPLES, and
        // the Value we pass specifies the number of SCANS to read.
        numScansRequested = sampling/readspersecond*NrCh
        err = LJ_eGetPtr(LJref, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, dataWave, numScansRequested)
        ShowError(err)
        SampRead[i] = numScansRequested
        // Retrieve the current Comm backlog.  The UD driver retrieves stream data from
        // the U6 in the background, but if the computer is too slow for some reason
        // the driver might not be able to read the data as fast as the U6 is
        // acquiring it, and thus there will be data left over in the U6 buffer.
        err = LJ_eGet(LJref, LJ_ioGET_CONFIG, LJ_chSTREAM_BACKLOG_COMM, 0, commBacklog)
        ShowError(err)
        commBackLogWave[i] = commBacklog
        // Retrieve the current UD driver backlog.  If this is growing, then the application
        // software is not pulling data from the UD driver fast enough.
        err = LJ_eGet(LJref, LJ_ioGET_CONFIG, LJ_chSTREAM_BACKLOG_UD, 0, udBacklog);
        ShowError(err)
        UDBackLogWave[i]=udBacklog
        // Move data to our full data wave
        Concatenate /NP {dataWave}, allDataWave
// HERE WE PUT OUR MANIPULATIONS

    endfor
    wavestats /Q allDataWave
    SetScale /P x 0,(1/sampling), "s" allDataWave


end

Gigaseal
Gigaseal's picture
I had a little bit of a look

I had a little bit of a look in event viewer and upon Igor crash it seems to have a problem with ntddl.dll

I have no clue what that might mean, or how it is caused, but it seems to be some core windows thing?

LabJack Support
labjack support's picture
It looks like dataWave is not

It looks like dataWave is not large enough in size for what is requested, which in the UD driver can can lead to crashes (out of bounds array access). The problem I see is related to:

numScansRequested = sampling/readspersecond*NrCh

Your dataWave is numScansRequested in size, and you are reading samples with the following:

err = LJ_eGetPtr(LJref, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, dataWave, numScansRequested)

Your dataWave should be at least numScansRequested*NrCh (#Scans * #Channels) in size since you request numScansRequested scans and LJ_chALL_CHANNELS in your code. When reading the stream samples you are specifying the number of scans to read, where 1 scan of samples are the channels in your scan list (NrCh samples per scan).