def test_spike_later_than_hilbert(self): # This is a spike clearly outside the bounds st = SpikeTrain([1, 250], units='s', t_start=-1 * pq.s, t_stop=300 * pq.s) phases_noint, _, _ = elephant.phase_analysis.spike_triggered_phase( elephant.signal_processing.hilbert(self.anasig0), st, interpolate=False) self.assertEqual(len(phases_noint[0]), 1) # This is a spike right on the border (length of the signal is 100s, # spike sits at t=100s). However, by definition of intervals in # Elephant (left borders inclusive, right borders exclusive), this # spike is not to be considered. st = SpikeTrain([1, 100], units='s', t_start=-1 * pq.s, t_stop=200 * pq.s) phases_noint, _, _ = elephant.phase_analysis.spike_triggered_phase( elephant.signal_processing.hilbert(self.anasig0), st, interpolate=False) self.assertEqual(len(phases_noint[0]), 1)
def default_data(block=None, n_chidx=1, n_units=1): # generate new block if none provided, otherwise attach to provided block if block is None: block = Block() for id in range(n_chidx): sorting_hash = elephant.spike_sorting.SpikeSorter.get_sorting_hash({ 'channel_index': id, 'random annotation': np.random.randint(0, 10**10) }) chidx = ChannelIndex([], sorting_hash=sorting_hash) chidx.block = block block.channel_indexes.append(chidx) for chidx in block.channel_indexes: for id in range(n_units): unit = Unit(unit_id=id) chidx.units.append(unit) unit.channel_index = chidx for st_id in range(id): st = SpikeTrain(np.random.uniform(0, st_id, 1) * pq.s, t_start=0 * pq.s, t_stop=st_id * pq.s, spiketrain_id=st_id) unit.spiketrains.append(st) st.unit = unit block.create_relationship() return block
def test_write_read_single_spike(self): block1 = Block() seg = Segment('segment1') spiketrain1 = SpikeTrain([1] * pq.s, t_stop=10 * pq.s, sampling_rate=1 * pq.Hz) spiketrain1.annotate(yep='yop') block1.segments.append(seg) seg.spiketrains.append(spiketrain1) # write block filename = self.get_local_path('matlabiotestfile.mat') io1 = self.ioclass(filename) io1.write_block(block1) # read block io2 = self.ioclass(filename) block2 = io2.read_block() self.assertEqual(block1.segments[0].spiketrains[0], block2.segments[0].spiketrains[0]) # test annotations spiketrain2 = block2.segments[0].spiketrains[0] assert 'yep' in spiketrain2.annotations assert spiketrain2.annotations['yep'] == 'yop'
def setUp(self): self.asiga0 = AnalogSignal(np.array( [np.sin(np.arange(0, 20 * math.pi, 0.1))]).T, units='mV', sampling_rate=10 / ms) self.asiga1 = AnalogSignal(np.array([ np.sin(np.arange(0, 20 * math.pi, 0.1)), np.cos(np.arange(0, 20 * math.pi, 0.1)) ]).T, units='mV', sampling_rate=10 / ms) self.asiga2 = AnalogSignal(np.array([ np.sin(np.arange(0, 20 * math.pi, 0.1)), np.cos(np.arange(0, 20 * math.pi, 0.1)), np.tan(np.arange(0, 20 * math.pi, 0.1)) ]).T, units='mV', sampling_rate=10 / ms) self.st0 = SpikeTrain( [9 * math.pi, 10 * math.pi, 11 * math.pi, 12 * math.pi], units='ms', t_stop=self.asiga0.t_stop) self.lst = [ SpikeTrain([9 * math.pi, 10 * math.pi, 11 * math.pi, 12 * math.pi], units='ms', t_stop=self.asiga1.t_stop), SpikeTrain([30, 35, 40], units='ms', t_stop=self.asiga1.t_stop) ]
def setUp(self): # standard testsignals tlen0 = 100 * pq.s f0 = 20. * pq.Hz fs0 = 1 * pq.ms t0 = np.arange( 0, tlen0.rescale(pq.s).magnitude, fs0.rescale(pq.s).magnitude) * pq.s self.anasig0 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) self.st0 = SpikeTrain( np.arange(0, tlen0.rescale(pq.ms).magnitude, 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst0 = BinnedSpikeTrain(self.st0, binsize=fs0) # shortened analogsignals self.anasig1 = self.anasig0.time_slice(1 * pq.s, None) self.anasig2 = self.anasig0.time_slice(None, 99 * pq.s) # increased sampling frequency fs1 = 0.1 * pq.ms self.anasig3 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs1) self.bst1 = BinnedSpikeTrain( self.st0.time_slice(self.anasig3.t_start, self.anasig3.t_stop), binsize=fs1) # analogsignal containing multiple traces self.anasig4 = AnalogSignal( np.array([ np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), np.sin(4 * np.pi * (f0 * t0).simplified.magnitude)]). transpose(), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) # shortened spike train self.st3 = SpikeTrain( np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst3 = BinnedSpikeTrain(self.st3, binsize=fs0) self.st4 = SpikeTrain(np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=5 * fs0, t_stop=tlen0 - 5 * fs0) self.bst4 = BinnedSpikeTrain(self.st4, binsize=fs0) # spike train with incompatible binsize self.bst5 = BinnedSpikeTrain(self.st3, binsize=fs0 * 2.) # spike train with same binsize as the analog signal, but with # bin edges not aligned to the time axis of the analog signal self.bst6 = BinnedSpikeTrain( self.st3, binsize=fs0, t_start=4.5 * fs0, t_stop=tlen0 - 4.5 * fs0)
def test_one_spiketrain_empty(self): '''Test for one empty SpikeTrain, but existing spikes in other''' st = [SpikeTrain( [9 * math.pi, 10 * math.pi, 11 * math.pi, 12 * math.pi], units='ms', t_stop=self.asiga1.t_stop), SpikeTrain([], units='ms', t_stop=self.asiga1.t_stop)] STA = sta.spike_triggered_average(self.asiga1, st, (-1 * ms, 1 * ms)) cmp_array = AnalogSignalArray(np.array([np.zeros(20, dtype=float)]).T, units='mV', sampling_rate=10 / ms) cmp_array = cmp_array / 0. cmp_array.t_start = -1 * ms assert_array_equal(STA[:, 1], cmp_array[:, 0])
def __init__(self, spk_trains, t_starts=None, t_stops=None): """Create a Spikes instance.""" # Create empty instance. self.spk_trains = None self.t_starts = None self.t_stops = None # Init t_starts and t_stops. # Below deals with single values, including None. n_trs = len(spk_trains) if not util.is_iterable(t_starts): t_starts = n_trs * [t_starts] if not util.is_iterable(t_stops): t_stops = n_trs * [t_stops] # Convert into Pandas Series for speed and more functionality. self.t_starts = pd.Series(t_starts) self.t_stops = pd.Series(t_stops) # Create list of Neo SpikeTrain objects. self.spk_trains = pd.Series(index=np.arange(n_trs), dtype=object) for i in self.spk_trains.index: # Remove spikes outside of time window. t_start, t_stop = self.t_starts[i], self.t_stops[i] spk_tr = util.values_in_window(spk_trains[i], t_start, t_stop) self.spk_trains[i] = SpikeTrain(spk_tr, t_start=t_start, t_stop=t_stop)
def test_one_spiketrain_empty(self): """Test for one empty SpikeTrain, but existing spikes in other""" st = [SpikeTrain( [9 * math.pi, 10 * math.pi, 11 * math.pi, 12 * math.pi], units='ms', t_stop=self.asiga1.t_stop), SpikeTrain([], units='ms', t_stop=self.asiga1.t_stop)] with warnings.catch_warnings(): warnings.simplefilter("ignore") """ Ignore the RuntimeWarning: invalid value encountered in true_divide new_signal = f(other, *args) for the empty SpikeTrain. """ STA = sta.spike_triggered_average(self.asiga1, spiketrains=st, window=(-1 * ms, 1 * ms)) assert np.isnan(STA.magnitude[:, 1]).all()
def test_spike_earlier_than_analogsignal(self): st = SpikeTrain([-1 * math.pi, 2 * math.pi], units='ms', t_start=-2 * math.pi, t_stop=20 * math.pi) self.assertRaises(ValueError, sta.spike_triggered_average, self.asiga0, st, (-2 * ms, 2 * ms))
def test_usage_of_spikes(self): st = SpikeTrain([16.5 * math.pi, 17.5 * math.pi, 18.5 * math.pi, 19.5 * math.pi], units='ms', t_stop=20 * math.pi) STA = sta.spike_triggered_average( self.asiga0, st, (-math.pi * ms, math.pi * ms)) self.assertEqual(STA.annotations['used_spikes'], 3) self.assertEqual(STA.annotations['unused_spikes'], 1)
def _pool_spiketrains(trains, extremes='inner'): """ Pool spikes from any number of spike trains into a unique spike train. Parameters ---------- trains: list list of spike trains to merge extremes: str, optional Only spikes of a and b in the specified extremes are considered. * 'inner': pool all spikes from min(a.t_start b.t_start) to max(a.t_stop, b.t_stop) * 'outer': pool all spikes from max(a.tstart_ b.t_start) to min(a.t_stop, b.t_stop) Default: 'inner' Output ------ neo.SpikeTrain containing all spikes in trains falling in the specified extremes """ merge_trains = trains[0] for t in trains[1:]: merge_trains = _pool_two_spiketrains( merge_trains, t, extremes=extremes) t_start, t_stop = merge_trains.t_start, merge_trains.t_stop merge_trains = sorted(merge_trains) merge_trains = np.squeeze(merge_trains) merge_trains = SpikeTrain( merge_trains, t_stop=t_stop, t_start=t_start, units=trains[0].units) return merge_trains
def setUp(self): tlen0 = 100 * pq.s f0 = 20. * pq.Hz fs0 = 1 * pq.ms t0 = np.arange( 0, tlen0.rescale(pq.s).magnitude, fs0.rescale(pq.s).magnitude) * pq.s self.anasig0 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) self.st0 = SpikeTrain( np.arange(50, tlen0.rescale(pq.ms).magnitude - 50, 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.st1 = SpikeTrain( [100., 100.1, 100.2, 100.3, 100.9, 101.] * pq.ms, t_start=0 * pq.ms, t_stop=tlen0)
def _cpp_hom_stat(A, t_stop, rate, t_start=0 * ms): """ Generate a Compound Poisson Process (CPP) with amplitude distribution A and heterogeneous firing rates r=r[0], r[1], ..., r[-1]. Parameters ---------- A : numpy.ndarray Amplitude distribution. A[j] represents the probability of a synchronous event of size j. The sum over all entries of A must be equal to one. t_stop : quantities.Quantity The end time of the output spike trains rate : quantities.Quantity Average rate of each spike train generated t_start : quantities.Quantity, optional The start time of the output spike trains Default: 0 ms Output ------ List of n neo.SpikeTrains, having average firing rate r and correlated such to form a CPP with amplitude distribution a """ # Generate mother process and associated spike labels mother = _mother_proc_cpp_stat( A=A, t_stop=t_stop, rate=rate, t_start=t_start) labels = _sample_int_from_pdf(A, len(mother)) N = len(A) - 1 # Number of trains in output try: # Faster but more memory-consuming approach M = len(mother) # number of spikes in the mother process spike_matrix = np.zeros((N, M), dtype=bool) # for each spike, take its label l for spike_id, l in enumerate(labels): # choose l random trains train_ids = random.sample(range(N), l) # and set the spike matrix for that train for train_id in train_ids: spike_matrix[train_id, spike_id] = True # and spike to True times = [[] for i in range(N)] for train_id, row in enumerate(spike_matrix): times[train_id] = mother[row].view(Quantity) except MemoryError: # Slower (~2x) but less memory-consuming approach print('memory case') times = [[] for i in range(N)] for t, l in zip(mother, labels): train_ids = random.sample(range(N), l) for train_id in train_ids: times[train_id].append(t) trains = [SpikeTrain( times=t, t_start=t_start, t_stop=t_stop) for t in times] return trains
def get_instantaneous_FR(spiketrain, sampling_period, t_start=0., t_stop=5000.): from elephant.statistics import instantaneous_rate as ir_fnc from neo import SpikeTrain from quantities import ms spiketrain = SpikeTrain(spiketrain, t_stop, units='ms', t_start=t_start) return ir_fnc(spiketrain, sampling_period * ms, kernel='auto')
def threshold_detection(signal, threshold=0.0 * mV, sign='above'): """ Returns the times when the analog signal crosses a threshold. Usually used for extracting spike times from a membrane potential. Adapted from version in NeuroTools. Parameters ---------- signal : neo AnalogSignal object 'signal' is an analog signal. threshold : A quantity, e.g. in mV 'threshold' contains a value that must be reached for an event to be detected. Default: 0.0 * mV. sign : 'above' or 'below' 'sign' determines whether to count thresholding crossings that cross above or below the threshold. format : None or 'raw' Whether to return as SpikeTrain (None) or as a plain array of times ('raw'). Returns ------- result_st : neo SpikeTrain object 'result_st' contains the spike times of each of the events (spikes) extracted from the signal. """ assert threshold is not None, "A threshold must be provided" if sign is 'above': cutout = np.where(signal > threshold)[0] elif sign in 'below': cutout = np.where(signal < threshold)[0] if len(cutout) <= 0: events_base = np.zeros(0) else: take = np.where(np.diff(cutout) > 1)[0] + 1 take = np.append(0, take) time = signal.times events = time[cutout][take] events_base = events.magnitude if events_base is None: # This occurs in some Python 3 builds due to some # bug in quantities. events_base = np.array([event.magnitude for event in events]) # Workaround result_st = SpikeTrain(events_base, units=signal.times.units, t_start=signal.t_start, t_stop=signal.t_stop) return result_st
def test_regression_269(self): # This is a spike train on a 30KHz sampling, one spike at 1s, one just # before the end of the signal cu = pq.CompoundUnit("1/30000.*s") st = SpikeTrain( [30000., (self.anasig0.t_stop - 1 * pq.s).rescale(cu).magnitude], units=pq.CompoundUnit("1/30000.*s"), t_start=-1 * pq.s, t_stop=300 * pq.s) phases_noint, _, _ = elephant.phase_analysis.spike_triggered_phase( elephant.signal_processing.hilbert(self.anasig0), st, interpolate=False) self.assertEqual(len(phases_noint[0]), 2)
def test_victor_purpura_matlab_comparison_int(self): repo_path =\ r"unittest/spike_train_dissimilarity/victor_purpura_distance/data" files_to_download = [ ("times_int.npy", "aa1411c04da3f58d8b8913ae2f935057"), ("matlab_results_int.npy", "7edd32e50edde12dc1ef4aa5f57f70fb") ] for filename, checksum in files_to_download: download_datasets(repo_path=f"{repo_path}/{filename}", checksum=checksum) times_int = np.load(ELEPHANT_TMP_DIR / 'times_int.npy') mat_res_int = np.load(ELEPHANT_TMP_DIR / 'matlab_results_int.npy') r_int = SpikeTrain(times_int[0], units='ms', t_start=0, t_stop=1000 * ms) s_int = SpikeTrain(times_int[1], units='ms', t_start=0, t_stop=1000 * ms) t_int = SpikeTrain(times_int[2], units='ms', t_start=0, t_stop=1000 * ms) vic_pur_result_int = stds.victor_purpura_distance( [r_int, s_int, t_int], cost_factor=1.0 / ms, kernel=None, sort=True, algorithm='intuitive') assert_array_equal(vic_pur_result_int, mat_res_int)
def test_victor_purpura_matlab_comparison_float(self): repo_path =\ r"unittest/spike_train_dissimilarity/victor_purpura_distance/data" files_to_download = [ ("times_float.npy", "ed1ff4d2c0eeed4a2b50a456803656be"), ("matlab_results_float.npy", "a17f049e7ad0ddf7ca812e86fdb92646") ] for filename, checksum in files_to_download: download_datasets(repo_path=f"{repo_path}/{filename}", checksum=checksum) times_float = np.load(ELEPHANT_TMP_DIR / 'times_float.npy') mat_res_float = np.load(ELEPHANT_TMP_DIR / 'matlab_results_float.npy') r_float = SpikeTrain(times_float[0], units='ms', t_start=0, t_stop=1000 * ms) s_float = SpikeTrain(times_float[1], units='ms', t_start=0, t_stop=1000 * ms) t_float = SpikeTrain(times_float[2], units='ms', t_start=0, t_stop=1000 * ms) vic_pur_result_float = stds.victor_purpura_distance( [r_float, s_float, t_float], cost_factor=1.0 / ms, kernel=None, sort=True, algorithm='intuitive') assert_array_almost_equal(vic_pur_result_float, mat_res_float)
def test_all_spiketrains_empty(self): st = SpikeTrain([], units='ms', t_stop=self.asiga1.t_stop) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger warnings. STA = sta.spike_triggered_average( self.asiga1, st, (-1 * ms, 1 * ms)) self.assertEqual("No spike at all was either found or used " "for averaging", str(w[-1].message)) nan_array = np.empty(20) nan_array.fill(np.nan) cmp_array = AnalogSignal(np.array([nan_array, nan_array]).T, units='mV', sampling_rate=10 / ms) assert_array_equal(STA.magnitude, cmp_array.magnitude)
def test_spike_triggered_average_with_n_spikes_on_constant_function(self): """Signal should average to the input""" const = 13.8 x = const * np.ones(201) asiga = AnalogSignal( np.array([x]).T, units='mV', sampling_rate=10 / ms) st = SpikeTrain([3, 5.6, 7, 7.1, 16, 16.3], units='ms', t_stop=20) window_starttime = -2 * ms window_endtime = 2 * ms STA = sta.spike_triggered_average( asiga, st, (window_starttime, window_endtime)) a = int(((window_endtime - window_starttime) * asiga.sampling_rate).simplified) cutout = asiga[0: a] cutout.t_start = window_starttime assert_array_almost_equal(STA, cutout, 12)
def test_only_one_spike(self): """The output should be the same as the input""" x = np.arange(0, 20, 0.1) y = x**2 sr = 10 / ms z = AnalogSignal(np.array([y]).T, units='mV', sampling_rate=sr) spiketime = 8 * ms spiketime_in_ms = int((spiketime / ms).simplified) st = SpikeTrain([spiketime_in_ms], units='ms', t_stop=20) window_starttime = -3 * ms window_endtime = 5 * ms STA = sta.spike_triggered_average( z, st, (window_starttime, window_endtime)) cutout = z[int(((spiketime + window_starttime) * sr).simplified): int(((spiketime + window_endtime) * sr).simplified)] cutout.t_start = window_starttime assert_array_equal(STA, cutout)
def _pool_two_spiketrains(a, b, extremes='inner'): """ Pool the spikes of two spike trains a and b into a unique spike train. Parameters ---------- a, b : neo.SpikeTrains Spike trains to be pooled extremes: str, optional Only spikes of a and b in the specified extremes are considered. * 'inner': pool all spikes from max(a.tstart_ b.t_start) to min(a.t_stop, b.t_stop) * 'outer': pool all spikes from min(a.tstart_ b.t_start) to max(a.t_stop, b.t_stop) Default: 'inner' Output ------ neo.SpikeTrain containing all spikes in a and b falling in the specified extremes """ unit = a.units times_a_dimless = list(a.view(Quantity).magnitude) times_b_dimless = list(b.rescale(unit).view(Quantity).magnitude) times = (times_a_dimless + times_b_dimless) * unit if extremes == 'outer': t_start = min(a.t_start, b.t_start) t_stop = max(a.t_stop, b.t_stop) elif extremes == 'inner': t_start = max(a.t_start, b.t_start) t_stop = min(a.t_stop, b.t_stop) times = times[times > t_start] times = times[times < t_stop] else: raise ValueError('extremes (%s) can only be "inner" or "outer"' % extremes) pooled_train = SpikeTrain(times=sorted(times.magnitude), units=unit, t_start=t_start, t_stop=t_stop) return pooled_train
def test_write_read_single_spike(self): block1 = Block() seg = Segment('segment1') spiketrain = SpikeTrain([1] * pq.s, t_stop=10 * pq.s, sampling_rate=1 * pq.Hz) block1.segments.append(seg) seg.spiketrains.append(spiketrain) # write block filename = BaseTestIO.get_filename_path(self, 'matlabiotestfile.mat') io1 = self.ioclass(filename) io1.write_block(block1) # read block io2 = self.ioclass(filename) block2 = io2.read_block() self.assertEqual(block1.segments[0].spiketrains[0], block2.segments[0].spiketrains[0])
def setUp(self): # standard testsignals tlen0 = 100 * pq.s f0 = 20. * pq.Hz fs0 = 1 * pq.ms t0 = np.arange( 0, tlen0.rescale(pq.s).magnitude, fs0.rescale(pq.s).magnitude) * pq.s self.anasig0 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) self.st0 = SpikeTrain( np.arange(0, tlen0.rescale(pq.ms).magnitude, 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst0 = BinnedSpikeTrain(self.st0, bin_size=fs0) def test_old_scipy_version(self): self.assertRaises(AttributeError, sta.spike_field_coherence, self.anasig0, self.bst0)
def _homogeneous_process(interval_generator, args, mean_rate, t_start, t_stop, as_array): """ Returns a spike train whose spikes are a realization of a random process generated by the function `interval_generator` with the given rate, starting at time `t_start` and stopping `time t_stop`. """ def rescale(x): return (x / mean_rate.units).rescale(t_stop.units) n = int(((t_stop - t_start) * mean_rate).simplified) number = np.ceil(n + 3 * np.sqrt(n)) if number < 100: number = min(5 + np.ceil(2 * n), 100) assert number > 4 # if positive, number cannot be less than 5 isi = rescale(interval_generator(*args, size=int(number))) spikes = np.cumsum(isi) spikes += t_start i = spikes.searchsorted(t_stop) if i == len(spikes): # ISI buffer overrun extra_spikes = [] t_last = spikes[-1] + rescale(interval_generator(*args, size=1))[0] while t_last < t_stop: extra_spikes.append(t_last) t_last = t_last + rescale(interval_generator(*args, size=1))[0] # np.concatenate does not conserve units spikes = Quantity(np.concatenate((spikes, extra_spikes)).magnitude, units=spikes.units) else: spikes = spikes[:i] if as_array: spikes = spikes.magnitude else: spikes = SpikeTrain(spikes, t_start=t_start, t_stop=t_stop, units=spikes.units) return spikes
def get_spikes(self, trs=None, t1s=None, t2s=None, ref_ts=None): """Return spike times of given trials within time windows.""" # Init trials and time limits. trs = self.init_trials(trs) t1s, t2s, ref_ts = self.init_time_limits(t1s, t2s, ref_ts) # Assamble time-windowed spike trains. spk_trains = pd.Series(index=trs, dtype=object) for itr in trs: # Select spikes between t1 and t2 during selected trials, and # convert them into new SpikeTrain list, with time limits set. t1, t2, tr = t1s[itr], t2s[itr], ref_ts[itr] spk_tr = util.values_in_window(self.spk_trains[itr], t1, t2) spk_tr, t1, t2 = spk_tr - tr, t1 - tr, t2 - tr # align to reference time # Need to check range once again to deal with rounding errors. spk_tr = util.values_in_window(spk_tr, t1, t2) spk_trains[itr] = SpikeTrain(spk_tr, t_start=t1, t_stop=t2) return spk_trains
def calc_corellation(spike_times, spike_ids, num, duration, bin_x=None): # Create randomly shuffled indices neuron_indices = np.arange(num) np.random.shuffle(neuron_indices) # Loop through indices spike_trains = [] for n in neuron_indices: # Extract spike times neuron_spike_times = spike_times[spike_ids == n] # If there are any spikes if len(neuron_spike_times) > 0: # Add neo SpikeTrain object spike_trains.append( SpikeTrain(neuron_spike_times * ms, t_start=1 * s, t_stop=10 * s)) # If we have found our 200 spike trains, stop if len(spike_trains) == 200: break # Check that 200 spike trains containing spikes could be found assert len(spike_trains) == 200 # Bin spikes using bins corresponding to 2ms refractory period binned_spike_trains = BinnedSpikeTrain(spike_trains, binsize=2.0 * ms) # Calculate correlation matrix correlation = corrcoef(binned_spike_trains) # Take lower triangle of matrix (minus diagonal) correlation_non_disjoint = correlation[np.tril_indices_from(correlation, k=-1)] # Calculate histogram return calc_histogram(correlation_non_disjoint, 0.002, bin_x)
event = Event(name="Seg {} :: Event".format(idx), times=event_times, labels=["A", "B", "C", "D", "E"]) seg.events.append(event) epoch_times = tstart + np.cumsum(np.array([0,1,2])) * pq.ms epoch = Epoch(name="Seg {} :: Epoch".format(idx), times=epoch_times, durations=np.array([0,1,2])*pq.ms, labels=["A+", "B+", "C+"]) seg.epochs.append(epoch) tstart = 10 *pq.s st_times = tstart + np.cumsum(np.arange(0,1,0.1)) * pq.s tstop = max(event_times[-1], epoch_times[-1], st_times[-1]) + 1 * pq.s st = SpikeTrain(name="Seg {} :: SpikeTrain".format(idx), times=st_times, t_start=tstart, t_stop=tstop) wf = np.random.random((len(st_times), nchannels, 30)) * pq.mV st.waveforms = wf st.sampling_rate = sampling_rate seg.spiketrains.append(st) unit = Unit(name="unit-{}".format(idx)) print(unit) unit.spiketrains.append(st) chx.units.append(unit) # Write the Block to file using the NixIO # Any existing file will be overwritten fname = "test_case.nix" io = NixIO(fname, "ow") io.write_block(block1)
class sfc_TestCase_new_scipy(unittest.TestCase): def setUp(self): # standard testsignals tlen0 = 100 * pq.s f0 = 20. * pq.Hz fs0 = 1 * pq.ms t0 = np.arange( 0, tlen0.rescale(pq.s).magnitude, fs0.rescale(pq.s).magnitude) * pq.s self.anasig0 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) self.st0 = SpikeTrain( np.arange(0, tlen0.rescale(pq.ms).magnitude, 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst0 = BinnedSpikeTrain(self.st0, binsize=fs0) # shortened analogsignals self.anasig1 = self.anasig0.time_slice(1 * pq.s, None) self.anasig2 = self.anasig0.time_slice(None, 99 * pq.s) # increased sampling frequency fs1 = 0.1 * pq.ms self.anasig3 = AnalogSignal( np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs1) self.bst1 = BinnedSpikeTrain( self.st0.time_slice(self.anasig3.t_start, self.anasig3.t_stop), binsize=fs1) # analogsignal containing multiple traces self.anasig4 = AnalogSignal( np.array([ np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), np.sin(4 * np.pi * (f0 * t0).simplified.magnitude)]). transpose(), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) # shortened spike train self.st3 = SpikeTrain( np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst3 = BinnedSpikeTrain(self.st3, binsize=fs0) self.st4 = SpikeTrain(np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=5 * fs0, t_stop=tlen0 - 5 * fs0) self.bst4 = BinnedSpikeTrain(self.st4, binsize=fs0) # spike train with incompatible binsize self.bst5 = BinnedSpikeTrain(self.st3, binsize=fs0 * 2.) # spike train with same binsize as the analog signal, but with # bin edges not aligned to the time axis of the analog signal self.bst6 = BinnedSpikeTrain( self.st3, binsize=fs0, t_start=4.5 * fs0, t_stop=tlen0 - 4.5 * fs0) # ========================================================================= # Tests for correct input handling # ========================================================================= def test_wrong_input_type(self): self.assertRaises(TypeError, sta.spike_field_coherence, np.array([1, 2, 3]), self.bst0) self.assertRaises(TypeError, sta.spike_field_coherence, self.anasig0, [1, 2, 3]) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0.duplicate_with_new_array([]), self.bst0) def test_start_stop_times_out_of_range(self): self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig1, self.bst0) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig2, self.bst0) def test_non_matching_input_binning(self): self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst1) def test_incompatible_spiketrain_analogsignal(self): # These spike trains have incompatible binning (binsize or alignment to # time axis of analog signal) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst5) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst6) def test_signal_dimensions(self): # single analogsignal trace and single spike train s_single, f_single = sta.spike_field_coherence(self.anasig0, self.bst0) self.assertEqual(len(f_single.shape), 1) self.assertEqual(len(s_single.shape), 2) # multiple analogsignal traces and single spike train s_multi, f_multi = sta.spike_field_coherence(self.anasig4, self.bst0) self.assertEqual(len(f_multi.shape), 1) self.assertEqual(len(s_multi.shape), 2) # frequencies are identical since same sampling frequency was used # in both cases and data length is the same assert_array_equal(f_single, f_multi) # coherences of s_single and first signal in s_multi are identical, # since first analogsignal trace in anasig4 is same as in anasig0 assert_array_equal(s_single[:, 0], s_multi[:, 0]) def test_non_binned_spiketrain_input(self): s, f = sta.spike_field_coherence(self.anasig0, self.st0) f_ind = np.where(f >= 19.)[0][0] max_ind = np.argmax(s[1:]) + 1 self.assertEqual(f_ind, max_ind) self.assertAlmostEqual(s[f_ind], 1., delta=0.01) # ========================================================================= # Tests for correct return values # ========================================================================= def test_spike_field_coherence_perfect_coherence(self): # check for detection of 20Hz peak in anasig0/bst0 s, f = sta.spike_field_coherence( self.anasig0, self.bst0, window='boxcar') f_ind = np.where(f >= 19.)[0][0] max_ind = np.argmax(s[1:]) + 1 self.assertEqual(f_ind, max_ind) self.assertAlmostEqual(s[f_ind], 1., delta=0.01) def test_output_frequencies(self): nfft = 256 _, f = sta.spike_field_coherence(self.anasig3, self.bst1, nfft=nfft) # check number of frequency samples self.assertEqual(len(f), nfft / 2 + 1) # check values of frequency samples assert_array_almost_equal( f, np.linspace( 0, self.anasig3.sampling_rate.rescale('Hz').magnitude / 2, nfft / 2 + 1) * pq.Hz) def test_short_spiketrain(self): # this spike train has the same length as anasig0 s1, f1 = sta.spike_field_coherence( self.anasig0, self.bst3, window='boxcar') # this spike train has the same spikes as above, but is shorter than # anasig0 s2, f2 = sta.spike_field_coherence( self.anasig0, self.bst4, window='boxcar') # the results above should be the same, nevertheless assert_array_equal(s1.magnitude, s2.magnitude) assert_array_equal(f1.magnitude, f2.magnitude)
class sfc_TestCase_new_scipy(unittest.TestCase): def setUp(self): # standard testsignals tlen0 = 100 * pq.s f0 = 20. * pq.Hz fs0 = 1 * pq.ms t0 = np.arange(0, tlen0.rescale(pq.s).magnitude, fs0.rescale(pq.s).magnitude) * pq.s self.anasig0 = AnalogSignal(np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) self.st0 = SpikeTrain(np.arange(0, tlen0.rescale(pq.ms).magnitude, 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst0 = BinnedSpikeTrain(self.st0, bin_size=fs0) # shortened analogsignals self.anasig1 = self.anasig0.time_slice(1 * pq.s, None) self.anasig2 = self.anasig0.time_slice(None, 99 * pq.s) # increased sampling frequency fs1 = 0.1 * pq.ms self.anasig3 = AnalogSignal(np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs1) self.bst1 = BinnedSpikeTrain(self.st0.time_slice( self.anasig3.t_start, self.anasig3.t_stop), bin_size=fs1) # analogsignal containing multiple traces self.anasig4 = AnalogSignal(np.array([ np.sin(2 * np.pi * (f0 * t0).simplified.magnitude), np.sin(4 * np.pi * (f0 * t0).simplified.magnitude) ]).transpose(), units=pq.mV, t_start=0 * pq.ms, sampling_period=fs0) # shortened spike train self.st3 = SpikeTrain(np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=0 * pq.ms, t_stop=tlen0) self.bst3 = BinnedSpikeTrain(self.st3, bin_size=fs0) self.st4 = SpikeTrain(np.arange( (tlen0.rescale(pq.ms).magnitude * .25), (tlen0.rescale(pq.ms).magnitude * .75), 50) * pq.ms, t_start=5 * fs0, t_stop=tlen0 - 5 * fs0) self.bst4 = BinnedSpikeTrain(self.st4, bin_size=fs0) # spike train with incompatible bin_size self.bst5 = BinnedSpikeTrain(self.st3, bin_size=fs0 * 2.) # spike train with same bin_size as the analog signal, but with # bin edges not aligned to the time axis of the analog signal self.bst6 = BinnedSpikeTrain(self.st3, bin_size=fs0, t_start=4.5 * fs0, t_stop=tlen0 - 4.5 * fs0) # ========================================================================= # Tests for correct input handling # ========================================================================= def test_wrong_input_type(self): self.assertRaises(TypeError, sta.spike_field_coherence, np.array([1, 2, 3]), self.bst0) self.assertRaises(TypeError, sta.spike_field_coherence, self.anasig0, [1, 2, 3]) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0.duplicate_with_new_data([]), self.bst0) def test_start_stop_times_out_of_range(self): self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig1, self.bst0) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig2, self.bst0) def test_non_matching_input_binning(self): self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst1) def test_incompatible_spiketrain_analogsignal(self): # These spike trains have incompatible binning (bin_size or alignment # to time axis of analog signal) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst5) self.assertRaises(ValueError, sta.spike_field_coherence, self.anasig0, self.bst6) def test_signal_dimensions(self): # single analogsignal trace and single spike train s_single, f_single = sta.spike_field_coherence(self.anasig0, self.bst0) self.assertEqual(len(f_single.shape), 1) self.assertEqual(len(s_single.shape), 2) # multiple analogsignal traces and single spike train s_multi, f_multi = sta.spike_field_coherence(self.anasig4, self.bst0) self.assertEqual(len(f_multi.shape), 1) self.assertEqual(len(s_multi.shape), 2) # frequencies are identical since same sampling frequency was used # in both cases and data length is the same assert_array_equal(f_single, f_multi) # coherences of s_single and first signal in s_multi are identical, # since first analogsignal trace in anasig4 is same as in anasig0 assert_array_equal(s_single[:, 0], s_multi[:, 0]) def test_non_binned_spiketrain_input(self): s, f = sta.spike_field_coherence(self.anasig0, self.st0) f_ind = np.where(f >= 19.)[0][0] max_ind = np.argmax(s[1:]) + 1 self.assertEqual(f_ind, max_ind) self.assertAlmostEqual(s[f_ind], 1., delta=0.01) # ========================================================================= # Tests for correct return values # ========================================================================= def test_spike_field_coherence_perfect_coherence(self): # check for detection of 20Hz peak in anasig0/bst0 with warnings.catch_warnings(): warnings.simplefilter("ignore") """ When the spiketrain is a vector with zero values, ignore the warning RuntimeWarning: invalid value encountered in true_divide Cxy = np.abs(Pxy)**2 / Pxx / Pyy. """ s, f = sta.spike_field_coherence(self.anasig0, self.bst0, window='boxcar') f_ind = np.where(f >= 19.)[0][0] max_ind = np.argmax(s[1:]) + 1 self.assertEqual(f_ind, max_ind) self.assertAlmostEqual(s[f_ind], 1., delta=0.01) def test_output_frequencies(self): nfft = 256 _, f = sta.spike_field_coherence(self.anasig3, self.bst1, nfft=nfft) # check number of frequency samples self.assertEqual(len(f), nfft / 2 + 1) f_max = self.anasig3.sampling_rate.rescale('Hz').magnitude / 2 f_ground_truth = np.linspace(start=0, stop=f_max, num=nfft // 2 + 1) * pq.Hz # check values of frequency samples assert_array_almost_equal(f, f_ground_truth) def test_short_spiketrain(self): # this spike train has the same length as anasig0 with warnings.catch_warnings(): warnings.simplefilter("ignore") """ When the spiketrain is a vector with zero values, ignore the warning RuntimeWarning: invalid value encountered in true_divide Cxy = np.abs(Pxy)**2 / Pxx / Pyy. """ s1, f1 = sta.spike_field_coherence(self.anasig0, self.bst3, window='boxcar') # this spike train has the same spikes as above, # but it's shorter than anasig0 s2, f2 = sta.spike_field_coherence(self.anasig0, self.bst4, window='boxcar') # the results above should be the same, nevertheless assert_array_equal(s1.magnitude, s2.magnitude) assert_array_equal(f1.magnitude, f2.magnitude)
def test_empty_analogsignal(self): asiga = AnalogSignal([], units='mV', sampling_rate=10 / ms) st = SpikeTrain([5], units='ms', t_stop=10) self.assertRaises(ValueError, sta.spike_triggered_average, asiga, st, (-1 * ms, 1 * ms))