Num. of buffered channels

Post Reply
maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Num. of buffered channels

Post by maarcc2050 » Tue Jan 19, 2010 2:23 pm

Hi.

Using speed mode 4, the # of channels is 256 @ 2048Hz. I read from the old threads that there is 282 buffered channel. A bit confused here. What's the new additional channels for and where are they from? So, if I were to read from active 2 hardware directly using my program, should I bother with this 282 or simply sample the 256 channels?

Thanks for any clarification.

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

Post by Coen » Tue Jan 19, 2010 3:11 pm

Sync+Status+256EEG+8EX+16sensor = 282 channels, see http://www.biosemi.com/faq/adjust_samplerate.htm and http://www.biosemi.com/faq/make_own_acq ... ftware.htm

Best regards, Coen (BioSemi)

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Thu Jan 21, 2010 1:40 am

Thanks!

1.
If we were to *not* do with double buffer like activeview, but to read direct, am I right to say that we should read 282 32 bit words for each sample from the read pointer?
2.
If so, can we assume that ringbuffer pointer is sequential? That is, it gets incremented by this sample size for each iteration?

3.
If so, is it right that we could just increment our pointer by 282 32 bit words and not care about the ringbuffer after that?

Thanks for any advise.

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

Post by Coen » Thu Jan 21, 2010 1:54 pm

The answer to all 3 above questions is "no". BioSemi recommends to develop in labVIEW, and to use the full or light versions of ActiView as a base for further developments.

Best regards, Coen (BioSemi)

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Fri Jan 22, 2010 12:20 am

Thanks Coen.

If we were to not use labview, which in the case for our research, we have specific needs that is best addressed with our own development, could you kindly share on the first question and enlighten a little more on the answer?

Here's the question again -
If we were to *not* do with double buffer like activeview, but to read direct, am I right to say that we should read 282 32 bit words for each sample from the read pointer?

Cheers.

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

Post by Coen » Fri Jan 22, 2010 12:45 am

You can only read data from the ringbuffer, you cannot read "direct" (whatever that may mean). In other words: do it like it is done in ActiView. It's the only way to do it.

Best regards, Coen (BioSemi)

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

Post by pmac » Fri Jan 22, 2010 1:15 pm

[quote="Coen"]You can only read data from the ringbuffer, you cannot read "direct" (whatever that may mean). In other words: do it like it is done in ActiView. It's the only way to do it.

Best regards, Coen (BioSemi)[/quote]

To elaborate on what Coen is saying ...

The ring buffer is the key element that allows acquisition to work on a general purpose
operating system like Windows, Linux or OSX. Think of the ring buffer as a fifo that's
being filled by a kernel mode driver and emptied by your program. The kernel driver acts
in real-time whereas your program runs at lower priority.

If NI's Labview is not the language you want to use, that's fine, use another language.
If you browse these forums you will find that some are using C. The ring buffer concept
and implementation is not tied to the Labview language. The module "labview_dll.dll"
is written in C and implements the ring buffer. In spite of its name it has nothing to
do with Labview! You can call its entry points from any compatible language. For
information about this see "http://www.biosemi.com/faq/make_own_acq ... ftware.htm".
The term "directly" used on this page means "directly to the ring buffer".

READ_POINTER tells you where the kernel driver is inserting new words. In your program
you keep track of where you are extracting words, taking care not to overrun the insertion
point or to lag too much that the insert point overruns your extraction point. It's all
sequential - just like in a fifo. Watch the clock style pointers displayed by ActiView.

I hope this helps,

Paul

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Wed Jan 27, 2010 5:28 am

Thank you Paul. It helps a great deal.

Where would I begin the extraction point?

I dumped the memory after I called read pointer for several seconds. I received output that is of this pattern -

19D57A00
00000000
00000000
FFFFFF00
8900FF00
0A19FB00
EF3AF600
7E9EBE00
7E951900
7E9CD400
7EABAD00
FFECC800
7E9AFD00
7E974100
7E975A00
7EA93D00
7EA1C800
EBF8A500
7EB0E700
7EA7AE00
F334A400
01482400
01D6EA00
E9061400
FDC75C00
7E836500
7E729D00
E9BEF800
EE19C200
7E89F700
7E78D300
7E7BC100
7E821400
7E7F4C00
EB2FEE00
7E7F4400
7E8A9000
81547800
81546300
81596400
81546700
8157FF00
81555100
81577F00
81557500
8156B200
81546E00
815D6000
814B9E00
8157B000
814CF300
8158DD00
8153FA00
8151F200
8153CE00
814FF200
81529A00
814E0400
8151EE00
8152AA00
8150C600
81554500
8153D100
81547600
814F4800
8155A500
814F5600
815A5A00
814F5E00

followed by 192 lines of 00000000 and then the following

00000100
09633D00
8149B000
814BC100
81480100
8141CC00
814FD600
81493A00
8144ED00
2C40FA00
C4FA9400
6CAAF200
8B886100
85839A00
85851400
8591F800
8597E600
00000000
00000000
00000000
00000000
00000000

The pattern repeats nicely every 282 lines, which corresponds nicely to the 282 channels. But I cant figure out, how the READ_POINTER tells me any clue about where to begin my extraction? which point in the ringbuffer? If read_pointer tells me the insertion point instead of extraction point(which I thought so), I might need some pointers(no pun intended) myself. Could you shed some light?

Thank you.

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

Post by pmac » Wed Jan 27, 2010 2:31 pm

Maarcc,

You establish your ring buffer with the call to READ_MULTIPLE_SWEEPS.
The ring buffer should be large. I think Actiview defaults to 32MB.

The call to USB_WRITE with the 0xff then starts the acquisition.

At this point both the insertion and extraction indices would be 0.

The first word (4 bytes) from the front end goes into ring[0]-ring[3].
This should be a sync word - 0xffffff00.

Each subsequent call to READ_POINTER tells you the current insertion index, i.e. a byte offset between 0 and the size of the ring buffer, always a multiple of 4.

Your program can start extracting at offset 0 as soon as READ_POINTER returns a value > 0. You may want to wait until this insert index is more than 282 words (282*4 bytes) ahead of your extract index so you can deal with whole sets of 282 samples at once.

Be careful: the insert index wraps back to 0 when it reaches the size of the ring buffer. Your extract index has to do this as well. And if your ring buffer is not a multiple of the size of the channel set (282*4 for mode 4), this wrap will occur part way through a set of channels.

The first word of a channel set is always 0xffffff00. The second word is a status word. The third word contains your first sample. The 24 bit samples are in the high order bits of each 32 bit word so each word must be right shifted 8 bits to get the actual sample.

Good luck with this,

Paul

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Wed Jan 27, 2010 3:18 pm

Thank you!! :)

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Fri Mar 05, 2010 5:35 am

According to the info I read, the throughput remains constant at 1.5 MByte per second for Active2 system.

So, at 2048 Hz, there are 282 samples. That would mean a total of 2048*282*4 bytes which is 2310144. That is above the 1.5Mbytes per sec throughput rate.

Could someone please enlighten?

Thank you.

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

Post by Coen » Fri Mar 05, 2010 11:38 pm

The signal through the optical fiber has 3 bytes per sample (the 24 bits from the ADC). The fourth byte is added in the USB receiver (32-bit integers are sent via USB to the PC).

Best regards, Coen (BioSemi).

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Sat Mar 06, 2010 4:00 am

Thanks Coen.

3*2048*282 = 1732608. Is this the exact number that the '1.5Mbytes' refer to? If not, could you provide a more precise number for this 1.5M?

Cheers.

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

Post by Coen » Sat Mar 06, 2010 1:12 pm

Yes, your calculation is correct. The 1.5 Mbit number actually refers to the older Mk1 version of our system, that used 258 channels (upgraded to 282 for the current Mk2 version). Also note that the throughput is a bit higher in speedmode 8 (AD-box daisy-chained with AIB), and much higher in speedmode 0-3 for the Mk2 (daisy chain of four AD-boxes).

Best regards, Coen (BioSemi)

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Sun Mar 07, 2010 7:40 am

Many thanks again.

I have this call to -> READ_POINTER(theHandle, &lPointer).

When I read the content of this lPointer, the values start from 0, then 131072, 262144, 393216 etc. The increment is always by 131072.

Question is, this does not look like the insertion index, i.e. a byte offset between 0 and the size of the ring buffer? Or does it? Can you enlighten?

I define my ringbuffer as: long buffer[8Mbyes]. Using lPointer as the index does not yield the content of the ringbuffer. What am i missing?

Thank you very much.

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

Post by pmac » Sun Mar 07, 2010 8:34 pm

These numbers look right for the beta Windows or Linux driver running with default settings.

The ring buffer support in Labview_DLL doesn't track the kernel's insert point on a word-by-word
basis. By default it goes for updates every 64 msec., after the first 3 updates. The first
3 updates are different because the number of bytes equivalent to 64 msec depends on the speed mode
setting on the frontend which isn't known until data starts to flow.

Once you get the 131072 from READ_POINTER you know that this is the last known insertion
point. You can access ring[0] to ring[131072-1]. The first word (bytes 0-3) and, with speed mode 4,
every 282th word after that up to 131072/4=32768 should be 0xffffff00. When you get the 262144 from
READ_POINTER you access bytes up to 262144-1. Are you not getting these sync values?

This 64 msec update interval in Labview_DLL is called the buffer stride. It is explained in the
INSTALL text file that came with the downloaded software. It can be shortened or lengthened if
necessary. Shorter values increase the load on the system.

Paul
~

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Wed Mar 10, 2010 4:37 am

Thanks Paul for the info.

1.
If the update is every 64 msec, that means, for a throughput rate of 1732608/sec, 110886.912 bytes = 27721.728 long words = 98 blocks of 282 data, are already available and waiting? Would this delay be a problem?

2.
We observed that when we call READ_POINTER, the function itself is slow and doesnt update as frequent as we expected. Perhaps it's attributable to the 64msec default like you mentioned? And we could better it, like you described by adjusting it according to the manual?

3.
We've now taken away READ_POINTER completely and resort to reading the ringbuffer directly with a regular offset of 282 blocks and checking the FFFFFF00 as the beginning of our new block of data. I've not tested the integrity of the data but so far things seems to be quite well. In your opinion, is our approach wrong and destined for some rude discovery?

Many thanks.

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

Post by pmac » Wed Mar 10, 2010 2:43 pm

Maarcc, to your three points,

> 1.
> If the update is every 64 msec, that means, for a throughput rate of 1732608/sec,
> 110886.912 bytes = 27721.728 long words = 98 blocks of 282 data, are already
> available and waiting? Would this delay be a problem?

It depends on your application ...
With speed mode 4, a 32 MB ring buffer holds approximately 13 seconds of data.
For the ECG application that we work on here, a 64 msec delay isn't a problem.

> 2.
> We observed that when we call READ_POINTER, the function itself is slow and doesnt
> update as frequent as we expected. Perhaps it's attributable to the 64msec default
> like you mentioned? And we could better it, like you described by adjusting it
> according to the manual?

The READ_POINTER is simply a call to retrieve the last known insertion point -
there is no new system call so it should return immediately. If you use the
SYNC parameter described in the INSTALL text file, READ_POINTER will delay the
return until the pointer differs from the value provided in the call. But SYNC is
not assumed by default, you must request it.

The 64 msec default stride is a value that works on most computers, for 2GHz
Pentium 4's and newer. I have used 32, 16, 8, 4, 2 and 1 msec strides on recent
Core 2 Duo machines.

> 3.
> We've now taken away READ_POINTER completely and resort to reading the ringbuffer
> directly with a regular offset of 282 blocks and checking the FFFFFF00 as the
> beginning of our new block of data. I've not tested the integrity of the data but
> so far things seems to be quite well. In your opinion, is our approach wrong and
> destined for some rude discovery?

Interesting ...

This approach should work but keep in mind:

- The presence of the ffffff00 sync word indicates that the previous lead
set is complete, not the lead set that the sync word is part of.

- If the ring buffer size is a multiple of the lead set size (282*4 in this case),
you should overwrite the sync word for each lead set that you've processed with
a 0 or -1 so that you can tell that you are looking at a fresh sweep of the buffer
and not reprocessing the previous sweep.


It sounds like you're getting somewhere,

Paul

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Thu Mar 11, 2010 2:14 am

Thanks Paul.

Our data seems alright except for the sensor channels.

Out of the 282 data, does index 258-265 correspond to EXG1-8?
And how do we map the rest of the 16 channels to GSR1,2;ERG1,2;RESP;PLET;TEMP? Which index corresponds to these 7 of them? And where do the rest of the unmapped channels go?

Cheers.

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

Post by Coen » Thu Mar 11, 2010 7:07 pm

0 = sync
1 = status
2-257 = channels 1-256 (8 SCSI type connectors)
258-265 = channels EX1 - EX 8 (8 touchproof connectors)
266 = GSR1 non-inverting
267 = GSR1 inverting
268 = GSR2 non-inverting
269 = GSR2 inverting
270 = ERGO1 non-inverting
271 = ERGO1 inverting
272 = ERGO2 non-inverting
273 = ERGO2 inverting
274 = RESP non-inverting
275 = RESP inverting
276 = PLETH
277 = TEMP non-inverting
278 = TEMP inverting
279 = BATT
280 = Reserved
281 = Reserved

GSR, TEMP and BATT need additional processing to generate meaningful data. ERGO, RESP and PLETH just need the proper scaling (differs from the scaling of the electrode channels). Please refer to the LabVIEW code for details (see subvi's GSR16.vi, SensorProcess.vi and Sensor.vi).

Best regards, Coen (BioSemi)

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

Post by pmac » Thu Mar 11, 2010 8:59 pm

maarcc,

Further to what I wrote earlier,

> - If the ring buffer size is a multiple of the lead set size (282*4 in this case),
> you should overwrite the sync word for each lead set that you've processed with
> a 0 or -1 so that you can tell that you are looking at a fresh sweep of the buffer
> and not reprocessing the previous sweep.

Coen rightly pointed out to me that when the ring buffer size is not a multiple of the lead set size,
there is a risk that a real data sample from a previous sweep could be mistaken as a sync since
ffffff00 is also the representation of sampled value -1! To be safe:

either use a ring buffer size that is a multiple of the lead set size and overwrite the sync with -1 when
you process each lead set,

or use READ_POINTER calls, perhaps with stride values shorter than 64 msec.


Paul

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Thu Mar 18, 2010 1:18 am

Thanks Paul and Coen.

I've followed your cues and taken the advise to adjust the programs. I did not use READ_Pointer and our buffer size remain at 32MB and not exact multiples of 282.

So far the data is as good as what you'll get from labview.

One thing to note is that there seems to be delay in either the hardware or the driver itself (not sure which) whenever the counter reaches (multiples of 2048) - 1. I've to delay reading the data for as long as a few seconds (about 3-4 secs) for the buffer to be written with the right values. Any idea? I'm using 2048Hz.

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

Post by pmac » Thu Mar 18, 2010 1:09 pm

Maarcc,

> I've followed your cues and taken the advise to adjust the programs. I did not use READ_Pointer and our
> buffer size remain at 32MB and not exact multiples of 282.

It's not clear that you took the advice ...

You don't use READ_POINTER and your buffer size isn't a multiple of the lead set size.

How do you avoid misinterpreting a sampled value of -1 left from the previous buffer sweep as a
sync word?

> One thing to note is that there seems to be delay in either the hardware or the driver itself (not sure which)
> whenever the counter reaches (multiples of 2048) - 1. I've to delay reading the data for as long as a few
> seconds (about 3-4 secs) for the buffer to be written with the right values. Any idea? I'm using 2048Hz.

There must be something wrong with your program. Run ActiView. The hands on the clocklike display move
continuously; there are no multi-second pauses.

Paul

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Thu Mar 18, 2010 2:52 pm

The buffer width is 4 bytes wide. Would the diff. between the sync word FFFFFF00 and -1 FFFFFFFF be sufficient enough to distinguish them? Or I'm missing something?

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

Post by Coen » Thu Mar 18, 2010 3:01 pm

The first 24 bits are from the ADC, the last two zero bytes are just added in the USB receiver to generate 32-bit words. So, FFFFFF00 is actually the -1 data value, as well as the sync word. Since all the original datawords (including sync and status) from the USB receiver always end with 00, overwriting the last one or two bytes to indicate that a word has been read from the ringbuffer would indeed be reliable (but in my view still more complicated than just using the file pointer value).

Best regards, Coen (BioSemi)

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Sun Mar 21, 2010 2:30 pm

Thanks Coen.

Could you advise how to "additional processing" the BATT so we can know how much battery left?

maarcc2050
Posts: 27
Joined: Sun Jan 17, 2010 1:23 pm
Location: Brisbane

Post by maarcc2050 » Thu Mar 25, 2010 12:11 am

Hi.

I checked the forum but couldnt find info on how to interpret the battery signal so we can make sense of how much battery left in our program. Any advise please.

Many thanks again.
M

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

Post by Coen » Thu Mar 25, 2010 2:05 pm

BAT/2097152 - 175.5 = CAP , where BAT is the 32-bit integer data word from the ringbuffer, and CAP is the remaining battery capacity in percent. You will have to limit CAP between 0% and 100% (the formula can generate numbers outside this range).

Best regards, Coen (BioSemi)

hm
Posts: 1
Joined: Mon Apr 12, 2010 2:38 pm
Location: Eindhoven

Unit of the recorded data

Post by hm » Mon Apr 12, 2010 2:58 pm

Hi,

I was able to get the battery level correct, using the equation you provided here. Thanks! I was wondering if you could also help me with figuring out the unit of the electrode channel and the Ergo1 channel.

I am aware that 24 bits are available for each sample and channel, but how can I scale them to meaningful voltage values? Also, I read from your comment on other thread that Ergo needs some scaling possibly different from the electrode reading. Would you mind providing some insight on the scaling issues?

Thanks!

Mun

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

Post by Coen » Tue Apr 13, 2010 12:57 pm

The scaling for the 24-bit output words from the ADCs is:

- Electrode channels: LSB = 31.25 nV (1/32 uV)
- Ergo channels: LSB = 125 nV (1/4 uV)

For the 32-bit words from the USB-receiver, the LSB values are a factor of 256 smaller (extra least significant zero byte is added in the receiver), so respectively 1/8192 uV and 1/2048 uV.

Best regards, Coen (BioSemi)

Post Reply