Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions articles/hardware/hs64/ts4231.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,33 @@ tracking capabilities.
:::

The <xref:OpenEphys.Onix1.TS4231V1PositionData> operator generates a sequence of
[TS4231V1PositionDataFrames](xref:OpenEphys.Onix1.TS4231V1PositionDataFrame). A `TS4231V1PositionDataFrame` is emitted
when a receiver on the Headstage 64 captures a sequence of 12 optical signals from a pair of lighthouses which occurs at
30 Hz. Therefore, with no occlusions, the maximum achievable sample rate is 30 Hz per receiver. There are three
receivers on the Headstage 64, so `TS4231V1PositionData` can emit up to 3 `TS4231V1PositionDataFrames` in a single 30 Hz
sampling cycle. Of course, if occlusions cause receivers to miss optical signals, this rate will be reduced.
[TS4231V1PositionDataFrames](xref:OpenEphys.Onix1.TS4231V1PositionDataFrame). A
`TS4231V1PositionDataFrame` is emitted when a receiver on the Headstage 64 captures a sequence of 12
optical signals from a pair of lighthouses which occurs at 30 Hz. Therefore, with no occlusions, the
maximum achievable sample rate is 30 Hz per receiver. There are three receivers on the Headstage 64,
so `TS4231V1PositionData` can emit up to 3 `TS4231V1PositionDataFrames` in a single 30 Hz sampling
cycle. Of course, if occlusions cause receivers to miss optical signals, this rate will be reduced.

The `TS4231V1PositionData`'s `DeviceName` property is set to "Headstage64/TS4231V1". This links the
`TS4231V1PositionData` operator to the corresponding configuration operator.

The [CsvWriter](xref:Bonsai.IO.CsvWriter) operator writes the `Clock`, and `Position`
members from the `TS4231V1PositionDataFrame` to a file with the following name format: `ts4231v1__<filecount>.csv`.
Because `CsvWriter` is a _sink_ operator, its output sequence is equivalent to its input sequence. In other words, its
output is equivalent to `TS4231V1PositionData`'s output. Therefore, it's possible to use
[MemberSelector](xref:Bonsai.Expressions.MemberSelectorBuilder) operators on the
`CsvWriter` to select members from `TS4231V1PositionDataFrame`. This is most easily performed by clicking the relevant
members that appear by hovering over the "Output" option that appears in the context menu that appears after
right-clicking the `CsvWriter` node. The <xref:OpenEphys.Onix1.TS4231V1PositionDataFrame.Position> member is selected in
the workflow to help visualize the position data by double-clicking the node when the workflow is running
The [CsvWriter](xref:Bonsai.IO.CsvWriter) operator writes the `Clock` and `Position` members from
the `TS4231V1PositionDataFrame` output by `TS4231V1PositionData` to a file with the following name
format: `uncalibrated-ts4231v1__<filecount>.csv`. Because `CsvWriter` is a _sink_ operator, its
output sequence is equivalent to its input sequence. In other words, its output is equivalent to
`TS4231V1PositionData`'s output. Therefore, it's possible to connect it directly to
<xref:OpenEphys.Onix1.TS4231V1SpatialTransform> which takes `TS4231V1PositionDataFrame` as its
input. To learn how to use this operator to transform coordinates in the TS4231 device reference
frame to a reference frame that is more intuitive or relevant to teh experiment, checkout out the
<xref:calibrate-ts4231> tutorial page.

`TS4231V1SpatialTransform` connects directly to another `CsvWriter` -- this one writes `Clock` and
`Position` members from the `TS4231V1PositionDataFrame` output by `TS4231V1PositionData` to a file
with the following name format: `calibrated-ts4231v1__<filecount>.csv`. The
[MemberSelector](xref:Bonsai.Expressions.MemberSelectorBuilder) operator on the `CsvWriter` to
selects a members from `TS4231V1PositionDataFrame`. The easiest way to place a `MemberSelector` is
is to click the relevant members that appear by hovering over the "Output"
option that appears in the context menu that appears after right-clicking the `CsvWriter` node. The
<xref:OpenEphys.Onix1.TS4231V1PositionDataFrame.Position> member is selected in the workflow to help
visualize the position data by double-clicking the node when the workflow is running. For more
details on visualizing data, checkout the <xref:visualize-data> page.
143 changes: 143 additions & 0 deletions articles/tutorials/calibrate-ts4231.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
uid: calibrate-ts4231
title: Calibrate Positional Tracking Data
---

This tutorial shows how to transform XYZ position coordinates measured by a TS4231 device which are
originally in the device's reference frame to coordinates that are in a reference frame that is more
intuitive or relevant to the experiment. This is performed by determining the position coordinates
of four points in both the TS4231 device's reference frame and the user-defined reference frame to
calculate a spatial transform matrix which transforms all coordinates measured by the TS4231 device to the
user-defined coordinate system.

^^^
![crop of figure 3 from "ONIX: a unified open-source platform..."](../../images/tutorials/calibrate-ts4231/ts4231-figure-demo.webp)
^^^ From figure 3 of [ONIX: a unified open-source platform for multimodal neural recording and perturbation during naturalistic behavior](https://www.nature.com/articles/s41592-024-02521-1), the TS4231 device was used to track a mouse's 3D position over the course of a 7.3-h-long recording.

## Setup

1. First, confirm the Lighthouse transmitters are properly mounted according to the [Lighthouse
Setup Guide](https://open-ephys.github.io/onix-docs/Hardware%20Guide/Lighthouses/setup.html) in
the ONIX Hardware docs.
1. Follow the [Getting Started](xref:getting-started) guide to set up and familiarize yourself with
Bonsai. In particular, [download the necessary Bonsai
packages](xref:install-configure-bonsai#package-installation) or [check for
updates](xref:install-configure-bonsai#update-packages) if they're already installed.
1. Copy the following workflow into the Bonsai workflow editor by hovering over the
workflow image and clicking on the clipboard icon that appears.

::: workflow
![SVG of copyable TS4231 calibration workflow](../../workflows/tutorials/calibrate-ts4231/calibrate-ts4231.bonsai)
:::

Open Bonsai and paste this workflow by clicking the Bonsai workflow editor pane and pressing
<kbd>Ctrl+V</kbd>.

Visit the <xref:hs64_workflow> and <xref:hs64_ts4231> pages to develop a foundation on how to
use Bonsai to acquire data from an ONIX headstage that has a TS4231 device. The primary
difference between this workflow and the example Headstage 64 workflow is that this one has
a transform operator for converting coordinates in the TS4231V1 reference frame to a user defined
reference frame.
1. Before beginning the calibration process, confirm that the lighthouse configuration can measure
the position of your TS4231 device across the entire desired range. To do this, [start the
workflow](xref:workflow-editor#starting-the-workflow) and confirm that the
<xref:OpenEphys.Onix1.TS4231V1PositionData> operator continually produces data as you slowly
move the headstage across the entire range of your arena while inspecting the
TS4231V1PositionData Position [visualizer](xref:visualize-data). If at some point the
TS4231V1PositionData operator stops producing data during this process (e.g. the Position
visualizer stops updating), the TS4231 receivers are either obstructed from or no longer within
range of the Lighthouse base station transmitters. Remedying this might require modifying the
lighthouse configuration or reducing the size of your arena.

## TS4231 Spatial Data Calibration

1. Open the TS4231V1 Position Calibration GUI.

- Start the workflow.
- Open the <xref:OpenEphys.Onix1.TS4231V1SpatialTransform> Position visualizer.
- Click TS4231V1SpatialTransform node to show its properties in the properties panel.
- Click the <kbd>...</kbd> next to the "SpatialTransform" property.

![Screenshot of blank TS4231V1 Calibration GUI](../../images/tutorials/calibrate-ts4231/calibration-gui.png)

1. Mark four points in your behavioral arena. The position coordinates of these four points will be
measured both in the TS4231 reference frame by the TS4231 device itself and in the user-defined
reference frame (if they are not already known, for example, using some features in the behavioral
arena with known dimensions). Here is a simple way to choose the four points:

1. The user-defined origin
2. A point in the behavioral arena along the user-defined X-axis
3. A point in the behavioral arena along the user-defined Y-axis
4. A point in the behavioral arena along the user-defined Z-axis

> [!TIP]
> Choosing the furthest extent along the X, Y, & Z axes minimizes the propagation of measurement
> error into the spatial transformation matrix. Balance this consideration with ease of knowing
> or measuring those coordinates.

Here is a real-world example of four sets of coordinates on our workbench that we use to
demonstrate the calibration process:

![Photo of four calibration points](../../images/tutorials/calibrate-ts4231/calibration-points.webp){width=75%}

The light red space is an arbitrarily-defined working area for this demo.
Units are in cm.

1. For each of the four points defined in the previous step:

- Choose a row in the TS4231V1 Calibration GUI to correspond to that point.
- Place your TS4231 device at that point and click the <kbd>Measure</kbd> button in the
corresponding row. The GUI will start taking measurements from the TS4231 device as long as
the TS4231 device is within range of and unobstructed from the lighthouse transmitter. If
the TS4231 measurement completes successfully, the corresponding entry in form is
automatically populated. Otherwise, that entry stays empty. In either case, you will be
informed in the "Status Messages" text box. If the TS4231 measurement fails, you may have to
reorient your Headstage64 or go back to the step in the previous section that describes how
to make sure the lighthouse configuration covers the entire area that your TS4231 device
will occupy.
- Populate the X, Y, and Z entries of the user-defined coordinates column in the corresponding
row.

> [!TIP]
> Be as precise and accurate as possible with both the placement of the
> TS4231 device and the manual measurements. Consider making a fixture to
> fix the orientation of the TS4231 device and help set it in positions that
> are more easily measured.

Once all fields in the Calibration GUI are populated with valid entries, the spatial transform
matrix is automatically calculated. When the spatial transform matrix is calculated, this will
be indicated in the GUI's bottom status strip and the spatial transform matrix text box such as
in the following screenshot:

![Screenshot of TS4231V1 Calibration GUI with calculated matrix](../../images/tutorials/calibrate-ts4231/calibration-gui_matrix-calculated.png)

1. After the spatial transform is calculated, click OK to proceed. This updates the spatial transform
matrix used by the TS4231V1SpatialTransform operator. This recalibrated spatial transform matrix
should be immediately apparent in the TS4231V1SpatialTransform position data visualizer.

If you are presented with the following confirmation, return to the TS4231 Calibration GUI main
form to fix the entries that were indicated invalid in the confirmation dialog.

![Screenshot of TS4231V1 Calibration GUI confirmation dialog](../../images/tutorials/calibrate-ts4231/calibration-gui_confirmation-dialog.png)

> [!IMPORTANT]
> After calibrating the TS4231V1 spatial transform matrix, it is important to not change the
> TS4231PositionData operator's P/Q property values or move the lighthouse base stations or else
> the calibrated spatial transform matrix will no longer be accurate.

## Verify TS4231 Calibration

After following one of the two methods in the previous section, [visualize](xref:visualize-data) the
calibrated data and confirm that the transformed data matches your expectations. Inspecting the
Position visualizer in Bonsai while moving the TS4231 device is a first-order test. To be more
robust, choose a bunch of points (none of which should be the four calibration points) and check
that their calibrated coordinates are what you expect.

Below is an animation of the 3D trajectory reconstructed in Python synced with video data for
demonstration purposes.

<video controls style="width:100%">
<source src="../../images/tutorials/calibrate-ts4231/ts4231-calibration-demo.mp4" type="video/mp4">
</video>


13 changes: 10 additions & 3 deletions articles/tutorials/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ title: Tutorials
---

This section contains tutorials that demonstrate how to make the most of
the Bonsai library by combining ONIX with third party software tools
th OpenEphys.Onix1 Bonsai package by combining ONIX with third party software tools.

<!-- , tuning closed loop
response times, etc.. -->
Tutorials include:

- [Process & Listen to Ephys Data](xref:ephys-process-listen): serves as a primer for processing
data in Bonsai.
- [Visualize Data in the Open Ephys GUI](xref:ephys-socket): teaches how to stream ephys data from
Bonsai to the Open Ephys GUI through an intermediary TCP connection for advanced visualizations.
- [Calibrate TS4231 Measurements](xref:calibrate-ts4231): demonstrates how to convert TS4231
position coordinates from the TS4231 device reference frame to a reference frame that is more
intuitive or relevant to the experimental system using the TS4231V1 Position Calibration GUI.
2 changes: 2 additions & 0 deletions articles/tutorials/toc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
- href: index.md
expanded: true
items:
- href: ephys-processing-listening.md
- href: ephys-socket.md
- href: calibrate-ts4231.md
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
72 changes: 67 additions & 5 deletions workflows/hardware/hs64/hs64.bonsai
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,67 @@
</Combinator>
</Expression>
<Expression xsi:type="io:CsvWriter">
<io:FileName>ts4231_.csv</io:FileName>
<io:FileName>uncalibrated_ts4231_.csv</io:FileName>
<io:Append>false</io:Append>
<io:Overwrite>false</io:Overwrite>
<io:Suffix>FileCount</io:Suffix>
<io:IncludeHeader>false</io:IncludeHeader>
<io:Selector>Clock,Position</io:Selector>
</Expression>
<Expression xsi:type="Combinator">
<Combinator xsi:type="onix1:TS4231V1SpatialTransform">
<onix1:SpatialTransform>
<onix1:A>
<onix1:M11>NaN</onix1:M11>
<onix1:M12>NaN</onix1:M12>
<onix1:M13>NaN</onix1:M13>
<onix1:M14>1</onix1:M14>
<onix1:M21>NaN</onix1:M21>
<onix1:M22>NaN</onix1:M22>
<onix1:M23>NaN</onix1:M23>
<onix1:M24>1</onix1:M24>
<onix1:M31>NaN</onix1:M31>
<onix1:M32>NaN</onix1:M32>
<onix1:M33>NaN</onix1:M33>
<onix1:M34>1</onix1:M34>
<onix1:M41>NaN</onix1:M41>
<onix1:M42>NaN</onix1:M42>
<onix1:M43>NaN</onix1:M43>
<onix1:M44>1</onix1:M44>
<onix1:Translation>
<onix1:X>NaN</onix1:X>
<onix1:Y>NaN</onix1:Y>
<onix1:Z>NaN</onix1:Z>
</onix1:Translation>
</onix1:A>
<onix1:B>
<onix1:M11>NaN</onix1:M11>
<onix1:M12>NaN</onix1:M12>
<onix1:M13>NaN</onix1:M13>
<onix1:M14>1</onix1:M14>
<onix1:M21>NaN</onix1:M21>
<onix1:M22>NaN</onix1:M22>
<onix1:M23>NaN</onix1:M23>
<onix1:M24>1</onix1:M24>
<onix1:M31>NaN</onix1:M31>
<onix1:M32>NaN</onix1:M32>
<onix1:M33>NaN</onix1:M33>
<onix1:M34>1</onix1:M34>
<onix1:M41>NaN</onix1:M41>
<onix1:M42>NaN</onix1:M42>
<onix1:M43>NaN</onix1:M43>
<onix1:M44>1</onix1:M44>
<onix1:Translation>
<onix1:X>NaN</onix1:X>
<onix1:Y>NaN</onix1:Y>
<onix1:Z>NaN</onix1:Z>
</onix1:Translation>
</onix1:B>
</onix1:SpatialTransform>
</Combinator>
</Expression>
<Expression xsi:type="io:CsvWriter">
<io:FileName>calibrated_ts4231_.csv</io:FileName>
<io:Append>false</io:Append>
<io:Overwrite>false</io:Overwrite>
<io:Suffix>FileCount</io:Suffix>
Expand Down Expand Up @@ -318,17 +378,19 @@
<Edge From="14" To="15" Label="Source1" />
<Edge From="16" To="17" Label="Source1" />
<Edge From="17" To="18" Label="Source1" />
<Edge From="18" To="19" Label="Source1" />
<Edge From="19" To="20" Label="Source1" />
<Edge From="20" To="21" Label="Source1" />
<Edge From="21" To="22" Label="Source1" />
<Edge From="22" To="23" Label="Source1" />
<Edge From="23" To="24" Label="Source1" />
<Edge From="24" To="25" Label="Source1" />
<Edge From="24" To="28" Label="Source1" />
<Edge From="25" To="26" Label="Source1" />
<Edge From="26" To="27" Label="Source1" />
<Edge From="26" To="30" Label="Source1" />
<Edge From="27" To="28" Label="Source1" />
<Edge From="28" To="29" Label="Source1" />
<Edge From="29" To="30" Label="Source1" />
<Edge From="30" To="31" Label="Source1" />
<Edge From="31" To="32" Label="Source1" />
<Edge From="33" To="34" Label="Source1" />
</Edges>
</Workflow>
</WorkflowBuilder>
Loading