So I'm having 2 issues.
First, the initial steadystate probabilities seem to be off. The neuron channel starts at a much higher percentage of open channels and starts to decline despite the voltage being held constant.
When I use a 2 state matlab model, and set the simulation to have the same starting probabilities, than I can reproduce the neuron trace, but if I calculate my own steady state activation (which seems to be the right one) it doesn't match neuron's.
The second issue is that when I increase to 3 or more channels even if I match the initial probabilities the traces end up diverging, however at the moment I just want to understand why the initial probabilities are wrong.
This is the full 2 state channel model I've been using
Code: Select all
TITLE channel model imported from QUB
NEURON {
SUFFIX QUB_K_CHANNEL2
USEION k READ ek WRITE ik
RANGE gbar, gk, ik, k0_C1_O1, k1_C1_O1, k0_O1_C1, k1_O1_C1
}
UNITS {
(mA) = (milliamp)
(mV) = (millivolt)
(pS) = (picosiemens)
(um) = (micron)
}
PARAMETER {
gbar = 0.001 (pS/um2)
k0_C1_O1 = 0.0006 (/ms)
k1_C1_O1 = 0.04 (/mV)
k0_O1_C1 = 0.0005 (/ms)
k1_O1_C1 = 0.08 (/mV)
}
STATE {
O1 C1 }
ASSIGNED {
v (mV)
ek (mV)
ik (mA/cm2)
gk (pS/um2)
C1O1 (/ms)
O1C1 (/ms)
}
INITIAL {
SOLVE states STEADYSTATE sparse
}
BREAKPOINT {
SOLVE states METHOD sparse
gk = gbar*O1
ik = (1e-4)*gk*(v - ek)
}
KINETIC states {
rates(v)
CONSERVE O1 + C1 = 1
~ C1 <-> O1 (C1O1, O1C1)
}
PROCEDURE rates(v(millivolt)) {
C1O1 = k0_C1_O1 * exp(k1_C1_O1*v)
O1C1 = k0_O1_C1 * exp(k1_O1_C1*v)
}
And the session file I've been using to create a patch clamp and some graphs to compare with matlab
Code: Select all
{load_file("nrngui.hoc")}
objectvar save_window_, rvp_
objectvar scene_vector_[6]
objectvar ocbox_, ocbox_list_, scene_, scene_list_
{ocbox_list_ = new List() scene_list_ = new List()}
{pwman_place(0,0,0)}
//Begin SingleCompartment
{
load_file("single.hoc")
}
ocbox_ = new SingleCompartment(0)
ocbox_.inserter = new Inserter(0)
{object_push(ocbox_.inserter)}
{
mt.select("QUB_K_CHANNEL2") i = mt.selected()
ms[i] = new MechanismStandard("QUB_K_CHANNEL2")
ms[i].set("gbar_QUB_K_CHANNEL2", 0.001, 0)
ms[i].set("k0_C1_O1_QUB_K_CHANNEL2", 0.0006, 0)
ms[i].set("k1_C1_O1_QUB_K_CHANNEL2", 0.04, 0)
ms[i].set("k0_O1_C1_QUB_K_CHANNEL2", 0.0005, 0)
ms[i].set("k1_O1_C1_QUB_K_CHANNEL2", 0.08, 0)
mstate[i]= 1
maction(i)
}
{object_pop() doNotify()}
{object_push(ocbox_)}
{inserter.v1.map()}
{endbox()}
{object_pop() doNotify()}
{
ocbox_ = ocbox_.vbox
ocbox_.map("SingleCompartment", 71, 124, 113.28, 115.2)
}
objref ocbox_
//End SingleCompartment
//Begin PointProcessManager
{
load_file("pointman.hoc")
}
{
soma ocbox_ = new PointProcessManager(0)
}
{object_push(ocbox_)}
{
mt.select("VClamp") i = mt.selected()
ms[i] = new MechanismStandard("VClamp")
ms[i].set("dur", 100, 0)
ms[i].set("dur", 400, 1)
ms[i].set("dur", 0, 2)
ms[i].set("amp", -20, 0)
ms[i].set("amp", 60, 1)
ms[i].set("amp", 0, 2)
ms[i].set("gain", 100000, 0)
ms[i].set("rstim", 1, 0)
ms[i].set("tau1", 0.001, 0)
ms[i].set("tau2", 0, 0)
ms[i].set("e0", -0.000599988, 0)
ms[i].set("vo0", 59.9988, 0)
ms[i].set("vi0", 59.9988, 0)
ms[i].set("fac", 0, 0)
mt.select("VClamp") i = mt.selected() maction(i)
hoc_ac_ = 0.5
sec.sec move() d1.flip_to(0)
}
{object_pop() doNotify()}
{
ocbox_ = ocbox_.v1
ocbox_.map("PointProcessManager", 75, 264, 208.32, 326.4)
}
objref ocbox_
//End PointProcessManager
{
xpanel("RunControl", 0)
v_init = -65
xvalue("Init","v_init", 1,"stdinit()", 1, 1 )
xbutton("Init & Run","run()")
xbutton("Stop","stoprun=1")
runStopAt = 5
xvalue("Continue til","runStopAt", 1,"{continuerun(runStopAt) stoprun=1}", 1, 1 )
runStopIn = 1
xvalue("Continue for","runStopIn", 1,"{continuerun(t + runStopIn) stoprun=1}", 1, 1 )
xbutton("Single Step","steprun()")
t = 500
xvalue("t","t", 2 )
tstop = 500
xvalue("Tstop","tstop", 1,"tstop_changed()", 0, 1 )
dt = 0.025
xvalue("dt","dt", 1,"setdt()", 0, 1 )
steps_per_ms = 40
xvalue("Points plotted/ms","steps_per_ms", 1,"setdt()", 0, 1 )
screen_update_invl = 0.05
xvalue("Scrn update invl","screen_update_invl", 1,"", 0, 1 )
realtime = 0.6
xvalue("Real Time","realtime", 0,"", 0, 1 )
xpanel(296,217)
}
{
save_window_ = new Graph(0)
save_window_.size(0,500,-70,60)
scene_vector_[3] = save_window_
{save_window_.view(0, -70, 500, 130, 576, 97, 300.48, 200.32)}
graphList[0].append(save_window_)
save_window_.save_name("graphList[0].")
save_window_.addexpr("v(.5)", 1, 1, 0.8, 0.9, 2)
}
{
save_window_ = new Graph(0)
save_window_.size(-10,500,0,1.3e-05)
scene_vector_[4] = save_window_
{save_window_.view(-10, 0, 510, 1.3e-05, 576, 358, 539.52, 201.28)}
graphList[1].append(save_window_)
save_window_.save_name("graphList[1].")
save_window_.addvar("soma.ik( 0.5 )", 1, 1, 0.8, 0.9, 2)
}
{
save_window_ = new Graph(0)
save_window_.size(0,500,0,1)
scene_vector_[5] = save_window_
{save_window_.view(0, 0, 500, 1, 897, 97, 300.48, 200.32)}
graphList[2].append(save_window_)
save_window_.save_name("graphList[2].")
save_window_.addvar("soma.O1_QUB_K_CHANNEL2( 0.5 )", 1, 1, 0.8, 0.9, 2)
}
objectvar scene_vector_[1]
{doNotify()}
And this is the matlab function that attempts to do the same experiment with the same model as neuron. Calling simplePatch_2state(true) uses the same starting probabilities that neuron uses, and should reproduce the same trace. Setting it to false and the script will use its own steadystate propabilities (which seem to be correct) and thus get a different trace than neuron.
Code: Select all
function simplePatch_2state(use_neuron_prob)
time_end = 500; % 500 ms
v_rev = -77;
V = zeros(time_end,1);
V(1:100) = -20;
V(101:time_end) = 60;
C = [.001, 0]; % conductance vector in pS/um2
K = zeros(2,2,2);
gbar = 0.001;
k0_c1_o1 = 0.0006;
k1_c1_o1 = 0.04;
k0_o1_c1 = 0.0005;
k1_o1_c1 = 0.08;
% put in matrix form so we can calculate the steady state
K(:,:,1) = [0, k0_c1_o1; k0_o1_c1, 0;]; % the k0
K(:,:,2) = [0, k1_c1_o1; k1_o1_c1, 0;]; % k1
Q = zeros(size(K,2),size(K,2));
p = zeros(size(K,2),time_end+1);
I = zeros(time_end);
% calculate the inital Q matrix
for x=1:size(K,2)
for y=1:size(K,2)
Q(x,y) = K(x,y,1) * exp(K(x,y,2)*V(1)); % q_ij = k0*exp(k1*v)
end
end
for x=1:size(K,2) % set the diagonals
Q(x,x) = 0;
Q(x,x) = - sum(Q(:,x));
end
% solve for steady state
p(:,1) = [Q; ones(1, length(Q))] \ [zeros(length(Q), 1); 1];
if (use_neuron_prob) % use the neuron starting probabilities instead
p(1,1) = 0.941693;
p(2,1) = 1 - 0.941693;
end
for t=1:time_end
% generate the new transition matrix
c1o1 = k0_c1_o1 * exp(k1_c1_o1*V(t));
o1c1 = k0_o1_c1 * exp(k1_o1_c1*V(t));
p(1,t+1) = p(1,t) - p(1,t) * o1c1 + p(2,t) * c1o1;
p(2,t+1) = p(2,t) + p(1,t) * o1c1 - p(2,t) * c1o1;
I(t) = 1e-4 * C * p(:,t+1) * (V(t)-v_rev); % current in mV/cm2
end
figure(1)
plot(V)
figure(2)
plot(I)
figure(3)
plot(p(1,:))
I'm sorry for the big code dump but it seemed to be the simplest way to make everything clear. I'd really appreciate if anyone could shed some light on what's going on as I don't understand where neuron is getting those steadystate probabilities from.
thanks,
Aaron