Skip to content

Commit

Permalink
Update EphysSocket Plugin documentation (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
bparks13 authored Mar 26, 2024
1 parent 08d861e commit 0bd4655
Show file tree
Hide file tree
Showing 9 changed files with 1,024 additions and 743 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/sphinx-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
# 2. Add and commit HTML files to gh-pages branch
- name: Commit documentation changes
run: |
git clone https://github.com/open-ephys/gui-docs.git --branch gh-pages --single-branch gh-pages
git clone https://github.com/${{ github.repository_owner }}/gui-docs.git --branch gh-pages --single-branch gh-pages
cd gh-pages
rm -rf *
cp -r ../docs/html/* .
Expand Down
79 changes: 64 additions & 15 deletions source/User-Manual/Plugins/Ephys-Socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ Ephys Socket
.. image:: ../../_static/images/plugins/ephyssocket/ephyssocket-01.png
:alt: Annotated Ephys Socket Editor

.. csv-table:: Receives continuous data from the OpenCVMatSocket in Bonsai. This is intended to be a quick way to stream ephys data from Bonsai, for example if you're performing closed-loop feedback in Bonsai, but want to visualize your data in the Open Ephys GUI.
.. csv-table:: Receives formatted data from a TCP socket that implements a particular :ref:`header format <Header Format for Custom Data Streams>`. A common use case is to receive data streamed from :ref:`Bonsai <In Bonsai>`. This is intended to be a quick way to stream ephys data from a third-party application and visualize in the Open Ephys GUI. Below is a way to setup streaming between Bonsai and the Open Ephys GUI, which can be extended to other software and/or hardware that carry the same header format.
:widths: 18, 80

"*Plugin Type*", "Source"
"*Platforms*", "Windows, Linux, macOS"
"*Built in?*", "No"
"*Key Developers*", "Jon Newman"
"*Key Developers*", "Jon Newman, Brandon Parks"
"*Source Code*", "https://github.com/open-ephys-plugins/ephys-socket"

Installing and upgrading
Expand All @@ -31,41 +31,90 @@ Plugin Configuration
In Bonsai
-----------

#. Make sure you have the "**Bonsai.Ephys**" and "**Bonsai.JonsUtils**" packages installed. For the latter, you'll have to set the package source to "Community Packages".
#. Make sure you have the **Bonsai.Ephys** and **OpenEphys.Sockets.Bonsai** packages installed. For the latter, you'll have to set the package source to "Community Packages".

#. Create a signal chain that includes (at least):

* A source that generates an OpenCV.Net.Mat output (e.g. Rhd2000EvalBoard, which is compatible with the Open Ephys acquisition board)
* A source that generates an `OpenCV.Net.Mat` output (e.g., :code:`Rhd2000EvalBoard`, which is compatible with the Open Ephys acquisition board)

* A member selector that isolates the OpenCV.Net.Mat output
* A member selector that isolates the `OpenCV.Net.Mat` output

* The OpenCVMatSocket from JonsUtils.
* The :code:`TcpServer` and :code:`SendMatOverSocket` nodes from **OpenEphys.Sockets.Bonsai**.

#. Click on the OpenCVMatSocket, and change the port number to :code:`9001`.
#. Click on the :code:`TcpServer`, and edit the fields there:

#. (Optional) Add a "Select Channels" operator before OpenCVMatSocket, to select a subset of channels for streaming.
* Set the address (for communication within the same computer, put "localhost" without quotes)

* Add a name to use for the connection channel. This can be an arbitrary name, but must match the same name used in the :code:`SendMatOverSocket` node

* Change the port number to :code:`9001`

#. (Optional) Add a "Select Channels" operator before :code:`SendMatOverSocket`, to select a subset of channels for streaming.

#. Click on the :code:`SendMatOverSocket` node, and choose the connection created previously from the drop-down menu

#. Start the workflow to initiate the data stream.

The workflow should look something like the one pictured below (:code:`.bonsai` file available in the `Ephys Socket GitHub repo <https://github.com/open-ephys-plugins/ephys-socket/tree/main/Resources>`__):

.. image:: ../../_static/images/plugins/ephyssocket/ephyssocket-02.png
:alt: A compatible Bonsai workflow
:alt: A compatible Bonsai workflow using hardware


A second workflow is included in the same `Resources folder <https://github.com/open-ephys-plugins/ephys-socket/tree/main/Resources>`__ which uses a function generator (imported from **Bonsai.Dsp**). This workflow is useful for testing socket connections without requiring hardware to be connected:

.. image:: ../../_static/images/plugins/ephyssocket/ephyssocket-03.png
:alt: A compatible Bonsai workflow using a function generator


In Open Ephys
--------------

#. Drag and drop the Ephys Socket plugin onto the signal chain.

#. Add downstream plugins (e.g., LFP Viewer)
#. Add downstream filters or sinks (i.e., :code:`LFP Viewer`, :code:`Record Node`, etc.).

#. Ensure the **port** matches the same number used in Bonsai.

#. Ensure the **frequency** parameter matches the sample rate of the Bonsai data stream. By default the Open Ephys acquisition board acquires data at 30000 Hz.

#. Change the **offset** and **scale** values as needed, but it is important to know that the Open Ephys GUI works in microvolts represented as floating points. These values may be required to transform your data into microvolts; for example, the Open Ephys Acquisition Board requires a scale of 0.195 and an offset of 32768 to correctly convert data from `uint16` to `float` values.

* If values are sent as microvolts, then **scale** and **offset** can be set to 1 and 0, respectively. Note that this will require more bandwidth.

#. Click the "Connect" button to establish the connection with Bonsai. If it's not connecting, make sure the Bonsai workflow is running, and the **port** numbers match. Once the connection is made, all input parameters will be grayed out, and cannot be changed until the socket is disconnected.

* If no data is being sent from Bonsai yet (e.g., the acquisition board is still initializing), the socket will not connect. Wait until the hardware is actively sending data before attempting to connect the socket.

#. Start acquisition in Open Ephys. If all is working, you should see the data stream in the LFP Viewer.

#. If the header format is changed in any way, such as by modifying the number of channels or changing the data type, the Open Ephys GUI will automatically detect these changes and stop acquiring data.

* If the GUI was not actively acquiring data, it is necessary to disconnect the socket and connect again to read the updated header values.

* Note that attempting to start acquisition after changing these values will automatically disconnect the socket anyway, forcing a new connection to be made.

.. warning:: This plugin does not guarantee that samples will not be lost in transit, so it's essential to save your data stream on the Bonsai end. There are at least two ways data loss can occur: 1) When a data stream is first connected, there is no guarantee that the data will be saved, since data is not acquired immediately after connecting the socket. 2) If too much data is being sent and the Open Ephys GUI cannot process the data quickly enough, some packets may be lost due to the TCP buffer filling up. If you suspect samples are being dropped (e.g., if the LFP Viewer is not updating at the expected speed), sending a lower bandwidth might fix the problem.


Header Format for Custom Data Streams
######################################

#. If the downstream plugins are grayed out, click the "Connect" button to re-establish the connection with Bonsai. If it's not connecting, make sure the Bonsai workflow is running, and the port numbers match.
While the :code:`SendMatOverSocket` node (found in **OpenEphys.Sockets.Bonsai**, see :ref:`In Bonsai` for details) is a common use case for sending `OpenCV.Net.Mat` data over the TCP socket, it is not the only way to stream data. As long as whatever is used to stream data (e.g., a Python script that sends data over the TCP socket) correctly prepends a header to the data stream, Ephys Socket can correctly interpret the data.

#. Make sure the "channels" parameter matches the number of channels coming out of Bonsai. You shouldn't have to change the "samples", "offset", or "scale" parameters unless you are interfacing with a custom data stream.
An example Python script is included in the `Resources <https://github.com/open-ephys-plugins/ephys-socket/tree/main/Resources>`__ folder of the plugin repository, which implements the format described here. Each variable is 4 bytes long (with the exception of the Bit Depth, which is 2 bytes long), and must be sent in the order listed below. The total header length is 22 bytes.

#. Ensure the "frequency" parameter matches the sample rate of the Bonsai data stream. By default the Open Ephys acquisition board acquires data at 30000 Hz.
.. csv-table:: Ephys Socket header variables
:widths: 18, 10, 60

"**Variable**", "**Data Type**", "**Description**"
"Offset", "`int32`", "Integer defining the offset in the data stream. For TCP sockets, value must always be set to **0**."
"Number of Bytes", "`int32`", "Total number of bytes sent in each packet. Calculated as :code:`num_bytes = num_channels * num_samples * element_size`. This does **not** include the header bytes."
"Bit Depth", "int16", "Depth defines the OpenCV.Mat `Depth <https://github.com/horizongir/opencv.net/blob/main/src/OpenCV.Net/CoreTypes.cs#L93>`__, an enumeration defined as :code:`[U8, S8, U16, S16, S32, F32, F64]`, where U is 'unsigned', S is 'signed', F is 'float', and the number indicates the number of bits. For example, :code:`U16` means 'unsigned integer with 16 bits'. Note that the enumeration is zero-indexed, where :code:`U8 = 0`, and :code:`F64 = 6`"
"Element Size", "`int32`", "Number of bytes needed for each sample. For :code:`U16`, :code:`element_size = 2`, while for :code:`F64`, :code:`element_size = 8`."
"Number of Channels", "`int32`", "Number of channels per packet."
"Number of Samples", "`int32`", "Number of samples sent per channel per packet."

#. Start acquisition in Open Ephys. If all is working, you should see the data stream in the LFP Viewer. If the buffer size (number of channels) doesn't match, Open Ephys won't be able to acquire data.
.. note::

.. warning:: This plugin doesn't currently guarantee that samples won't be lost in transit, so it's essential to save your data stream on the Bonsai end. We are working on implementing a buffering system on the Open Ephys side, to ensure that all samples are being received. If you suspect samples are being dropped (e.g., if the LFP Viewer is not updating at the expected speed), sending fewer channels at a time should fix the problem.
Pay attention to the order of data samples in the example script. Samples are not interleaved, but rather in each packet the samples for channel 1 are sent, followed by the samples for channel 2, and so on.
Binary file modified source/_static/images/plugins/ephyssocket/ephyssocket-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 0bd4655

Please sign in to comment.