Public
Edited
Jul 2, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class FirstOrderLI {
constructor(tau_rc=0.2, v_init=0) {
this.tau_rc = tau_rc;
this.v = v_init;
}

step(I, t_step) {
this.v = this.v * (1 - t_step/this.tau_rc) + (I * t_step / this.tau_rc);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Note that v_init, tau_rc, and time_step are all declared outside of this cell
{
const NUM_STEPS = 2 / time_step; // Simulate for 2 seconds

// Create a neuron with initial voltage of v_init
const neuron = new FirstOrderLI(tau_rc, v_init);

// An array to track the times and potentials
const v_history = [ ];

// Loop through NUM_STEPS times
for(let i = 0; i < NUM_STEPS; i++) {
neuron.step(0, time_step); // First argument is 0 to specify I[t] = 0
v_history.push({ t: i*time_step, v: neuron.v }); // Append to the historical data
}

// Show line graph with
return Plot.line(v_history, {x: "t", y: "v"}).plot();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const TIME_STEP = 1e-3; // 0.001
const NUM_STEPS = 4 / TIME_STEP; // Simulate for 4 seconds

const I = step_func(1.1); // A function that is "on" for 8 seconds

const neuron = new FirstOrderLI(tau_rc1);

// An array to track the times, potentials, and inputs
const v_history = [ ];
for(let i = 0; i < NUM_STEPS; i++) {
const t = i*TIME_STEP;
const I_t = I(t);
neuron.step(I_t, TIME_STEP);
v_history.push({t, v: neuron.v, I: I_t });
}
return Plot.plot({
y: {
label: 'I'
},
marks: [
Plot.line(v_history, {x: "t", y: "I", stroke: "blue"}),
Plot.line(v_history, {x: "t", y: "v", stroke: "#AAA"})
],
});
}
Insert cell
Insert cell
Insert cell
class FirstOrderLIF {
constructor(tau_rc=0.2, v_init=0, tau_ref=0.002, v_th=1){
this.tau_rc = tau_rc;
this.tau_ref = tau_ref;
this.v = v_init;
this.v_th = v_th;
this.output = 0;
this.refractory_time = 0;
}

step(I, t_step) {
this.refractory_time -= t_step; // Subtract the amount of time thhat passed from our refractory time
if(this.refractory_time < 0) { // If we aren't in our refractory period, update the voltage
this.v = this.v * (1 - t_step/this.tau_rc) + (I * t_step / this.tau_rc);
}

if(this.v >= this.v_th) { // Fired
this.refractory_time = this.tau_ref; // Set refractory time

this.output = 1 / t_step; // Fire
this.v = 0; // Reset potential
} else {
this.output = 0; // Don't fire
}
return this.output;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const TIME_STEP = 1e-3; // 0.001
const NUM_STEPS = 15 / TIME_STEP; // Simulate for 15 seconds

const I = mul(step_func(4, 5), 1.2); // A function that is "on" for 8 seconds

const neuron = new FirstOrderLIF(tau_rc2, 0, tau_ref, v_th);

// An array to track the times, potentials, and inputs
const v_history = [ ];
for(let i = 0; i < NUM_STEPS; i++) {
const t = i*TIME_STEP;
const I_t = I(t);
neuron.step(I_t, TIME_STEP);
v_history.push({t, v: neuron.v, I: I_t, output: neuron.output*TIME_STEP*0.1, v_th: neuron.v_th });
}
return Plot.plot({
y: {
label: 'I'
},
marks: [
Plot.line(v_history, {x: "t", y: "v_th", stroke: "#AAA", strokeDasharray: "5 5", strokeWidth: 0.5 }),
Plot.line(v_history, {x: "t", y: "output", stroke: "red", strokeWidth: 7}),
Plot.line(v_history, {x: "t", y: "I", stroke: "blue"}),
Plot.line(v_history, {x: "t", y: "v", stroke: "#AAA"}),
],
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class FirstOrderLIF1 {
constructor(tau_rc=0.2, v_init=0, tau_ref=0.002, v_th=1){
this.tau_rc = tau_rc;
this.tau_ref = tau_ref;
this.v = v_init;
this.v_th = v_th;
this.output = 0;
this.refractory_time = 0;
}

step(I, t_step) {
this.refractory_time -= t_step; // Subtract the amount of time thhat passed from our refractory time
const old_v = this.v;
if(this.refractory_time < 0) { // If we aren't in our refractory period, update the voltage
this.v = this.v * (1 - t_step/this.tau_rc) + (I * t_step / this.tau_rc);
}

if(this.v >= this.v_th) { // Fired
// vvv CHANGED vvv
const spike_time = (this.tau_rc * (this.v_th - this.v) + t_step * (I - this.v_th)) / (I - this.v); // When did the neuron actually spike
this.refractory_time = this.tau_ref + spike_time;
// ^^^ CHANGED ^^^
this.output = 1 / t_step; // Fire
this.v = 0; // Reset potential
} else {
this.output = 0; // Don't fire
}
return this.output;
}
}
Insert cell
Insert cell
class FirstOrderLIF2 {
constructor(tau_rc=0.2, v_init=0, tau_ref=0.002, v_th=1){
this.tau_rc = tau_rc;
this.tau_ref = tau_ref;
this.v = v_init;
this.v_th = v_th;
this.output = 0;
this.refractory_time = 0;
}

step(I, t_step) {
this.refractory_time -= t_step;
// vvvvvvv CHANGED vvvvvvv
let delta_t = t_step - this.refractory_time; // How much time passed where we can actually accept input?
if (delta_t < 0 ) { delta_t = 0; } // Make sure it's not negative
if (delta_t > t_step) { delta_t = t_step; } // Make sure it's not greater than our time step
// ^^^^^^^ CHANGED ^^^^^^^
this.v = this.v * (1 - delta_t/this.tau_rc) + (I * delta_t / this.tau_rc); // CHANGED: Note that we use delta_t rather than t_step

if(this.v >= this.v_th) { // Fired
const spike_time = (this.tau_rc * (this.v_th - this.v) + t_step * (I - this.v_th)) / (I - this.v); // When did the neuron actually spike
this.refractory_time = this.tau_ref + spike_time;
this.output = 1 / t_step; // Fire
this.v = 0; // Reset potential
} else {
this.output = 0; // Don't fire
}
return this.output;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class AnalyticalLIF {
constructor(tau_rc=0.2, v_init=0, tau_ref=0.002, v_th=1){
this.tau_rc = tau_rc;
this.tau_ref = tau_ref;
this.v = v_init;
this.v_th = v_th;
this.output = 0;
this.refractory_time = 0;
}

step(I, t_step) {
this.refractory_time -= t_step;
let delta_t = t_step - this.refractory_time; // How much time passed where we can actually accept input?
if (delta_t < 0 ) { delta_t = 0; } // Make sure it's not negative
if (delta_t > t_step) { delta_t = t_step; } // Make sure it's not greater than our time step
// vvvvvvv CHANGED vvvvvvv
this.v = I + (this.v - I) * Math.exp(-delta_t/this.tau_rc);
// ^^^^^^^ CHANGED ^^^^^^^
if(this.v >= this.v_th) { // Fired
// vvvvvvv CHANGED vvvvvvv
const spike_time = delta_t + this.tau_rc * Math.log((this.v-I)/(this.v_th-I));
// ^^^^^^^ CHANGED ^^^^^^^

this.refractory_time = this.tau_ref + spike_time;

this.output = 1 / t_step; // Fire
this.v = 0; // Reset potential
} else {
this.output = 0; // Don't fire
}
return this.output;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more