:opt no-lint
import qualified Data.ByteString as B
import Text.Printf
:l GPlot2DH
import GPlot2DH
Constants
tau = 6e-2 -- time constant
uRest = -70e-3 -- base voltage
r = 1e3 -- leak resistor ???
dt = 0.001 -- delta t
vTh = -54e-3 -- Firing threshold
spikeV = 10e-3 -- Firing amplitude
uReset = -80e-3 -- Firing reset voltage (sets refractory period)
Main Code
{-
solveDE parameters,
current time - advances recursively
stop time - time to stop sim
current - zero for one shot, non-zero creates pulses
voltage - present voltage
spikeTable - advances recursively
-}
solveDE :: Float -> Float -> Float -> Float -> [Float] -> [(Float, Float)]
solveDE curTime endTime i u sts
| (curTime >= endTime) = []
| (u >= vTh) = (curTime+dt,uReset) : solveDE (curTime+dt) endTime i uReset sts
| (otherwise) =
let
(u',sts') = if not (null sts) -- check for empty spike table
then
if curTime > head sts -- are we going to spike?
then
(u + spikeV, tail sts) -- advance spike table
else
(u, sts) -- spike not used
else
(u, sts) -- spike not used
-- Do the math and recurse
du = ((1.0/tau) * ((-1) * (u' - uRest)) + (i * r))*dt
newU = u' + du
newT = curTime + dt
in (newT,newU) : solveDE newT endTime i newU sts'
-- Show the output
showResults :: [Float] -> [Float] -> IO ()
showResults ts vs = do
putStrLn "Action potential simulation using the LIF model with Inputs:"
putStrLn "\n Time(ms) Membrane Potential (mV)"
mapM_ (\(t, v) -> (printf "%10.2f %10.2f\n" (t*1000) (v*1000))) $ zip ts vs
graphResults :: [Float] -> [Float] -> Float -> IO (B.ByteString)
graphResults ts vs thresh = do
writeFile "lifwi_solution01.dat"
(concatMap (\(a,b) -> show (a*1000) ++ " " ++ show (b*1000) ++ "\n") $ zip ts vs)
runGNUPlot "lifwi_solution01.dat"
"Leaky Integrate and Fire Neuronal Model with Inputs"
"Time (ms)" "Activation Voltage (mV)"
"lifwi_solution01.png" (thresh * 1000)
Simple Spiking
$I(t) = 0$
Note that the reset value after a spike is lower than the resting value. With no spike inputs the voltage recovers exponentially to the resting value.
spikeTable = [0.02, 0.055, 0.07]
results = solveDE 0 0.2 0.0 (-70e-3) spikeTable
(ts,vs) = unzip results
graphResults ts vs vTh
Generate a Frequency
This gets interesting!
Nature created an Ion channel opening to a frequency .. pretty cool.
Setting the current to non-zero creates a spike train proportional to the current. The example below sets,
$I(t) = 1\ ma$
spikeTable = []
results = solveDE 0 0.2 1e-3 (-70e-3) spikeTable
(ts,vs) = unzip results
graphResults ts vs vTh
Current and Spikes
Don't know if nature does this .. It gets a bit complicated.
spikeTable = [0.02, 0.055, 0.07]
results = solveDE 0 0.2 9e-4 (-70e-3) spikeTable
(ts,vs) = unzip results
graphResults ts vs vTh