Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to find an appropriate device to wire to #272

Open
ebach23 opened this issue May 9, 2024 · 26 comments
Open

Unable to find an appropriate device to wire to #272

ebach23 opened this issue May 9, 2024 · 26 comments
Labels
question Further information is requested

Comments

@ebach23
Copy link

ebach23 commented May 9, 2024

I posted this on the main spike interface issue page and was suggested the following:
"Looks like we don't have wiring to RHD2216 yet. I would open this issue on the probeinterface repo so that it can be put on the todo list over there. We have tools to allow you to do it manually if you want help with that and if you get that working then you can actually share the mapping with us and we can include it in probeinterface in the future."

We recently switched from a Cambridge Neurotech 64 channel probe to a Cambridge Neurotech 16 channel probe that uses an omnetics adapter to connect to our Intan 16 channel headstage. We are trying to analyze a group of our data obtained with this set-up but are not able to wire to any of the devices that are listed as an option for these probes.
Our probes are: ASSY-1-P-2 - cambridgeneurotech - 16ch - 1shanks
The device options made available are:
['H32>RHD2132',
'ASSY-156>RHD2164',
'ASSY-116>RHD2132',
'ASSY-77>Adpt.A64-Om32_2x-sm-NN>RHD2164',
'ASSY-77>Adpt.A64-Om32_2x-sm-NN>two_RHD2132',
'cambridgeneurotech_mini-amp-64']

All of these appear to be 32 to channel or 64 channel which then read the error: "AssertionError: chan_indices 32 != contact count 16"
Can you help us identify how we can fix this problem?

@alejoe91
Copy link
Member

alejoe91 commented May 9, 2024

Hi! Do you have a channel map for your setup?

@alejoe91 alejoe91 added the question Further information is requested label May 9, 2024
@ebach23
Copy link
Author

ebach23 commented May 9, 2024 via email

@alejoe91
Copy link
Member

alejoe91 commented May 9, 2024

I cannot see the images because I think you replied to the email. Can you reply to the issue instead?

@ebach23
Copy link
Author

ebach23 commented May 9, 2024

Sorry about that. Hopefully it will work now…
image
image

@zm711
Copy link
Contributor

zm711 commented May 17, 2024

@ebach23, could you also share the headstage info you're using. We need to see the final connectors on the other side of the omnetics!

@ebach23
Copy link
Author

ebach23 commented May 22, 2024

Oops, I missed your question until now. The headstage we are using is an Intan C3334 | RHD 16-channel headstage18-pin Omnetics electrode connector

@paulrignanese
Copy link

This would be very useful for our lab as well ! We are also using an omnetics adapter to connect to the Intan headstage for our 4 tetrodes twisted wires.

@oortelli
Copy link

oortelli commented Jan 16, 2025

@zm711 / @alejoe91 : Wondering if any progress has been made? I'm also trying to map the ASSY-1-P2 16 channel cambridge probe to Intan C3334 (RHD 16ch).

@zm711
Copy link
Contributor

zm711 commented Jan 17, 2025

Howdy All!

No progress. Unfortunately we are all super busy with the spinterface repo and trying to get neo up to speed for numpy 2.0. @chrishalcrow is working on better organizing everything we have at this point, but I'm not sure if he would have time for additional maps yet. The normal process for this is that we have at least two independent people verify a map so if you want to give it a try you definitely could and then we can verify (verify is easier than the initial round). Looking at my schedule I wouldn't have time to do this in the near future.

@oortelli
Copy link

I understand, @zm711. I can post my attempt for verification.

Before I do so, I want to make sure my understanding is correct - I need to map the Omnetics pins (from electrode pin output: https://intantech.com/RHD_headstages.html?tabSelect=RHD16ch&yPos=0) with the channel IDs (from Cambridge info: https://www.cambridgeneurotech.com/assets/files/ASSY-1-P-1-P-2-map.pdf).

Because I'm using a Cambridge adaptor with a Cambridge probe, I do NOT need an extra step, per Issue #301 comments... because this is a Cambridge neurotech probe to Cambridge neurotech adaptor.

@zm711
Copy link
Contributor

zm711 commented Jan 17, 2025

Yes you're thinking about this correct. In general the cambridge_neurotech doesn't have the extra change in numbers when using a cambridge_neurotech adaptor. So you basically need to go from the headstage to the channel ids. The only other thing is to keep track of what we index on which will be the headstage numbers (this is the opposite of making a probemap for KS2,2.5 or 3--which some people have done in the past).

@oortelli
Copy link

Ok, thanks, @zm711 ! I'm not fully sure that I'm following you when you say " The only other thing is to keep track of what we index on which will be the headstage numbers (this is the opposite of making a probemap for KS2,2.5 or 3--which some people have done in the past)."

I believe the correct mapping would be: manual_mapping=[14, 10, 9, 13, 15, 11, 8, 12, 3, 5, 4, 1, 2, 0, 6, 7]

I will note that when I run the rest of this chunk (code below) the image of the probe I get doesn't have the same ids as I'd expect from the Cambridge schematic, pics provided.

I'm not sure if this is a separate problem.

Thanks for your thoughts.

probe.set_device_channel_indices(manual_mapping)
fig, ax = plt.subplots(figsize=(10,10))
plot_probe(probe, with_contact_id=True, with_device_index=True, ax=ax)
probe_wired= probe
probe= probe.to_dataframe(complete=True)
probe
pi.write_probeinterface('A1x16-Poly2-10mm-50s-177_wired.json', probe_wired)

Image
Image

@zm711
Copy link
Contributor

zm711 commented Jan 17, 2025

@alejoe91 what do you think? I confirm that if I do this I get

Image

this seems like a mistake or they changed their order of channel ids?

@oortelli thanks for checking this we need to make sure that we have the correct probe from cambridge neurotech first and then we can think about the wiring.

@samuelgarcia
Copy link
Member

I think we have a mistake in our library.
I will check this with cambridge neurotech team.

@ebach23
Copy link
Author

ebach23 commented Jan 20, 2025

Thanks for helping with this issue everyone. I just spoke to Jessie from Cambridge neurotech. She confirmed that the probe is incorrect and the mapping we have on paper is correct. I tried to edit the json file in the library, but it would not read the info. I eventually rewrote from scratch. I wrote the following and would greatly appreciate if someone could check this mapping:

n = 16
positions = np.zeros((n, 2))
for i in range(n):
x = i // 8
y = i % 8
positions[i] = x, y
positions *= 22.5 #this numberr might be 17 in order to make center distance 22.5 apart while incorporating width
positions[8:16, 1] -= -25
probe = Probe(ndim=2, si_units='um')
probe.set_contacts(positions=positions, shapes='rect', shape_params={'width': 11, 'height': 15})
probe.create_auto_shape(probe_type='tip')
contact_indices = [11, 15, 6, 8, 14, 12, 13, 9, 10, 16, 2, 3, 7, 5, 1, 4]
probe.set_contact_ids(contact_indices)
polygon = [(-10, 230), (-10, -20), (35, -70), (66.5, -25), (66.5, 225)]
probe.set_planar_contour(polygon)
print(probe.device_channel_indices)
fig, ax = plt.subplots(figsize=(10,10))
#plot_probe(probe, ax=ax, probe_shape_kwargs={'facecolor': 'purple', 'edgecolor': 'k', 'lw': 0.5, 'alpha': 0.2})
plot_probe(probe, with_contact_id=True, with_device_index=True, ax=ax, probe_shape_kwargs={'facecolor': 'purple', 'edgecolor': 'k', 'lw': 0.5, 'alpha': 0.2})
df = probe.to_dataframe()
print(df)

To map device channel IDs as follows:
manual_mapping=[14, 10, 9, 13, 15, 11, 8, 12, 3, 5, 4, 1, 2, 0, 6, 7]
probe.set_device_channel_indices(manual_mapping)
fig, ax = plt.subplots(figsize=(10,10))
plot_probe(probe, with_contact_id=True, with_device_index=True, ax=ax)
probe_wired= probe

Thanks so much!

@jgoins17
Copy link

@samuelgarcia not sure where this mistake is coming from, I've checked the files in the shared folder we have with you and everything seems in order. Nothing about the mapping has changed. please let us know if you need anything from us to correct.

@jgoins17
Copy link

Here is a channel map pathway for ASSY-1_ADPT16-Om16CN_RHDC3334. If someone verifies this then once @samuelgarcia has figured out where the original error is coming from you will be good to go. [https://docs.google.com/spreadsheets/d/1eiYabG7ehvdEBi2Xn4GgDdNsV9fzYqm6P0Pda8DAB8g/edit?usp=sharing]

@ebach23
Copy link
Author

ebach23 commented Jan 24, 2025

@jgoins17 can you share this in another way? I am unable to view the google file and have tried to request access.

@zm711
Copy link
Contributor

zm711 commented Jan 24, 2025

@jgoins17 did you post the corrected map to the probeinterface_library repo? https://github.com/SpikeInterface/probeinterface_library
My guess is just the wrong json got loaded there. But Sam and Alessio can confirm.

@ebach23
Copy link
Author

ebach23 commented Jan 24, 2025

@zm711 is there a way I can help facilitate this process? Would it help if I post the output I get after spikesorting and plotting in phy? If we interpreted the map we got correctly from jgoins17 the output does not make sense after sorting (kilosort4) and plotting in phy. Here is a screenshot of a unit (blue unit) that seems to have been correctly sorted, but the waveform map doesn't make sense to me.

Image

@zm711
Copy link
Contributor

zm711 commented Jan 24, 2025

This may be related to what I was referring to above. Kilosort prefers to have the map such that the values are just the matrix indices along with their position. For probeinterface we use the mapping to index the data/write the map in the Kilosort way. So I would need to know exactly how you ran this to understand what the exact issue is and how it was generated.

I know this is confusing, but this comes from the fact that KS/Phy organizes their data differently than the object model of spikeinterface/probeinterface (and this was an intentional choice on the SI side). So we handle that translation in the run_sorter, but if a user tries to do the translation themselves we just need to confirm that the two different models don't get mixed up.

@ebach23
Copy link
Author

ebach23 commented Jan 24, 2025

@zm711 thanks for getting back. I think I may have figured out how to correct the mapping. The output now makes sense once I bring it into phy. I think I missed a step in the indexing: Manual mapping after incorporating the alignment of the probe I gave it in accordance to what Jessie had sent in her google doc (and we had mapped the same way) should actually read:

n = 16
positions = np.zeros((n, 2))
for i in range(n):
x = i // 8
y = i % 8
positions[i] = x, y
positions *= 22.5 #this numberr might be 17 in order to make center distance 22.5 apart while incorporating width
positions[8:16, 1] -= -25
probe = Probe(ndim=2, si_units='um')
probe.set_contacts(positions=positions, shapes='rect', shape_params={'width': 11, 'height': 15})
probe.create_auto_shape(probe_type='tip')
contact_indices = [11, 15, 6, 8, 14, 12, 13, 9, 10, 16, 2, 3, 7, 5, 1, 4]
probe.set_contact_ids(contact_indices)
polygon = [(-10, 230), (-10, -20), (35, -70), (66.5, -25), (66.5, 225)]
probe.set_planar_contour(polygon)
print(probe.device_channel_indices)
fig, ax = plt.subplots(figsize=(10,10))
#plot_probe(probe, ax=ax, probe_shape_kwargs={'facecolor': 'purple', 'edgecolor': 'k', 'lw': 0.5, 'alpha': 0.2})
plot_probe(probe, with_contact_id=True, with_device_index=True, ax=ax, probe_shape_kwargs={'facecolor': 'purple', 'edgecolor': 'k', 'lw': 0.5, 'alpha': 0.2})
df = probe.to_dataframe()
print(df)

manual_mapping=[4,6,11,12,0,1,2,3,5,7,10,9,8,15,14,13]
probe.set_device_channel_indices(manual_mapping)
fig, ax = plt.subplots(figsize=(10,10))
plot_probe(probe, with_contact_id=True, with_device_index=True, ax=ax)
probe_wired= probe

Here is the output that I now get in phy from one of the largest units that kilosort4 sorts:

Image

If someone could doublecheck that would be great!
Are you saying you want me to send you every line of code I used to get to the phy output. Happy to do so just making that is what you are asking for.

@zm711
Copy link
Contributor

zm711 commented Jan 24, 2025

I meant that if you were running through Spikeinterface vs running through KS4 gui we would need to see the differences. But at least at initial look this looks pretty good. We will have to carefully verify the mapping you shared to make sure it makes sense, but that Phy screen seems to make sense.

@ebach23
Copy link
Author

ebach23 commented Jan 26, 2025

@zm711 oh ok, I think I understand what you are concerned about now. If I am interpreting what you have said correctly your concern should not impact the mapping. Everything is being run through spikeinterface including sorting using kilosort4 (using container/docker). I then use the export to phy function in spikeinterface to generate the .npy files which in turn are accessed by phy. I have looked at a few more recordings now, and they all seem to make a lot more sense, but if there is someone that can verify the mapping I would feel a lot more confident. Part of the reason I still don't feel convinced is that I based the initial step on

https://github.com/SpikeInterface/SpikeInterface-Training-Edinburgh-May24/blob/main/hands_on/probe_handling/probe_handling.ipynb

This is the mapping that I originally posted in Spikeinterface (issue #2821) on 29 Aug 2024. @oortelli came up with very similar mapping posted last week (I noticed the mistake seemed to be mine). However to make the 'new' map I had to take the entire process one step further than what is outlined in the tutorial above. I can share my spreadsheet if that would help? Essentially I reassigned the order of the mapping in accordance with probe contact locations starting from bottom left to the top left (1:8) and then bottom right to top of right (9:16). So on the probe contact ID1 is located @ location 15 on probe. This contact ID maps onto the headstage as contact 14. Meaning I assigned 14 to slot 15 and so on.

Maybe this is the result of using an adaptor? Although, I was told by @jgoins17 that there was no need for a two step process. So a bit confused and concerned, that if my logic is correct, I made another mapping faux pas as I did back in August. Verification by someone would be great!

@samuelgarcia
Copy link
Member

Hi,
probes ASSY-1-P-1 and ASSY-1-P-2 has been fix in the PR
See this
SpikeInterface/probeinterface_library#13

After this pull request is merge, please remove/rest the probeinterface cache folder in your profile
For instance in my linux it is here /home/samuel/.config/probeinterface/

@oortelli
Copy link

oortelli commented Feb 7, 2025

Hi @samuelgarcia - thanks so much. I’m glad to see this was fixed as I’m hoping this will help resolve my problems. I thought I cleared my cache and got the newest version of probe interface but it seems to still be pulling the old probe. I’m likely doing something wrong and was wondering if you could advise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants