|
| 1 | +""" |
| 2 | +Working with tetrodes |
| 3 | +===================== |
| 4 | +
|
| 5 | +Tetrodes are a common recording method for electrophysiological data. It is also common |
| 6 | +to record from several tetrodes at the same time. In this 'how to' we'll see how to |
| 7 | +work with data from two tetrodes, each with four channels. |
| 8 | +
|
| 9 | +We'll start by importing some functions we'll use in this How To guide |
| 10 | +""" |
| 11 | + |
| 12 | +import spikeinterface.preprocessing as spre |
| 13 | +from spikeinterface.widgets import plot_traces, plot_probe_map |
| 14 | +from spikeinterface import generate_ground_truth_recording |
| 15 | + |
| 16 | +from probeinterface import generate_tetrode, ProbeGroup |
| 17 | + |
| 18 | +############################################################################## |
| 19 | +# In practice, you would read in your raw data from a file. Instead, we will generate a |
| 20 | +# recording with eight channels. We can also set a duration, number of units and |
| 21 | +# sampling frequency. |
| 22 | + |
| 23 | +recording, _ = generate_ground_truth_recording( |
| 24 | + durations = [60], # make the recording 60s long |
| 25 | + sampling_frequency=30_000, |
| 26 | + num_channels=8, |
| 27 | + num_units=10, |
| 28 | +) |
| 29 | + |
| 30 | +############################################################################## |
| 31 | +# We now need to define the probe. This will tell the recording which channels came from |
| 32 | +# which tetrode. To do this, we will use the :code:`generate_tetrode` function from :code:`ProbeInterface` |
| 33 | +# to generate two 4-channel probes (representing one tetrode each). In our case, since we |
| 34 | +# don't know the relative distances between the tetrodes, we will move the second |
| 35 | +# tetrode away from the first by 100 microns. This is just so we can visualize the |
| 36 | +# results more easily. Eventually, we will sort each tetrode separately, so their |
| 37 | +# relative distance won't affect the results. |
| 38 | + |
| 39 | +# Technically, we will add each tetrode to a :code:`ProbeGroup`. Read more in the ProbeInterface |
| 40 | +# docs. |
| 41 | + |
| 42 | +# Create each individual tetrode |
| 43 | +tetrode_1 = generate_tetrode() |
| 44 | +tetrode_1.create_auto_shape() |
| 45 | + |
| 46 | +tetrode_2 = generate_tetrode() |
| 47 | +tetrode_2.move([100, 0]) |
| 48 | +tetrode_2.create_auto_shape() |
| 49 | + |
| 50 | +# Add the two tetrodes to a ProbeGroup |
| 51 | +tetrode_group = ProbeGroup() |
| 52 | +tetrode_group.add_probe(tetrode_1) |
| 53 | +tetrode_group.add_probe(tetrode_2) |
| 54 | + |
| 55 | +# Now we need to "wire" our tetrodes to ensure that each contact |
| 56 | +# can be associated with the correct channel when we attach it |
| 57 | +# to the recording. In this example we are just using `range` |
| 58 | +# but see ProbeInterface for more tutorials on wiring |
| 59 | +tetrode_group.set_global_device_channel_indices(range(8)) |
| 60 | + |
| 61 | +############################################################################## |
| 62 | +# We can now attach the :code:`tetrode_group` to our recording. To check if this worked, we'll |
| 63 | +# plot the probe map |
| 64 | + |
| 65 | +recording_with_probe = recording.set_probegroup(tetrode_group) |
| 66 | +plot_probe_map(recording_with_probe) |
| 67 | + |
| 68 | +############################################################################## |
| 69 | +# Looks good! Now that the recording is aware of the probe geometry, we can |
| 70 | +# begin a standard spike sorting pipeline. First, we can apply preprocessing. |
| 71 | +# Note that we apply this preprocessing on the entire bundle of tetrodes. |
| 72 | + |
| 73 | +preprocessed_recording = spre.bandpass_filter(recording_with_probe) |
| 74 | + |
| 75 | +############################################################################## |
| 76 | +# WARNING: a very common preprocessing step is to apply a common median |
| 77 | +# reference. This subtracts the median signal from all channels to help |
| 78 | +# remove noise. However, for a tetrode, a spike is often seen on all |
| 79 | +# channels. So removing the median can remove the entire spike! |
| 80 | +# This is still a danger if you have two tetrodes in a bundle, which |
| 81 | +# might pick up the same spike, but becomes less dangerous |
| 82 | +# as the number of tetrodes in your bundle increases. |
| 83 | +# |
| 84 | +# Tetrodes often have dead channels, so it is advised to try and detect |
| 85 | +# and remove these. For tetrodes, we should use a detection method which |
| 86 | +# doesn't depend on the channel locations such as std or mad: |
| 87 | + |
| 88 | +recording_good_channels = spre.detect_and_remove_bad_channels( |
| 89 | + preprocessed_recording, |
| 90 | + method = "std", |
| 91 | +) |
| 92 | + |
| 93 | +############################################################################## |
| 94 | +# It can be a good idea to sort your tetrode data separately for each tetrode. |
| 95 | +# When we use :code:`set_probegroup`, the channels are automatically |
| 96 | +# labelled by which probe in the probe group they belong to. We can access |
| 97 | +# this labeling using the "group" property. |
| 98 | + |
| 99 | +print(recording_good_channels.get_property("group")) |
| 100 | + |
| 101 | +############################################################################## |
| 102 | +# We can then use this information to split the recording by the group property: |
| 103 | + |
| 104 | +grouped_recordings = recording_good_channels.split_by('group') |
| 105 | +print(grouped_recordings) |
| 106 | + |
| 107 | +############################################################################## |
| 108 | +# Now that we've got preprocess, clean data. Let's take a look at a |
| 109 | +# snippet of data from the first group: |
| 110 | + |
| 111 | +plot_traces(grouped_recordings[0]) |
| 112 | + |
| 113 | +############################################################################## |
| 114 | +# Beautiful! We are now ready to sort. To read more about sorting by group, see |
| 115 | +# :ref:`sorting-by-channel-group`. Note that many modern sorters are designed |
| 116 | +# to sort data from high-density probes and will fail for tetrodes. Please read |
| 117 | +# each spike sorter's documentation to find out if it is appropriate for tetrodes. |
0 commit comments