Jump to content

Contributions:BlackrockGemini: Difference between revisions

From BCI2000 Wiki
Nluczak (talk | contribs)
Updated to reflect on changes to gemini
Nluczak (talk | contribs)
No edit summary
 
Line 1: Line 1:
==Synopsis==
==Synopsis==
The Blackrock Gemini acquisition module enables signal acquisition from Blackrock Microsystems Gemini acquisition hardware through the "cbsdk" C++ API.
The BlackrockGemini signal source module acquires data from Blackrock Microsystems Gemini acquisition hardware over Ethernet, using the Cerebus SDK ([https://github.com/dashesy/CereLink cbsdk]).  All channel configuration — enabled channels, per-channel sampling rate, gain, and label — is set in Blackrock's Central application and imported into BCI2000 automatically at <code>SetConfig</code> time.


==Location==
==Location==
Line 6: Line 6:


==Versioning==
==Versioning==
===Author===
===Authors===
Griffin Milsap (griffin.milsap@gmail.com), Jürgen Mellinger (mellinger@neurotechcenter.org)
Griffin Milsap (griffin.milsap@gmail.com), Jürgen Mellinger (mellinger@neurotechcenter.org), Nicholas Luczak (luczak@neurotechcenter.org)
 
===Source Code Revisions===
===Source Code Revisions===
*Initial development: 4365/8061
*Initial development: 8061
*Tested under: 8522
*Tested under: 9216
*Known to compile under: 8522
*Known to compile under: 9216
*Broken since: N/A
*Broken since: N/A


==Functional Description==
==System Setup==
The BlackrockGemini source module is used for acquiring recordings from Blackrock Gemini systems using CBSDK as provided through official Blackrock channels, or through CereLink (https://github.com/dashesy/CereLink). This documentation explains the parameterization and specifics on how to set up the system.


===System Setup===
===Network Configuration===
Building the BlackrockGemini module should copy .bat files for standard experiments into the batch directory.
The module talks to the Gemini Hub over UDP and is sensitive to packet loss. Connect the BCI2000 machine and the Gemini Hub to a '''single''' commercial-grade switch, or use a crossover cable directly between the two.  Do not place a second switch, or a consumer-grade router, in between.


Ensure your machine is connected to a switch or router that the Gemini Hub is also connected to.  This module communicates to the Gemini Hub using UDP, and is susceptible to packet lossEnsure you have a commercial grade switch to avoid dropping packets. You can also use a crossover cable to connect directly to the Gemini Hub, but this prevents other computers from receiving data from the Gemini Hub.
Configure the BCI2000 machine's network interface as follows:
* '''IP address:''' <code>192.168.137.<u>XXX</u></code>, where <code>XXX</code> is below 128, not 10, and ideally below 16Make sure no other computer on the switch uses the same address.
* '''Subnet mask:''' <code>255.255.255.0</code>
* '''Default gateway:''' blank


You will also need to change your interface's network configuration:
To verify connectivity, open a command prompt and run:
* IP address: 192.168.137.XXX where XXX is less than 128.  <u>This number needs to be below 16 and not 10.</u>  Ensure no other computers have this same address on this switch.
ping 192.168.137.128
* Subnet Mask: 255.255.255.0
That is the Gemini Hub's default address.  If the hub responds, the module should be able to reach it.
* Default Gateway: <Blank>
 
To test your network configuration, open a terminal or command prompt and type '''ping 192.168.137.128'''. This is the Gemini Hub's default network address.  If you can ping the Gemini Hub, you should be able to run the module.
===Configuring Channels in Central===
All amplifier-side configuration is done in Blackrock's Central software.  The Gemini Hub always digitises at 30 kHz; each channel can be independently enabled for continuous streaming at 500 Hz, 1 kHz, 2 kHz, 10 kHz, or 30 kHz.  The hub decimates non-30 kHz streams (with antialiasing) before transmission.
 
A sample group may mix neural-amplifier channels and analog-input channels (sync pulses, eye-tracker outputs, photodiode signals, and so on).  Any channel enabled for continuous streaming at the SamplingRate selected in BCI2000 will appear in the signal, regardless of the bank it lives on.  Within the signal, channels are grouped by Blackrock instrument id (neural-amp channels first, analog inputs next), and within each instrument they appear in the order reported by Central.


==Parameters==
==Parameters==
Blackrock systems are very configurable, and it appears to make little sense to reproduce each individual setting as a BCI2000 parameter.
All parameters live under '''Source -- Signal Properties'''.
Rather, you will configure the recording setup using the Blackrock "Central" software, and BCI2000 will auto-configure to match the SampleGroup dictated by the SamplingRate parameter.  Gemini Hubs always acquire data at 30Khz, but channels can be added to a SampleGroup which is downsampled (with antialiasing) in real-time by the Gemini Hub before being streamed over ethernet to receivers.  You can add channels to these channel groups in the Central software by enabling continuous streaming on individual channels, and selecting the sampling rate.


The following parameters are available for configuring the BlackrockGemini source module. You will find these parameters in the Source -- Signal Properties section.
===SamplingRate===
===SamplingRate===
In standard use, this is one of two parameters you need to play with.  This is where you select the sample group you want BCI2000 to record from.  Valid sampling rates are 500 Hz, 1000 Hz, 2000 Hz, 10000 Hz, and 30000 Hz.  When the SetConfig button is pressed, BCI2000 will collect all channels that are members of that SampleGroup and configure to acquire from those channels.
Selects the sample group to record from.  Valid values are 500 Hz, 1000 Hz, 2000 Hz, 10000 Hz, and 30000 Hz.  When <code>SetConfig</code> is pressed, the module collects every channel currently enabled at this rate in Central and configures BCI2000 to acquire them.
 
The sample group can mix neural channels and analog input channels (such as sync, eye-tracking, or photodiode signals).  Any channel you have enabled for continuous streaming in Central at the selected rate will be picked up, regardless of which bank it lives on.  In the BCI2000 signal, neural channels are listed first, followed by the analog input channels, in the order shown by Central.


===SampleBlockSize===
===SampleBlockSize===
There are a bunch of default SampleBlockSizes for the different SamplingRates, which you will get if you use 'auto' as the value of this parameterThey are roughly set to clock BCI2000 at about 50 Hz. Depending on the processing you're doing, you may want to lengthen the block size. Any number of samples is valid here: even 1.  You may want to not do that, however.  Clocking the system above 50 Hz [http://www.youtube.com/watch?v=2FM3Em7FIOc is a bad choice].  The default block size for different sample groups is as follows:
Samples per block per channelSet to <code>auto</code> to pick a default that clocks BCI2000 at approximately 50 Hz:


     int gGroupRates[] = { 0, 500, 1000, 2000, 10000, 30000 }; // samples per second
     int gGroupRates[] = { 0, 500, 1000, 2000, 10000, 30000 }; // samples per second
     int gBlockSizes[] = { 0, 10,  20,  40,  200,  600  }; // samples per block (50 Hz)
     int gBlockSizes[] = { 0, 10,  20,  40,  200,  600  }; // samples per block (~50 Hz)
 
Any positive integer is accepted.  Clocking BCI2000 faster than 50 Hz is [http://www.youtube.com/watch?v=2FM3Em7FIOc generally a bad idea].
 
===SourceCh===
Total number of channels.  Set to <code>auto</code>; the module fills this in from the Central configuration at <code>SetConfig</code> time.


===ChannelNames===
===ChannelNames===
These will be pulled from the Channel Label property set in the Central Software.  Use 'auto' to configure this parameter.
Channel labels.  Populated automatically from the Channel Label column in Central.  Use <code>auto</code>.
 
===SourceChOffset / SourceChGain===
Per-channel offset and gain.  Populated automatically from each channel's <code>cbSCALING</code> limits reported by cbsdk.  Use <code>auto</code>.
 
==States==


===SourceChOffset/SourceChGain===
===NSPSyncState===
Again, these are populated automaticallyUse 'auto' to configure this parameter.
A two-bit state used internally by the module's start-of-run state machineNot intended for downstream analysis.


===NSPInstances===
===BlackrockSourceTimeHigh / BlackrockSourceTimeLow===
This parameter determines how many NSPs you intend to record fromThis is the other parameter that you might want to play with, but only if you have more than one NSP.  Using more than 2 NSPs is untested.
The upper and lower 32 bits of the 64-bit per-sample timestamp produced by the Gemini HubConcatenate as
timestamp_ns = (BlackrockSourceTimeHigh << 32) | BlackrockSourceTimeLow
to obtain nanoseconds since the Unix epoch (1970-01-01 UTC, 1 ns resolution).


===DigitalOutput===
Under the hood, these states are populated by reserving the final two rows of the source signal and labelling them <code>@BlackrockSourceTimeHigh</code> and <code>@BlackrockSourceTimeLow</code>; the <code>@</code> prefix instructs BCI2000 to route those samples into the corresponding state rather than leave them in the signal.
This parameter specifies a matrix of expressions that will be evaluated once per SampleBlock to set the digital output channels.  Each row of this matrix defines an expression for one digital output.  If that expression evaluates true for that block, the associated digital output will be set high, and vice versa for false.  See [[User Reference:Expression Syntax]] for help with BCI2000 Expressions.  An example matrix is provided below.


    Instance Output Expression
==Implementation Notes==
    1        1      StimulusCode!=0 // Will set output 1 on NSP1 high whenever a stimulus is on screen
This section is intended for programmers extending, porting, or debugging the module.
    2        3      KeyDown!=0 // Will set output 3 on NSP2 high whenever a key is pressed.


==States==
===Class Overview===
===BlackrockTimeStampHigh===
<code>BlackrockADC</code> derives from <code>BufferedADC</code>.  Acquisition is callback-driven:
The higher 32 bits of the 64-bit per-sample timestamp sent by the Gemini Hub.
 
===BlackrockTimeStampLow===
* <code>OnStartAcquisition()</code> opens the cbsdk connection and registers <code>DataCallback</code> with <code>cbSdkRegisterCallback(CBSDKCALLBACK_CONTINUOUS)</code>.  Every incoming <code>cbPKT_GROUP</code> is dispatched to <code>OnData()</code> on a cbsdk thread.
The lower 32 bits of the 64-bit per-sample timestamp sent by the Gemini Hub.
* <code>OnData()</code> assembles one composite sample per timestep and pushes it into <code>mDataPacketBuffers</code>.  When enough samples are queued for a full block, it signals <code>mDataAvailable</code>.
The time stamp itself represents the amount of time since the UNIX epoch (1.1.1970), with a resolution of 1ns (one nanosecond, 1e-9 seconds).
* <code>DoAcquire()</code>, running on BCI2000's source thread, blocks on <code>mDataAvailable</code> and drains a block's worth of composite samples into the output signal.
* <code>mDataMutex</code> (a <code>std::recursive_mutex</code>) protects the per-instrument queues, the composite buffers, and the layout vectors.
 
===Per-timestep Packet Pairing===
On Gemini, each timestep is broadcast as '''one <code>cbPKT_GROUP</code> per instrument''' — for example, one for the front-end amplifier and a second for the AINP board.  The <code>cbpkt_header.time</code> field in these packets is a per-packet send time, not a shared sample time, so channels cannot be paired across instruments by matching timestamps.
 
The module pairs them '''by arrival order''' instead:
# Each instrument has its own FIFO in <code>mInstrumentQueues</code>.
# <code>OnData()</code> pushes every packet into the FIFO for its <code>cbpkt_header.instrument</code>.
# While every FIFO is non-empty, the fronts are popped and concatenated into one composite frame in <code>mDataPacketBuffers</code>, with each instrument's samples written at its reserved <code>baseOffset</code> inside the frame.
# A '''resync guard''' flushes every FIFO if any one of them exceeds <code>kMaxInstrumentQueueDepth</code> (8192 packets).  This re-aligns pairing from a clean state if an instrument falls far behind.
 
===Channel Discovery===
<code>GetChannelConfig()</code> deliberately does '''not''' use <code>cbSdkGetSampleGroupList()</code>.  On Gemini, that API reports only front-end channels in the requested sample group; AINP channels configured for the same rate stream as <code>cbPKT_GROUP</code> packets under a different <code>cbpkt_header.instrument</code> and are omitted from the list.
 
Instead, the module probes every channel id from 1 through <code>cbNUM_ANALOG_CHANS</code> with <code>cbSdkGetChannelConfig()</code>, filters by <code>chanInfo.smpgroup == iGroup</code>, groups the survivors by <code>chanInfo.cbpkt_header.instrument</code>, and emits them in ascending instrument-id order.  As a side effect, this yields the instrument id used to route each channel's packets in <code>OnData()</code>.
 
===Build===
The CMake target is Windows-only.  It links against the prebuilt Cerebus SDK in <code>lib/x64/cbsdkx64.lib</code> (x64) or <code>lib/x86/cbsdk.lib</code> (x86).  The headers <code>cbsdk.h</code> and <code>cbhwlib.h</code> ship in <code>include/</code>. Batch files are copied to <code>prog/batch</code>, and the <code>BlackrockGemini.prm</code> fragment to <code>parms/fragments/amplifiers</code>, by <code>BCI2000_ADD_SIGNAL_SOURCE_MODULE</code>.
 
The module has been built and run against both the official Blackrock cbsdk release and the open-source [https://github.com/dashesy/CereLink CereLink] fork; either is compatible.


==See also==
==See also==
[[User Reference:Filters]], [[Contributions:ADCs]], [[Contributions:Blackrock]]
[[User Reference:Filters]], [[Contributions:ADCs]]


[[Category:Contributions]][[Category:Data Acquisition]]
[[Category:Contributions]][[Category:Data Acquisition]]

Latest revision as of 20:34, 20 April 2026

Synopsis

The BlackrockGemini signal source module acquires data from Blackrock Microsystems Gemini acquisition hardware over Ethernet, using the Cerebus SDK (cbsdk). All channel configuration — enabled channels, per-channel sampling rate, gain, and label — is set in Blackrock's Central application and imported into BCI2000 automatically at SetConfig time.

Location

http://www.bci2000.org/svn/trunk/src/contrib/SignalSource/BlackrockGemini

Versioning

Authors

Griffin Milsap (griffin.milsap@gmail.com), Jürgen Mellinger (mellinger@neurotechcenter.org), Nicholas Luczak (luczak@neurotechcenter.org)

Source Code Revisions

  • Initial development: 8061
  • Tested under: 9216
  • Known to compile under: 9216
  • Broken since: N/A

System Setup

Network Configuration

The module talks to the Gemini Hub over UDP and is sensitive to packet loss. Connect the BCI2000 machine and the Gemini Hub to a single commercial-grade switch, or use a crossover cable directly between the two. Do not place a second switch, or a consumer-grade router, in between.

Configure the BCI2000 machine's network interface as follows:

  • IP address: 192.168.137.XXX, where XXX is below 128, not 10, and ideally below 16. Make sure no other computer on the switch uses the same address.
  • Subnet mask: 255.255.255.0
  • Default gateway: blank

To verify connectivity, open a command prompt and run:

ping 192.168.137.128

That is the Gemini Hub's default address. If the hub responds, the module should be able to reach it.

Configuring Channels in Central

All amplifier-side configuration is done in Blackrock's Central software. The Gemini Hub always digitises at 30 kHz; each channel can be independently enabled for continuous streaming at 500 Hz, 1 kHz, 2 kHz, 10 kHz, or 30 kHz. The hub decimates non-30 kHz streams (with antialiasing) before transmission.

A sample group may mix neural-amplifier channels and analog-input channels (sync pulses, eye-tracker outputs, photodiode signals, and so on). Any channel enabled for continuous streaming at the SamplingRate selected in BCI2000 will appear in the signal, regardless of the bank it lives on. Within the signal, channels are grouped by Blackrock instrument id (neural-amp channels first, analog inputs next), and within each instrument they appear in the order reported by Central.

Parameters

All parameters live under Source -- Signal Properties.

SamplingRate

Selects the sample group to record from. Valid values are 500 Hz, 1000 Hz, 2000 Hz, 10000 Hz, and 30000 Hz. When SetConfig is pressed, the module collects every channel currently enabled at this rate in Central and configures BCI2000 to acquire them.

SampleBlockSize

Samples per block per channel. Set to auto to pick a default that clocks BCI2000 at approximately 50 Hz:

   int gGroupRates[] = { 0, 500, 1000, 2000, 10000, 30000 }; // samples per second
   int gBlockSizes[] = { 0, 10,  20,   40,   200,   600   }; // samples per block (~50 Hz)

Any positive integer is accepted. Clocking BCI2000 faster than 50 Hz is generally a bad idea.

SourceCh

Total number of channels. Set to auto; the module fills this in from the Central configuration at SetConfig time.

ChannelNames

Channel labels. Populated automatically from the Channel Label column in Central. Use auto.

SourceChOffset / SourceChGain

Per-channel offset and gain. Populated automatically from each channel's cbSCALING limits reported by cbsdk. Use auto.

States

NSPSyncState

A two-bit state used internally by the module's start-of-run state machine. Not intended for downstream analysis.

BlackrockSourceTimeHigh / BlackrockSourceTimeLow

The upper and lower 32 bits of the 64-bit per-sample timestamp produced by the Gemini Hub. Concatenate as

timestamp_ns = (BlackrockSourceTimeHigh << 32) | BlackrockSourceTimeLow

to obtain nanoseconds since the Unix epoch (1970-01-01 UTC, 1 ns resolution).

Under the hood, these states are populated by reserving the final two rows of the source signal and labelling them @BlackrockSourceTimeHigh and @BlackrockSourceTimeLow; the @ prefix instructs BCI2000 to route those samples into the corresponding state rather than leave them in the signal.

Implementation Notes

This section is intended for programmers extending, porting, or debugging the module.

Class Overview

BlackrockADC derives from BufferedADC. Acquisition is callback-driven:

  • OnStartAcquisition() opens the cbsdk connection and registers DataCallback with cbSdkRegisterCallback(CBSDKCALLBACK_CONTINUOUS). Every incoming cbPKT_GROUP is dispatched to OnData() on a cbsdk thread.
  • OnData() assembles one composite sample per timestep and pushes it into mDataPacketBuffers. When enough samples are queued for a full block, it signals mDataAvailable.
  • DoAcquire(), running on BCI2000's source thread, blocks on mDataAvailable and drains a block's worth of composite samples into the output signal.
  • mDataMutex (a std::recursive_mutex) protects the per-instrument queues, the composite buffers, and the layout vectors.

Per-timestep Packet Pairing

On Gemini, each timestep is broadcast as one cbPKT_GROUP per instrument — for example, one for the front-end amplifier and a second for the AINP board. The cbpkt_header.time field in these packets is a per-packet send time, not a shared sample time, so channels cannot be paired across instruments by matching timestamps.

The module pairs them by arrival order instead:

  1. Each instrument has its own FIFO in mInstrumentQueues.
  2. OnData() pushes every packet into the FIFO for its cbpkt_header.instrument.
  3. While every FIFO is non-empty, the fronts are popped and concatenated into one composite frame in mDataPacketBuffers, with each instrument's samples written at its reserved baseOffset inside the frame.
  4. A resync guard flushes every FIFO if any one of them exceeds kMaxInstrumentQueueDepth (8192 packets). This re-aligns pairing from a clean state if an instrument falls far behind.

Channel Discovery

GetChannelConfig() deliberately does not use cbSdkGetSampleGroupList(). On Gemini, that API reports only front-end channels in the requested sample group; AINP channels configured for the same rate stream as cbPKT_GROUP packets under a different cbpkt_header.instrument and are omitted from the list.

Instead, the module probes every channel id from 1 through cbNUM_ANALOG_CHANS with cbSdkGetChannelConfig(), filters by chanInfo.smpgroup == iGroup, groups the survivors by chanInfo.cbpkt_header.instrument, and emits them in ascending instrument-id order. As a side effect, this yields the instrument id used to route each channel's packets in OnData().

Build

The CMake target is Windows-only. It links against the prebuilt Cerebus SDK in lib/x64/cbsdkx64.lib (x64) or lib/x86/cbsdk.lib (x86). The headers cbsdk.h and cbhwlib.h ship in include/. Batch files are copied to prog/batch, and the BlackrockGemini.prm fragment to parms/fragments/amplifiers, by BCI2000_ADD_SIGNAL_SOURCE_MODULE.

The module has been built and run against both the official Blackrock cbsdk release and the open-source CereLink fork; either is compatible.

See also

User Reference:Filters, Contributions:ADCs