-
Notifications
You must be signed in to change notification settings - Fork 222
Fix a cross-band interpolation bug, and allow time_vector in interpolate_motion #3517
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
Changes from 3 commits
507b6b3
4e38ac1
726170b
e791fe1
82e2600
d8f39b5
0a201e1
ad00beb
28527d2
b3b3fcf
b02860e
df24840
91fb732
b80bad7
c890603
6d2e479
ee29fae
b4c91a0
38e0ada
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -122,14 +122,23 @@ def interpolate_motion_on_traces( | |||||
time_bins = interpolation_time_bin_centers_s | ||||||
if time_bins is None: | ||||||
time_bins = motion.temporal_bins_s[segment_index] | ||||||
bin_s = time_bins[1] - time_bins[0] | ||||||
bins_start = time_bins[0] - 0.5 * bin_s | ||||||
# nearest bin center for each frame? | ||||||
bin_inds = (times - bins_start) // bin_s | ||||||
bin_inds = bin_inds.astype(int) | ||||||
|
||||||
# nearest interpolation bin: | ||||||
# seachsorted(b, t, side="right") == i means that b[i-1] <= t < b[i] | ||||||
|
# seachsorted(b, t, side="right") == i means that b[i-1] <= t < b[i] | |
# searchsorted(b, t, side="right") == i means that b[i-1] <= t < b[i] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, I cannot believe that is not the default behaviour of "left"!
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand this line
cwindolf marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,14 @@ | ||
from pathlib import Path | ||
import warnings | ||
|
||
import numpy as np | ||
import pytest | ||
import spikeinterface.core as sc | ||
from spikeinterface import download_dataset | ||
from spikeinterface.sortingcomponents.motion import Motion | ||
from spikeinterface.sortingcomponents.motion.motion_interpolation import ( | ||
InterpolateMotionRecording, | ||
correct_motion_on_peaks, | ||
interpolate_motion, | ||
interpolate_motion_on_traces, | ||
) | ||
from spikeinterface.sortingcomponents.motion import Motion | ||
from spikeinterface.sortingcomponents.tests.common import make_dataset | ||
|
||
|
||
|
@@ -115,6 +113,66 @@ def test_interpolation_simple(): | |
assert np.all(traces_corrected[:, 2:] == 0) | ||
|
||
|
||
def test_cross_band_interpolation(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a really nice test, super useful also for conceptualising the cross-band interpolation |
||
"""Simple version of using LFP to interpolate AP data | ||
|
||
This also tests the time vector implementation in interpolation. | ||
The idea is to have two recordings which are all 0s with a 1 that | ||
moves from one channel to another after 3s. They're at different | ||
sampling frequencies. motion estimation in one sampling frequency | ||
applied to the other should still lead to perfect correction. | ||
""" | ||
from spikeinterface.sortingcomponents.motion import estimate_motion | ||
|
||
# sampling freqs and timing for AP and LFP recordings | ||
fs_lfp = 50.0 | ||
fs_ap = 300.0 | ||
t_start = 10.0 | ||
total_duration = 5.0 | ||
nt_lfp = int(fs_lfp * total_duration) | ||
nt_ap = int(fs_ap * total_duration) | ||
|
||
t_switch = 3 | ||
|
||
# because interpolation uses bin centers logic, there will be a half | ||
# bin offset at the change point in the AP recording. | ||
halfbin_ap_lfp = int(0.5 * (fs_ap / fs_lfp)) | ||
|
||
# channel geometry | ||
nc = 10 | ||
|
||
geom = np.c_[np.zeros(nc), np.arange(nc)] | ||
|
||
# make an LFP recording which drifts a bit | ||
traces_lfp = np.zeros((nt_lfp, nc)) | ||
traces_lfp[: int(t_switch * fs_lfp), 5] = 1.0 | ||
traces_lfp[int(t_switch * fs_lfp) :, 6] = 1.0 | ||
rec_lfp = sc.NumpyRecording(traces_lfp, sampling_frequency=fs_lfp) | ||
rec_lfp.set_dummy_probe_from_locations(geom) | ||
|
||
# same for AP | ||
traces_ap = np.zeros((nt_ap, nc)) | ||
traces_ap[: int(t_switch * fs_ap) - halfbin_ap_lfp, 5] = 1.0 | ||
traces_ap[int(t_switch * fs_ap) - halfbin_ap_lfp :, 6] = 1.0 | ||
rec_ap = sc.NumpyRecording(traces_ap, sampling_frequency=fs_ap) | ||
rec_ap.set_dummy_probe_from_locations(geom) | ||
|
||
# set times for both, and silence the warning | ||
with warnings.catch_warnings(): | ||
warnings.simplefilter("ignore", category=UserWarning) | ||
rec_lfp.set_times(t_start + np.arange(nt_lfp) / fs_lfp) | ||
rec_ap.set_times(t_start + np.arange(nt_ap) / fs_ap) | ||
|
||
# estimate motion | ||
motion = estimate_motion(rec_lfp, method="dredge_lfp", rigid=True) | ||
|
||
# nearest to keep it simple | ||
rec_corrected = interpolate_motion(rec_ap, motion, spatial_interpolation_method="nearest", num_closest=2) | ||
traces_corrected = rec_corrected.get_traces() | ||
target = np.zeros((nt_ap, nc - 2)) | ||
target[:, 4] = 1 | ||
ii, jj = np.nonzero(traces_corrected) | ||
assert np.array_equal(traces_corrected, target) | ||
|
||
|
||
def test_InterpolateMotionRecording(): | ||
rec, sorting = make_dataset() | ||
motion = make_fake_motion(rec) | ||
|
@@ -148,5 +206,6 @@ def test_InterpolateMotionRecording(): | |
if __name__ == "__main__": | ||
# test_correct_motion_on_peaks() | ||
# test_interpolate_motion_on_traces() | ||
test_interpolation_simple() | ||
test_InterpolateMotionRecording() | ||
# test_interpolation_simple() | ||
# test_InterpolateMotionRecording() | ||
test_cross_band_interpolation() | ||
cwindolf marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to check my understanding, the
searchsorted
on thebin_edges
is functionally equivalent to this approach? (but of course searchsorted is less verbose)