C++ Data Acquisition Program

Post Reply
erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

C++ Data Acquisition Program

Post by erfan.y »

Hi
I am a student who is new to biosemi and not expert in programming. I am designing a data acquisition program for biosemi. I can enable the handshake and communicate with the usb. but I have problem in READ_POINTER function. I do not exactly understand how to work with this function to receive the data. Is it possible for someone to help me understand, I don mean giving the code, just making me understand how to work with it?

Thanks a million

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

now I got the READ_POINTER to work, the output is a pointer to an integer. I dont know what is this integer. I guess we used an array of 64 zero bytes data to save the data of all sockets, if it is correct then what is the mapping of sockets to array index? and why there is only a pointer to an integer in READ_POINTER. how can I get the data for the sockets like EX1, EX2, EX3 ,... .

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

You define a ring buffer to hold your samples in your call to READ_MULTIPLE_SWEEPS.

Then READ_POINTER returns, in its integer argument, the position (an index) in this ring buffer where the next sample will be stored.

This index value will be between 0 and the size of the ring buffer.

After your first call to READ_POINTER you will find your samples in the ring buffer, from index 0 up to the value returned by READ_POINTER.
Be careful - READ_POINTER returns a byte index; you must divide it by 4 to get a 4 byte integer index.

On each subsequent call to READ_POINTER will give you an updated "next sample position". You will find newer samples in the section
of the ring buffer between the index values returned in your last 2 calls to READ_POINTER.
Be careful - the index value will wrap back to 0 when it reaches the defined size of the ring buffer and previous samples will be overwritten.

For more information, read this thread:
viewtopic.php?t=452

Or, use the BioSemi forum search function for "READ_POINTER" discussions.

Also, have a look at how these functions are used in the labview_dll_synctest.cpp source file that's included in the driver package that you
downloaded from BioSemi.

I hope this helps,
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Thanks a lot Paul.

Sorry I have to ask some more question. I read that topic, but some parts I do not understand, let me specify this.
I have an array of data: CHAR data[64]
I made a ring buffer like this: PUCHAR ringbuffer;
and I allocated memory: ringbuffer = (PUCHAR)VirtualAlloc(NULL,ringBuffersize,MEM_COMMIT,PAGE_READWRITE);
then I call the READ_MULTIPLE_SWEEPS to initialize the buffer. After that enabling the usb hand shake with USB_WRITE.

OK. now its time to use the READ_POINTER. I call the READ_POINTER(driver,readdata); which driver is the handle used before and readdata is PINT_PTR which I allocated 3kb memory for it. So now that readdata points to an integer which is the index of the ringbuffer which the newer data is going to be saved there if I am right. but I do not understand yet, if as an instance I want to get the data from the EX1, how can I find it. what I thought and guessed from the posts and your guide is that the pointer is pointing to an index which the next data is there, I suppose data is the whole data of all sensors. so if we consider I call READ_POINTER it gives me 0, I call it again it will give me 1128 which divide by 4 is 282, so from the index 0 to index 282 of the ring buffer the data for all the sensors is saved(am I right?). so each time the number is a multiple of 282 which is a set of data of all sensors saved in 282 indexes.

I really appreciate your time and help, Thanks Paul.

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

You are getting close.

Your "readdata" argument for READ_POINTER is usually the address of a simple 4 byte integer, not an array.
READ_POINTER will store the current value of its internal "next sample index" in that integer so you can know
where the seam between new samples and old samples is in your array "ringbuffer".

Using speed mode 4, one sweep of all the channels is a packet of 282 samples.
In the 2nd message on the thread mentioned above Coen defines this as:

Sync+Status+256EEG+8EX+16sensor = 282 channels

For you, addressing "ringbuffer" as an integer array,
ringbuffer[0] is the Sync value (i.e. 0xffffff00),
ringbuffer[1] is a status word,
ringbuffer[3] to ringbuffer[257] are EEG or ECG samples,
ringbuffer[258] to ringbuffer[265] are the EX samples,
ringbuffer[266] to ringbuffer[281] are the sensors.

This sequence repeats throughout your "ringbuffer" array:

ringbuffer[282] is Sync,
ringbuffer[283] is status,
ringbuffer[284] to ringbuffer[539] are ...
ringbuffer[540] to ringbuffer[547] are EX,
ringbuffer[548] to ringbuffer[563] are sensors.

ringbuffer[564] is Sync,
...

Be careful: although your data is in packets of 282 channels, READ_POINTER considers it as simply a stream of bytes.
The index value returned by READ_POINTER is always a multiple of 4 but rarely a multiple of 282.
You must be prepared to deal with partial packets.

Regards,
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Thanks Paul for all helps
I am getting integers from READ_POINTER

I made a loop to call this function, but the numbers increment haphazardly. However as you said all of them are multiples of 4.

here are the few first numbers

0
262144
524288
593920
742400
860880
1039360
1187840

So, first I wanted to ask about the sample rate which you said. How can I change the sample rate? as I worked out with different delay times in order to get these numbers, I found almost the sample rate would be something between 0.05 to 0.1 second. but I could not find out how to change it. since the website is talking about the activew not the other data acquisition software.

secondly, based on the information which you mentioned about samples and channels, I thought the subtract of two continues integer of the READ_POINTER function would be between 0 and 282. So if I get a full package of the samples it will be 282 otherwise I would have some partial packages which would be between 0 and 282. However the numbers that I am getting now is much higher than that, I dont know why?!?! and I was wondering how can I get the index for the EX1 or GSR since they are not following the pattern that I thought.

last but not least, I wanted to ask you even if I find the proper index of for example GSR, then at the ringbuffer[index] what kind of data will be? is it printable on the screen? or it needs to be sketched like a graph?

Thanks Paul.
I am sorry you are the only resource that I have now, sorry to bug u a lot.

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

Your numbers from READ_POINTER look right!

The frontend sample rate is set manually by the mode switch. Mode 4 is usually 2048 samples/second/channel.
Other possible mode settings are shown in a table at the bottom of this page:
http://www.biosemi.com/faq/make_own_acq ... ftware.htm
Note in the table: as the sample rate increases, the number of channels decreases and thus the packet size as well.

Once you start acquisition, samples start flowing into your ringbuffer. The index returned by READ_POINTER is
determined by how many samples have passed through the USB inferface and into your ringbuffer at the moment when
you make the call - it usually doesn't increment at a fixed rate.

In the above example, after your second call to READ_POINTER, you will find the first EX sample at 258, then at 258+282,
258+282*2, 258+282*3, ..., but take care not to go past the second value returned by READ_POINTER (byte index 262144 =
word index 65536). I think your last complete packet starts at 65142 so the last EX sample to use would be at 65142+258.

After your third call you continue where you left off - at the packet that starts at 65142+282 with first EX sample
at 65142+282+258. Then you can continue using EX samples up to byte index 524288 = word index 131072. The last
complete packet would start at 130566.

And so on with subsequent calls. In general you can't predict what READ_POINTER will return. As your program works
forward it has to keep track of its own index and make sure it doesn't cross over READ_POINTER's index.

The samples in your ringbuffer are 24 bits. They are the high order 24 bits of the 32 bit integer. If you divide
the integer by 256 you get a sample whose least significant bit is 1/32th of a microvolt - see the paragraphs after
the mode table in the above mentioned BioSemi FAQ web page.

I hope this helps,
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Thanks Paul,

I did what you said, I made a loop for calling the READ_POINTER, counting to 10 and I got the following numbers.

0
0
0
262144
262144
524288
593920
742400
890880
1039360

there is a Sleep(50) in this counter which 50ms is less than the sample rate, so that is why i am getting the same number in some of them.

so I wanted to save the data to a text file to make sure i am getting something and also to analyse the data. so I made another loop counting to 100. this loop is after the READ_POINTER loop

int index=266 //Index for GSR
ofstream output;
output.open(...);
for(...)
{
output<<ringbuffer[index]
index+=282;
}

and it didnt work out, the file was empty, not even zero or any other character, it was jus totally empty then i thought maybe the first samples were something wrong with them or totally zero or nothing, then i used the fifth numer that READ_POINTER returned. it was 262144. then I did the same i added 266 to it and saved the data to the file, but the file was still empty. I really dont get what is wrong.

Thanks Paul

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

Try the code below. I haven't actually tried it myself because I'm not near my development machines today.

I use your previously referenced variables: driver, ringbuffer, ringBuffersize

Sorry, posting seems to remove program indentation.

Paul


//==============================================
int packetNum = 0;
int seam;
int lastSeam=0;
char *curBuffer=ringbuffer;
int nextSync=0

for ( ; ; )
{
read_pointer(driver, &seam);
if (seam == lastSeam)
continue;

int bytesRead = seam - lastSeam;
if (bytesRead < 0)
bytesRead += ringBuffersize;;

lastSeam = seam;

int newBytes = ringbuffer+seam - curBuffer;
if (newBytes < 0)
newBytes += ringBuffersize;
int newSamps = newBytes/4;

for (int ii=0; ii<newSamps> newSamps)
break; // not a complete packet

if (nextSync*4 >= ringBuffersize)
nextSync -= ringBuffersize/4
if (((int *)ringbuffer)[nextSync] != 0xffffff00)
{
printf("\n*** missing sync at %d ***\n", nextSync);
return 0;
}

int nextGSR = nextSync + 266;
if (nextGSR*4 >= ringBuffersize)
nextGSR -= ringBuffersize/4;

printf("packet %d index %d GSR %d\n", ++packetNum, nextGSR, ((int *)ringbuffer)[nextGSR]/256);
}

// update current buffer address
curBuffer = ringbuffer + nextSync*4;

if (curBuffer >= ringbuffer+ringBuffersize)
curBuffer -= ringBuffersize;
}

//==============================================

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Erfan,

The code in my last post was mangled a bit by the posting process!!!

These 2 line are nonsense:

for (int ii=0; ii<newSamps>newSamps)
break; // not a complete packet

The problem seems to be caused by angle brackets. Let me write it correctly using Fortran operators, i.e. .lt. for "less than" and .gt. for "greater than".

The 2 bad lines should be replaced with these 4 lines:

for (int ii=0; ii.lt.newSamps; ii+=282,nextSync+=282)
{
if (ii+282 .gt. newSamps)
break; // not a complete packet

Then replace the .lt. and .gt. with the appropriate angle brackets.

Someday I'll learn how to properly post code here, I hope.
Sorry about this.
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Hi Paul

Thanks for the help. Its working, its amazing :D . I really have no idea how far could I get without ur help. I am making an API for it, so its gonna like convert or somehow translate the data. I noticed lots of stuff I didn care in my codes such as checking synch channel checking whether there is new data or not and also multiples and division of 4. Thanks really, you really are an expert programmer. I wonder where you are working at :D

thanks for help Paul, really

is there any way to be in touch with you in the future? which i may get stuck with something and you can guide me or help me out?

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Hei Paul

Thanks for helping
I have a problem with the data I get. A normal GSR value is about 20,000 s(siemens)
or 625,000 ns or 625 µs. While, I am comparing the GSR values of my Data acquisition program and actiview, I see that I get the value around 800 ns from activew!!!! I was surprised, I tried the same experiment on the same place of body with the c++ program and I got the value varying from 50,577 to 1,477,525

here are some values from c++ program

packet 764 index 1555778 GSR 124190
packet 766 index 1556060 GSR 592257
packet 768 index 1556342 GSR 647651
packet 770 index 1556624 GSR 635052
packet 772 index 1556906 GSR 513327
packet 774 index 1557188 GSR 40460
packet 776 index 1590746 GSR 419176
packet 778 index 1591028 GSR 471859
packet 780 index 1591310 GSR 463159
packet 782 index 1591592 GSR 338526
packet 784 index 1625432 GSR 201031
packet 786 index 1625714 GSR 257236
packet 788 index 1625996 GSR 259186
packet 790 index 1626278 GSR 131284
packet 792 index 1660682 GSR 11223
packet 794 index 1740770 GSR 293756
packet 796 index 1775456 GSR 307101
packet 798 index 1775738 GSR 712646
packet 800 index 1776020 GSR 712335
packet 802 index 1776302 GSR 711966
packet 804 index 1776584 GSR 511148
packet 806 index 1810142 GSR 184549
packet 808 index 1810424 GSR 593108
packet 810 index 1810706 GSR 593780
packet 812 index 1810988 GSR 598908
packet 814 index 1811270 GSR 392568
packet 816 index 1844828 GSR 44498
packet 818 index 1845110 GSR 447275
packet 820 index 1845392 GSR 439599
packet 822 index 1845674 GSR 449961
packet 824 index 1845956 GSR 242860
packet 826 index 1879796 GSR 279560

Please note that when I get the value from the ring buffer I multiplied it bt 0.032. which means *32 for converting to ns, and /1000 for converting to µs. I DID NOT divide by 256 or anything else//

Thanks for helping,
I appreciate,

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

1. Quoting the BioSemi web page mentioned previously:

"The receiver converts every 24-bit word from the AD-box into a 32-bit Signed Integer, by adding an extra zero Least Significant Byte to the ADC data.
The 24-bit ADC output has an LSB value of 1/32th uV.
The 32-bit Integer received for the USB interface has an LSB value of 1/32*1/256 = 1/8192th uV"

My understanding of this is that you must also divide by 256.

2. Your GSR numbers seem to jump around a lot. Perhaps this is normal - I've never worked with this measurement. And are the units really seconds and not volts?

3. Why do your packet numbers advance in steps of 2 when the corresponding index values advance only by 282?

Regards,
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Hi Paul

I know tried also with dividing by 256, yet its not quite comparable to actiview and normal rates what I wrote there was the example I was trying at that time. I also mentioned the units are in s(siemens) not s for seconds.

Oh and about the packet number, ignore that, i was saving to the file and I wrote another line of code and I forgot I already incremented the packet number when I show on the screen so I incremented again. but thanks for saying.

pmac
Posts: 70
Joined: Thu Jan 21, 2010 2:51 pm
Location: Canada

Post by pmac »

Hi Erfan,

Have a look at this BioSemi forum thread:

viewtopic.php?t=400&highlight=gsr

Also, try the Search function at the top of this forum page, for example try the search string: gsr

Regards,
Paul

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

Post by erfan.y »

Hi
Thanks Paul
Sorry, you are right. I just got used to ask all questions from you :D,
Thanks a lot man

erfan.y
Posts: 11
Joined: Wed Jul 06, 2011 11:01 am
Location: Sweden

EX1 value

Post by erfan.y »

Thanks Paul for you replies.

I was working with the EX1 sensor, and I was getting the values with my own data acquisition software. I want to ask, do we need to do any calculations with the value we get to get the true value of EX1 sensor :?: except the 256 division to get the 32 bit value.

I searched over forum and I looked up the data acquisition faq on the website, there wasnt anything about the calculation of EX sensors.

Coen
Site Admin
Posts: 1124
Joined: Fri Mar 26, 2004 7:00 pm
Location: Amsterdam, Netherlands
Contact:

Post by Coen »

Divide the 32-bit integers by 8192 (32*256) to convert to microVolt.

Best regards, Coen (BioSemi)

Lloyd
Posts: 26
Joined: Fri Mar 26, 2004 7:46 pm
Location: Wilmington, NC, USA
Contact:

MATLAB API

Post by Lloyd »

If you are interested in an open source MATLAB API for ActiveTwo, see this topic viewtopic.php?p=2049#2049. Thanks.

Post Reply