For a project I need to create LIF ensembles with various spiking threshold. As far as I know, it is not possible to choose this parameter in Nengo. Therefore, I changed the source code to provide the possibility of manually setting the threshold when creating a LIF:
`class LIF(LIFRate): """Spiking version of the leaky integrate-and-fire (LIF) neuron model. Parameters ---------- tau_rc : float Membrane RC time constant, in seconds. Affects how quickly the membrane voltage decays to zero in the absence of input (larger = slower decay). tau_ref : float Absolute refractory period, in seconds. This is how long the membrane voltage is held at zero after a spike. min_voltage : float Minimum value for the membrane voltage. If ``-np.inf``, the voltage is never clipped. amplitude : float Scaling factor on the neuron output. Corresponds to the relative amplitude of the output spikes of the neuron. """ probeable = ('spikes', 'voltage', 'refractory_time') min_voltage = NumberParam('min_voltage', high=0) def __init__(self, tau_rc=0.02, tau_ref=0.002, min_voltage=0, amplitude=1, spiking_threshold=1): super(LIF, self).__init__( tau_rc=tau_rc, tau_ref=tau_ref, amplitude=amplitude) self.min_voltage = min_voltage self.spiking_threshold=spiking_threshold def step_math(self, dt, J, spiked, voltage, refractory_time): # reduce all refractory times by dt refractory_time -= dt # compute effective dt for each neuron, based on remaining time. # note that refractory times that have completed midway into this # timestep will be given a partial timestep, and moreover these will # be subtracted to zero at the next timestep (or reset by a spike) delta_t = (dt - refractory_time).clip(0, dt) # update voltage using discretized lowpass filter # since v(t) = v(0) + (J - v(0))*(1 - exp(-t/tau)) assuming # J is constant over the interval [t, t + dt) voltage -= (J - voltage) * np.expm1(-delta_t / self.tau_rc) # determine which neurons spiked (set them to 1/dt, else 0) spiked_mask = voltage > self.spiking_threshold spiked[:] = spiked_mask * (self.amplitude / dt) # set v(0) = 1 and solve for t to compute the spike time t_spike = dt + self.tau_rc * np.log1p( -(voltage[spiked_mask] - self.spiking_threshold) / (J[spiked_mask] - self.spiking_threshold)) # set spiked voltages to zero, refractory times to tau_ref, and # rectify negative voltages to a floor of min_voltage voltage[voltage < self.min_voltage] = self.min_voltage voltage[spiked_mask] = 0 refractory_time[spiked_mask] = self.tau_ref + t_spike`
I basically replaced every 1 by self.spiking_threshold in step_math, although I’m not sure about what exactly is computed.
Although it successfully sets the threshold, this solution seems to affect the way the ensemble represents values. With the simple code below, the decoded value is inversely scaled by the given spiking_threshold:
`with model: stim = nengo.Node() a = nengo.Ensemble(n_neurons=50, dimensions=1, neuron_type=nengo.neurons.LIF(spiking_threshold=2.)) nengo.Connection(stim, a)`
Is there a clean way to choose the spiking threshold? Can you give me some hints to implement it otherwise?