def regular_gaussian_generator(self, rate, phase=0.0, scale=5., t_start=0.0, t_stop=1000.0, array=False): """ Returns a SpikeTrain whose spikes are regularly spaced, but jittered according to a Gaussian distribution around the spiking period, with the given rate (Hz) and stopping time t_stop (milliseconds). Note: t_start is always 0.0, thus all realizations are as if they spiked at t=0.0, though this spike is not included in the SpikeList. Inputs: rate - the rate of the discharge (in Hz) t_start - the beginning of the SpikeTrain (in ms) t_stop - the end of the SpikeTrain (in ms) phase - Offset the spiketrain by this number (in ms.) scale - width of the Gaussian distribution placed at the regular spike times, according to which the spike will be drawn (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeTrain object. Examples: >> regular_generator(50, 0, 1000) >> regular_generator(20, 5000, 10000, array=True) See also: inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator """ import scipy.stats n = (t_stop - t_start) / 1000.0 * rate t_bin = 1 time_axis = numpy.arange(t_start, t_stop, t_bin) if n > 0: t_peaks = numpy.arange( t_start, t_stop, 1000. / rate, dtype='float') + phase else: t_peaks = numpy.array([]) #Some spikes will fall off the starting edge. Get rid of them t_peaks = t_peaks[t_peaks > 0.] spike_times = numpy.array( [scipy.stats.norm.rvs(t, scale) for t in t_peaks]) if not array: return SpikeTrain(spike_times, t_start=t_start, t_stop=t_stop) else: return numpy.sort(spike_times)
def regular_generator(self, rate, phase=0.0, jitter=True, t_start=0.0, t_stop=1000.0, array=False): """ Returns a SpikeTrain whose spikes are regularly spaced with the given rate (Hz) and stopping time t_stop (milliseconds). Note: t_start is always 0.0, thus all realizations are as if they spiked at t=0.0, though this spike is not included in the SpikeList. Inputs: rate - the rate of the discharge (in Hz) t_start - the beginning of the SpikeTrain (in ms) phase - Offset the spiketrain by this number (in ms.) jitter - whether the spiketrain should be jittered by an amount numpy.random.rand()/rate t_stop - the end of the SpikeTrain (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeTrain object. Examples: >> regular_generator(50, 0, 1000) >> regular_generator(20, 5000, 10000, array=True) See also: inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator """ # less wasteful than double length method above n = (t_stop - t_start) / 1000.0 * rate #jitter if n > 0: spikes = numpy.arange(t_start, t_stop, 1000. / rate, dtype='float') + phase else: spikes = numpy.array([]) if jitter: spikes += numpy.random.rand() * 1000. / rate #Remove any spikes that extend beyond t_stop spikes = spikes[spikes < t_stop] if not array: spikes = SpikeTrain(spikes, t_start=t_start, t_stop=t_stop) return spikes
def threshold_detection(self, threshold=None, format=None,sign='above'): """ Returns the times when the analog signal crosses a threshold. The times can be returned as a numpy.array or a SpikeTrain object (default) Inputs: threshold - Threshold format - when 'raw' the raw events array is returned, otherwise this is a SpikeTrain object by default sign - 'above' detects when the signal gets above the threshodl, 'below when it gets below the threshold' Examples: >> aslist.threshold_detection(-55, 'raw') [54.3, 197.4, 206] """ assert threshold is not None, "threshold must be provided" if sign is 'above': cutout = numpy.where(self.signal > threshold)[0] elif sign in 'below': cutout = numpy.where(self.signal < threshold)[0] if len(cutout) <= 0: events = numpy.zeros(0) else: take = numpy.where(numpy.diff(cutout)>1)[0]+1 take = numpy.append(0,take) time = self.time_axis() events = time[cutout][take] if format is 'raw': return events else: return SpikeTrain(events,t_start=self.t_start,t_stop=self.t_stop)
def _inh_2Dadaptingmarkov_generator_python(self, a, bq, tau_s, tau_r, qrqs, t, t_stop, array=False): """ Returns a SpikeList whose spikes are an inhomogeneous realization (dynamic rate) of the so-called 2D adapting markov process (see references). 2D implies the process has two states, an adaptation state, and a refractory state, both of which affect its probability to spike. The implementation uses the thinning method, as presented in the references. For the 1d implementation, with no relative refractoriness, see the inh_adaptingmarkov_generator. Inputs: a,bq - arrays of the parameters of the hazard function where a[i] and bq[i] will be active on interval [t[i],t[i+1]] tau_s - the time constant of adaptation (in milliseconds). tau_r - the time constant of refractoriness (in milliseconds). qrqs - the ratio of refractoriness conductance to adaptation conductance. typically on the order of 200. t - an array specifying the time bins (in milliseconds) at which to specify the rate t_stop - length of time to simulate process (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeList object. Note: - t_start=t[0] - a is in units of Hz. Typical values are available in Fig. 1 of Muller et al 2007, a~5-80Hz (low to high stimulus) - bq here is taken to be the quantity b*q_s in Muller et al 2007, is thus dimensionless, and has typical values bq~3.0-1.0 (low to high stimulus) - qrqs is the quantity q_r/q_s in Muller et al 2007, where a value of qrqs = 3124.0nS/14.48nS = 221.96 was used. - tau_s has typical values on the order of 100 ms - tau_r has typical values on the order of 2 ms References: Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories Neural Comput. 2007 19: 2958-3010. Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. Examples: See source:trunk/examples/stgen/inh_2Dmarkov_psth.py See also: inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator """ from numpy import shape if shape(t) != shape(a) or shape(a) != shape(bq): raise ValueError('shape mismatch: t,a,b must be of the same shape') # get max rate and generate poisson process to be thinned rmax = numpy.max(a) ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) isi = numpy.zeros_like(ps) isi[1:] = ps[1:] - ps[:-1] isi[0] = ps[0] # -0.0 # assume spike at 0.0 # return empty if no spikes if len(ps) == 0: return SpikeTrain(numpy.array([]), t_start=t[0], t_stop=t_stop) # gen uniform rand on 0,1 for each spike rn = numpy.array(self.rng.uniform(0, 1, len(ps))) # instantaneous a,bq for each spike idx = numpy.searchsorted(t, ps) - 1 spike_a = a[idx] spike_bq = bq[idx] keep = numpy.zeros(shape(ps), bool) # thin spikes i = 0 t_last = 0.0 t_i = 0 # initial adaptation state is unadapted, i.e. large t_s t_s = 1000 * tau_s t_r = 1000 * tau_s while (i < len(ps)): # find index in "t" time, without searching whole array each time t_i = numpy.searchsorted(t[t_i:], ps[i], 'right') - 1 + t_i # evolve adaptation state t_s += isi[i] t_r += isi[i] if rn[i] < a[t_i] * numpy.exp(-bq[t_i] * (numpy.exp( -t_s / tau_s) + qrqs * numpy.exp(-t_r / tau_r))) / rmax: # keep spike keep[i] = True # remap t_s state t_s = -tau_s * numpy.log(numpy.exp(-t_s / tau_s) + 1) t_r = -tau_r * numpy.log(numpy.exp(-t_r / tau_r) + 1) i += 1 spike_train = ps[keep] if array: return spike_train return SpikeTrain(spike_train, t_start=t[0], t_stop=t_stop)
def _inh_gamma_generator_python(self, a, b, t, t_stop, array=False): """ Returns a SpikeList whose spikes are a realization of an inhomogeneous gamma process (dynamic rate). The implementation uses the thinning method, as presented in the references. Inputs: a,b - arrays of the parameters of the gamma PDF where a[i] and b[i] will be active on interval [t[i],t[i+1]] t - an array specifying the time bins (in milliseconds) at which to specify the rate t_stop - length of time to simulate process (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeList object. Note: t_start=t[0] a is a dimensionless quantity > 0, but typically on the order of 2-10. a = 1 results in a poisson process. b is assumed to be in units of 1/Hz (seconds). References: Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories Neural Comput. 2007 19: 2958-3010. Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. Examples: See source:trunk/examples/stgen/inh_gamma_psth.py See also: inh_poisson_generator, gamma_hazard """ from numpy import shape if shape(t) != shape(a) or shape(a) != shape(b): raise ValueError('shape mismatch: t,a,b must be of the same shape') # get max rate and generate poisson process to be thinned rmax = numpy.max(1.0 / b) ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) # return empty if no spikes if len(ps) == 0: if array: return numpy.array([]) else: return SpikeTrain(numpy.array([]), t_start=t[0], t_stop=t_stop) # gen uniform rand on 0,1 for each spike rn = numpy.array(self.rng.uniform(0, 1, len(ps))) # instantaneous a,b for each spike idx = numpy.searchsorted(t, ps) - 1 spike_a = a[idx] spike_b = b[idx] keep = numpy.zeros(shape(ps), bool) # thin spikes i = 0 t_last = 0.0 t_i = 0 while (i < len(ps)): # find index in "t" time t_i = numpy.searchsorted(t[t_i:], ps[i], 'right') - 1 + t_i if rn[i] < gamma_hazard( (ps[i] - t_last) / 1000.0, a[t_i], b[t_i]) / rmax: # keep spike t_last = ps[i] keep[i] = True i += 1 spike_train = ps[keep] if array: return spike_train return SpikeTrain(spike_train, t_start=t[0], t_stop=t_stop)
def inh_poisson_generator(self, rate, t, t_stop, base_generator=None, array=False, **base_generator_kwargs): """ Returns a SpikeList whose spikes are a realization of an inhomogeneous poisson process (dynamic rate). The implementation uses the thinning method, as presented in the references. Inputs: rate - an array of the rates (Hz) where rate[i] is active on interval [t[i],t[i+1]] t - an array specifying the time bins (in milliseconds) at which to specify the rate t_stop - length of time to simulate process (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeList object. Note: t_start=t[0] References: Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories Neural Comput. 2007 19: 2958-3010. Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. Examples: >> time = arange(0,1000) >> stgen.inh_poisson_generator(time,sin(time), 1000) See also: poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator """ if base_generator == None: base_generator = self.poisson_generator if numpy.shape(t) != numpy.shape(rate): raise ValueError( 'shape mismatch: t,rate must be of the same shape') # get max rate and generate poisson process to be thinned rmax = numpy.max(rate) ps = base_generator(rmax, t_start=t[0], t_stop=t_stop, array=True, **base_generator_kwargs) # return empty if no spikes if len(ps) == 0: if array: return numpy.array([]) else: return SpikeTrain(numpy.array([]), t_start=t[0], t_stop=t_stop) # gen uniform rand on 0,1 for each spike rn = numpy.array(self.rng.uniform(0, 1, len(ps))) # instantaneous rate for each spike idx = numpy.searchsorted(t, ps) - 1 spike_rate = rate[idx] # thin and return spikes spike_train = ps[rn < spike_rate / rmax] if array: return spike_train return SpikeTrain(spike_train, t_start=t[0], t_stop=t_stop)
def poisson_generator(self, rate, t_start=0.0, t_stop=1000.0, array=False, debug=False): """ Returns a SpikeTrain whose spikes are a realization of a Poisson process with the given rate (Hz) and stopping time t_stop (milliseconds). Note: t_start is always 0.0, thus all realizations are as if they spiked at t=0.0, though this spike is not included in the SpikeList. Inputs: rate - the rate of the discharge (in Hz) t_start - the beginning of the SpikeTrain (in ms) t_stop - the end of the SpikeTrain (in ms) array - if True, a numpy array of sorted spikes is returned, rather than a SpikeTrain object. Examples: >> gen.poisson_generator(50, 0, 1000) >> gen.poisson_generator(20, 5000, 10000, array=True) See also: inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator """ #number = int((t_stop-t_start)/1000.0*2.0*rate) # less wasteful than double length method above n = (t_stop - t_start) / 1000.0 * rate number = numpy.ceil(n + 3 * numpy.sqrt(n)) if number < 100: number = min(5 + numpy.ceil(2 * n), 100) if number > 0: isi = self.rng.exponential(1.0 / rate, number) * 1000.0 if number > 1: spikes = numpy.add.accumulate(isi) else: spikes = isi else: spikes = numpy.array([]) spikes += t_start i = numpy.searchsorted(spikes, t_stop) extra_spikes = [] if i == len(spikes): # ISI buf overrun t_last = spikes[-1] + self.rng.exponential(1.0 / rate, 1)[0] * 1000.0 while (t_last < t_stop): extra_spikes.append(t_last) t_last += self.rng.exponential(1.0 / rate, 1)[0] * 1000.0 spikes = numpy.concatenate((spikes, extra_spikes)) if debug: print "ISI buf overrun handled. len(spikes)=%d, len(extra_spikes)=%d" % ( len(spikes), len(extra_spikes)) else: spikes = numpy.resize(spikes, (i, )) if not array: spikes = SpikeTrain(spikes, t_start=t_start, t_stop=t_stop) if debug: return spikes, extra_spikes else: return spikes