I'm trying to implement the spiking neuron of the Izhikevich model. The formula for this type of neuron is really simple:
v[n+1] = 0.04*v[n]^2 + 5*v[n] + 140 - u[n] + I
u[n+1] = a*(b*v[n] - u[n])
where v is the membrane potential and u is a recovery variable.
If v gets above 30, it is reset to c and u is reset to u + d.
Given such a simple equation I wouldn't expect any problems. But while the graph should look like , all I'm getting is this:
I'm completely at loss what I'm doing wrong exactly because there's so little to do wrong. I've looked for other implementations but the code I'm looking for is always hidden in a dll somewhere. However I'm pretty sure I'm doing exactly what the Matlab code of the author (2) is doing. Here is my full R code:
v = -70
u = 0
a = 0.02
b = 0.2
c = -65
d = 6
history <- c()
for (i in 1:100) {
if (v >= 30) {
v = c
u = u + d
}
v = 0.04*v^2 + 5*v + 140 - u + 0
u=a*(b*v-u);
history <- c(history, v)
}
plot(history, type = "l")
To anyone who's ever implemented an Izhikevich model, what am I missing?
usefull links:
(1) http://www.opensourcebrain.org/projects/izhikevichmodel/wiki
(2) http://www.izhikevich.org/publications/spikes.pdf
Answer
So it turns out I read the formula wrong. Apparently v' means new v = v + 0.04*v^2 + 5*v + 140 - u + I. My teachers would have written this as v' = 0.04*v^2 + 6*v + 140 - u + I. I'm very grateful for your help in pointing this out to me.
Take a look at the code that implements the Izhikevich model in R below. It results in the following R plots:
Regular Spiking Cell:
Chattering Cell:
And the R code:
# Simulation parameters
dt = 0.01 # ms
simtime = 500 # ms
t = 0
# Injection current
I = 15
delay = 100 # ms
# Model parameters (RS)
a = 0.02
b = 0.2
c = -65
d = 8
# Params for chattering cell (CH)
# c = -50
# d = 2
# Initial conditions
v = -80 # mv
u = 0
# Input current equation
current = function()
{
if(t >= delay)
{
return(I)
}
return (0)
}
# Model state equations
deltaV = function()
{
return (0.04*v*v+5*v+140-u+current())
}
deltaU = function()
{
return (a*(b*v-u))
}
updateState = function()
{
v <<- v + deltaV()*dt
u <<- u + deltaU()*dt
if(v >= 30)
{
v <<- c
u <<- u + d
}
}
# Simulation code
runsim = function()
{
steps = simtime / dt
resultT = rep(NA, steps)
resultV = rep(NA, steps)
for (i in seq(steps))
{
updateState()
t <<- dt*(i-1)
resultT[i] = t
resultV[i] = v
}
plot(resultT, resultV,
type="l", xlab = "Time (ms)", ylab = "Membrane Potential (mV)")
}
runsim()
Some notes:
I've picked the parameters for the "Regular Spiking (RS)" cell from Izhikevich's site. You can pick other parameters from the two upper-right plots on that page. Uncomment the CH parameters to get a plot for the "Chattering" type cell.
As commenters have suggested, the first two equations in the question are incorrectly implemented differential equations. The correct way to implement the first one would be something like: "v[n+1] = v[n] + (0.04*v[n]^2 + 5*v[n] + 140 - u[n] + I) * dt". See the code above for example. dt refers to the user specified time step integration variable and usually dt << 1 ms.
In the for loop in the question, the state variables u and v should be updated first, then the condition checked after.
As noted by others, a current source is needed for both of these cell types. I've used 15 (I believe these are pico amps) from this page on the author's site (bottom value for I in the screenshot). I've also implemented a delay for the current onset (100 ms parameter).
The simulation code should implement some kind of time tracking so it's easier to know when the spikes are occurring in resulting plot. The above code implements this, and runs the simulation for 500 ms.
Related
While using the real-time Fractal zoomer XaoS to explore the infinite universe having user formula "sin(z^2)-cos(z^2)+c", we start out here (important for universe identification and formula matching with other zoomer software applications, libraries or frameworks.):
I found the following fractal, which I really like:
As you, perhaps, can see, I have run up against the resolution wall (floor?), which means that the deeper I zoom at that point, the more pixelated and boxy the image gets:
Here is the XaoS source code (*.xpf file contents):
;Position file automatically generated by XaoS 4.2.1
; - a realtime interactive fractal zoomer
;Use xaos -loadpos <filename> to display it
(initstate)
(defaultpalette 0)
(formula 'user)
(usrform "sin(z^2)-cos(z^2)+c")
(angle 90)
(maxiter 1000)
(view -0.241140329885861603 1.09425325699643758E-015 8.78234117374088186E-014 8.78234139599431772E-014)
And Fractal->View... yields:
So I tried to enter the formula into UltraFractal, but no matter what I try, I can't get it to work.
This works:
init:
z = #start
loop:
z = sin(z^#power) + cos(z^#power) + #pixel
This does not work:
init:
z = #start
loop:
z = sin(z^#power) - cos(z^#power) + #pixel
The only difference in the above two is the minus sign.
This does not work:
init:
z = #start
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
z = ss - cc + #pixel
This works:
init:
z = #start
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
z = ss + cc + #pixel
but if I add a line negating cc, it doesn't work again:
init:
z = #start
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
cc = -cc
z = ss + cc + #pixel
Finally, one last example.
This works:
init:
z = #start
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
z = ss + 1 - ( 1 - cc ) + #pixel
but this doesn't:
init:
z = #start
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
z = ss + 1 - ( 1 + cc ) + #pixel
As I think I've proven, negation and subtraction seem to be working. And I keep changing only the minus sign or the subtraction to make it stop working, so I suspect that there is a bug (or an arbitrary limitation of not being able to use this particular formula? - doesn't make sense.)
In the "Fractal Mode" pane, lower right part of screen, I click the third item down, "Switch Mode", and it displays "Contains errors." This is the only helpful feedback I've been able to find.
This is a paid program, so I do not expect to be having this problem. Anyone? (secondary question - what zoomer will render this well? Thanks!)
Here is my current UltraFractal source code:
comment {
This file contains standard fractal types for Ultra Fractal. Many of the
fractal formulas here were written by other formula authors, as noted in the
comments with each formula. All formulas have been edited and simplified by
Frederik Slijkerman.
These formulas are also available as objects for the common.ulb framework in
Standard.ulb.
}
sin2_minus_cos2 {
;
; Generic Mandelbrot set.
;
init:
z = #start
z9 = 1
loop:
z2p = z^#power
ss = sin(z2p)
cc = cos(z2p)
cc = -cc
z = ss + cc + #pixel
bailout:
|z| <= #bailout
$IFDEF VER60
perturbinit:
#dz = 0
perturbloop:
if #power == (2, 0)
#dz = 2 * #z * #dz + sqr(#dz) + #dpixel
elseif #power == (3, 0)
complex z2 = sqr(#z)
complex dz2 = sqr(#dz)
#dz = 3 * z2 * #dz + 3 * #z * dz2 + #dz * dz2 + #dpixel
else ; power 4
complex z2 = sqr(#z)
complex dz2 = sqr(#dz)
complex zdz4 = 4*#z*#dz
#dz = #dpixel + zdz4*z2 + 6*z2*dz2 + zdz4*dz2 + sqr(dz2)
endif
$ENDIF
default:
title = "sin2_minus_cos2"
center = (-0.5, 0)
$IFDEF VER50
rating = recommended
$ENDIF
$IFDEF VER60
perturb = #power == (2, 0) || #power == (3, 0) || #power == (4, 0)
$ENDIF
param start
caption = "Starting point"
default = (0,0)
hint = "The starting point parameter can be used to distort the Mandelbrot \
set. Use (0, 0) for the standard Mandelbrot set."
endparam
param power
caption = "Power"
default = (2,0)
hint = "This parameter sets the exponent for the Mandelbrot formula. \
Increasing the real part to 3, 4, and so on, will add discs to \
the Mandelbrot figure. Non-integer real values and non-zero \
imaginary values will create distorted Mandelbrot sets. Use (2, 0) \
for the standard Mandelbrot set."
endparam
float param bailout
caption = "Bailout value"
default = 4.0
min = 1.0
$IFDEF VER40
exponential = true
$ENDIF
hint = "This parameter defines how soon an orbit bails out while \
iterating. Larger values give smoother outlines; values around 4 \
give more interesting shapes around the set. Values less than 4 \
will distort the fractal."
endparam
switch:
type = "Julia"
seed = #pixel
power = power
bailout = bailout
}
I just punched the formula into a zoomer on my Android, and it seems to work.
Here is that coordinate, zoomed out just a little, so that you can barely see the pixelated fractal (just another example of great beauty from this wonderful infinite universe!):
EDIT:
This formula works:
init:
z = #start
loop:
; in XaoS, user formula sin(z)^2-cos(z)^2+c
z = sin(z)^2 - cos(z)^2 + #pixel
And here's the result in UltraFractal:
I'm trying to translate a C routine from an old sound synthesis program into R, but have indexing issues which I'm struggling to understand (I'm a beginner when it comes to using loops).
The routine creates an exponential lookup table - the vector exptab:
# Define parameters
sinetabsize <- 8192
prop <- 0.8
BP <- 10
BD <- -5
BA <- -1
# Create output vector
exptab <- vector("double", sinetabsize)
# Loop
while(abs(BD) > 0.00001){
BY = (exp(BP) -1) / (exp(BP*prop)-1)
if (BY > 2){
BS = -1
}
else{
BS = 1
}
if (BA != BS){
BD = BD * -0.5
BA = BS
BP = BP + BD
}
if (BP <= 0){
BP = 0.001
}
BQ = 1 / (exp(BP) - 1)
incr = 1 / sinetabsize
x = 0
stabsize = sinetabsize + 1
for (i in (1:(stabsize-1))){
x = x + incr
exptab [[sinetabsize-i]] = 1 - (BQ * (exp(BP * x) - 1))
}
}
Running the code gives the error:
Error in exptab[[sinetabsize - i]] <- 1 - (BQ * (exp(BP * x) - 1)) :
attempt to select less than one element in integerOneIndex
Which, I understand from looking at other posts, indicates an indexing problem. But, I'm finding it difficult to work out the exact issue.
I suspect the error may lie in my translation. The original C code for the last few lines is:
for (i=1; i < stabsize;i++){
x += incr;
exptab[sinetabsize-i] = 1.0 - (float) (BQ*(exp(BP*x) - 1.0));
}
I had thought the R code for (i in (1:(stabsize-1))) was equivalent to the C code for (i=1; i< stabsize;i++) (i.e. the initial value of i is i = 1, the test is whether i < stabsize, and the increment is +1). But now I'm not so sure.
Any suggestions as to where I'm going wrong would be greatly appreciated!
As you say, array indexing in R starts at 1. In C it starts at zero. I reckon that's your problem. Can sinetabsize-i ever get to zero?
I am struggling to figure out how to create a for loop in which some initial objects (u, l, h, and y) and their values are updated and reported at the end of each iteration of the loop. And that the loop takes into account the values of the prior iteration as the basis (for example after updating the above objects, the runif function takes the updated values of u and l in drawing a q. I keep getting the same result repeated with no variation, and I am unsure as to what might be the best way to resolve this.
Apologies in advance as I am fairly new to R and coding in general.
reset = {
l = 0.1 #lower bound of belief in theta
u = 0.9 #upper bound of belief in theta
h = 0.2 #lower legal threshold, below which an action is not liable
y = 0.8 #upper legal threshold, above which an action is liable
}
### need 1-u <= h <= y <= 1-l for each t along every path of play
period = c(1:100) ## Number of periods in the iteration of the loop.
for (t in 1:length(period)) {
q = runif(1,min = l, max = u) ### 1 draw of q from a uniform distribution
q
probg = function(q,l,u){(u - (1-q))/(u-l)} ### probability of being found guilty given q in the ambiguous region
probg(q,l,u)
probi = function(q,l,u){1-probg(q,l,u)} ### probability of being found innocent given q in the ambiguous region
probi(q,l,u)
ruling = if(q>=y | probg(q,l,u) > 1){print("Guilty") ###Strict liability
} else if(q<=h | probi(q,l,u) > 1) {print("Innocent") ###Permissible
} else if(q>h & q<y) { ###Ambiguous region
discovery = sample(c('guilty','not guilty'), size=1, replace=TRUE, prob=c(probg(q,l,u),probi(q,l,u))) ### court discovering whether a particular ambiguous q is permissible or not
}
discovery
ruling
if(ruling == "not guilty") {u = 1-q} else if (ruling == "guilty") {l = 1-q} else (print("beliefs unchanged"))
if(ruling == "not guilty"){h = 1 - u} else if (ruling == "guilty") {y = 1 - l} else (print("legal threshold unchanged")) #### legal adjustment and updating of beliefs in ambiguous region after discovery of liability
probg(q,l,u)
probi(q,l,u)
modelparam = c(l,u,h,y)
show(modelparam)
}
I my main objectif is to obtain the same results on SAS and on R. Somethimes and depending on the case, it is very easy. Otherwise it is difficult, specially when we want to compute something more complicated than the usual.
So, in ored to understand my case, I have the following differential equation system :
y' = z
z' = b* y'+c*y
Let :
b = - 2 , c = - 4, y(0) = 0 and z(0) = 1
In order to resolve this system, in SAS we use the command PROC MODEL :
data t;
do time=0 to 40;
output;
end;
run;
proc model data=t ;
dependent y 0 z 1;
parm b -2 c -4;
dert.y = z;
dert.z = b * dert.y + c * y;
solve y z / dynamic solveprint out=out1;
run;
In R, we could write the following solution using the lsoda function of the deSolve package:
library(deSolve)
b <- -2;
c <- -4;
rigidode <- function(t, y, parms) {
with(as.list(y), {
dert.y <- z
dert.z <- b * dert.y + c * y
list(c(dert.y, dert.z))
})
}
yini <- c(y = 0, z = 1)
times <- seq(from=0,to=40,by=1)
out_ode <- ode (times = times, y = yini, func = rigidode, parms = NULL)
out_lsoda <- lsoda (times = times, y = yini, func = rigidode, parms = NULL)
Here are the results :
SAS
R
For time t=0,..,10 , we obtain similar results. But for t=10,...,40, we start to have differences. For me, these differences are important.
In order to correct these differences, I fixed on R the error truncation term on 1E-9 in stead of 1E-6. I also verified if the numerical integration methods and the hypothesis used by default are the same.
Do you have any idea how to deal with this problem?
Sincerely yours,
Mily
I've just been working though converting some MATLAB scripts to work in R, however having never used MATLAB in my life, and not exactly being an expert on R I'm having some trouble.
Edit: It's a script I was given designed to correct temperature measurements for lag generated by insulation mass effects. My understanding is that It looks at the rate of change of the temperature and attempts to adjust for errors generated by the response time of the sensor. Unfortunately there is no literature available to me to give me an indication of the numbers i am expecting from the function, and the only way to find out will be to experimentally test it at a later date.
the original script:
function [Tc, dT] = CTD_TempTimelagCorrection(T0,Tau,t)
N1 = Tau/t;
Tc = T0;
N = 3;
for j=ceil(N/2):numel(T0)-ceil(N/2)
A = nan(N,1);
# Compute weights
for k=1:N
A(k) = (1/N) + N1 * ((12*k - (6*(N+1))) / (N*(N^2 - 1)));
end
A = A./sum(A);
# Verify unity
if sum(A) ~= 1
disp('Error: Sum of weights is not unity');
end
Comp = nan(N,1);
# Compute components
for k=1:N
Comp(k) = A(k)*T0(j - (ceil(N/2)) + k);
end
Tc(j) = sum(Comp);
dT = Tc - T0;
end
where I've managed to get to:
CTD_TempTimelagCorrection <- function(temp,Tau,t){
## Define which equation to use based on duration of lag and frequency
## With ESM2 profiler sampling # 2hz: N1>tau/t = TRUE
N1 = Tau/t
Tc = temp
N = 3
for(i in ceiling(N/2):length(temp)-ceiling(N/2)){
A = matrix(nrow=N,ncol=1)
# Compute weights
for(k in 1:N){
A[k] = (1/N) + N1 * ((12*k - (6*(N+1))) / (N*(N^2 - 1)))
}
A = A/sum(A)
# Verify unity
if(sum(A) != 1){
print("Error: Sum of weights is not unity")
}
Comp = matrix(nrow=N,ncol=1)
# Compute components
for(k in 1:N){
Comp[k] = A[k]*temp[i - (ceiling(N/2)) + k]
}
Tc[i] = sum(Comp)
dT = Tc - temp
}
return(dT)
}
I think the problem is the Comp[k] line, could someone point out what I've done wrong? I'm not sure I can select the elements of the array in such a way.
by the way, Tau = 1, t = 0.5 and temp (or T0) will be a vector.
Thanks
edit: apparently my description is too brief in explaining my code samples, not really sure what more I could write that would be relevant and not just wasting peoples time. Is this enough Mr Filter?
The error is as follows:
Error in Comp[k] = A[k] * temp[i - (ceiling(N/2)) + k] :
replacement has length zero
In addition: Warning message:
In Comp[k] = A[k] * temp[i - (ceiling(N/2)) + k] :
number of items to replace is not a multiple of replacement length
If you write print(i - (ceiling(N/2)) + k) before that line, you will see that you are using incorrect indices for temp[i - (ceiling(N/2)) + k], which means that nothing is returned to be inserted into Comp[k]. I assume this problem is due to Matlab allowing the use of 0 as an index and not R, and the way negative indices are handled (they don't work the same in both languages). You need to implement a fix to return the correct indices.