2022-09-01 • 1144 weights

Imports

#
using Revise
using MyToolbox
using VoltoMapSim

Params

d = 1
p = get_params(
    duration = 10minutes,
    p_conn = 0.04,
    g_EE = 1 / d,
    g_EI = 1 / d,
    g_IE = 4 / d,
    g_II = 4 / d,
    ext_current = Normal(-0.5 * pA/√seconds, 5 * pA/√seconds),
    E_inh = -80 * mV,
    record_v = [1:40; 801:810],
);

Run sim

s = cached(sim, [p.sim]);
s = augment_simdata(s, p);

Plot firing rates

using PyPlot
using VoltoMapSim.Plot
histplot_fr(s.spike_rates);
../_images/2022-09-01__1144_weights_14_0.png
rasterplot(s.spike_times, tlim=[0,1]);
../_images/2022-09-01__1144_weights_15_0.png

Connection tests

(Using the new connection test and performance evaluation where we also predict exc or inh). – though results for unconnected are unchanged, so we can still compare with previous mass-eval (2022-07-23__Record_many).

using Base.Threads
detrates = Dict()
neurons = p.sim.network.record_v
pbar = Progress(length(neurons))
@threads for m in neurons
    perf = cached_conntest_eval(s, m, p, verbose = false)
    detrates[m] = perf.detection_rates
    next!(pbar)
end
Progress:  58%|████████████████████████                 |  ETA: 0:00:00
Progress: 100%|█████████████████████████████████████████| Time: 0:00:00

Plot perf

exc_post = [1:40;]
inh_post = [801:810;];
function detplot(ids, groupname)
    N = length(ids)
    ax = ydistplot(
        "Exc. inputs" => [detrates[n].TPR_exc for n in ids],
        "Inh. inputs" => [detrates[n].TPR_inh for n in ids],
        "Unconn." => [detrates[n].FPR for n in ids],
        ylim = [0,1],
        hylabel = "Detection rates for $(groupname) neurons (n = $N)",
        ref = p.evaluation.α,
    )
    return nothing
end;
detplot(exc_post, "excitatory")
../_images/2022-09-01__1144_weights_23_0.png
detplot(inh_post, "inhibitory")
../_images/2022-09-01__1144_weights_24_0.png

Interesting!

  1. Higher-than-α FPR exists here too

  2. E→E is detected here!

(compare with 2022-07-23 Record many neurons, where E→E is not detected at all).

In 2022-05-13 Network, we had (only for 1 neuron instead of 40) low E→E detectability, no I→E detectability, and lower than α FPR. But that net had the mistaken ‘1414’ connection strength params (inh inputs 4x as strong, instead of outputs).

Inspect performance

m = 1
perf = cached_conntest_eval(s,m,p)
ENV["LINES"] = 100  # display all rows of table
perf.tested_neurons

76 rows × 5 columns

input_neuron_IDreal_typepredicted_typepvalarea_over_start
Int64SymbolSymbolFloat64Float64
1139excexc0.0117
2681excinh0.01-4
311excexc0.0118
4766excexc0.0152
5132excexc0.0318.5
6516excexc0.0130.4
7418excinh0.01-3.7
8565excunconn0.0518.7
9597excexc0.0126.3
10446excexc0.0119.4
11447excexc0.0140.3
12710excexc0.0128.6
1366excexc0.018.29
14136excunconn0.095.45
15312excexc0.0182.6
16145excinh0.01-27.8
17169excexc0.0150.6
18194excunconn0.35-1.99
19629excexc0.014.7
20352excunconn0.82-8.92
21800excunconn0.72-4.17
22303excexc0.012.51
23101excunconn0.2921.1
2470excexc0.0116.9
25337excexc0.0112
2633excunconn0.1810.6
27988inhinh0.01-8.34
28894inhinh0.01-52.9
29831inhexc0.032.46
30902inhinh0.01-59.7
31897inhinh0.01-59.3
32928inhinh0.01-62.6
33914inhinh0.01-27
34829inhinh0.01-17.2
35908inhinh0.01-89.6
36922inhinh0.01-45.9
3723unconnunconn0.4231.2
3825unconnunconn0.6-13.3
3986unconnunconn0.33-11.2
40113unconnunconn0.64-11
41197unconnunconn0.651.15
42227unconnunconn0.959.94
43230unconnunconn0.397.05
44262unconnunconn0.079.06
45269unconnunconn0.456.56
46323unconnunconn0.43.37
47332unconnunconn0.880.694
48367unconnexc0.022.77
49394unconnunconn1-6.72
50410unconnunconn0.73.76
51424unconnunconn0.2221.4
52439unconnunconn0.08-57.6
53460unconnunconn0.0821.5
54487unconnunconn0.32-7.35
55499unconnexc0.012.17
56521unconnunconn0.375.41
57537unconnunconn0.22-2.49
58547unconninh0.04-18.2
59599unconnunconn0.15-10.6
60612unconninh0.01-34.3
61646unconnunconn0.39-1.08
62669unconnunconn0.27-20
63702unconnunconn0.49-21
64722unconnunconn0.52-5.28
65768unconnunconn0.3322.8
66790unconnunconn0.58-0.542
67813unconnunconn0.46-23.2
68821unconnunconn0.5-3.52
69842unconnunconn0.086.56
70843unconnunconn0.2710.1
71875unconnunconn0.49-47.3
72882unconnunconn0.16-5.13
73896unconnunconn0.86-20.6
74921unconnunconn0.88-3.81
75956unconnunconn0.7-10.5
76977unconnexc0.0421.7

Inhibitory input misclassified

one inh misclassified:

Plot.plotSTA(from::Int, to::Int, s, p, kw...) = plotSTA(s.signals[to].v, s.spike_times[from], p, kw...)
plotSTA(831, 1, s, p);
../_images/2022-09-01__1144_weights_31_0.png

Not so clear. A clearer one:

plotSTA(894, 1, s,p);
../_images/2022-09-01__1144_weights_33_0.png

But yeah, it would be fixed with a shorter STA window.

Exc input misclassified

plotSTA(145, 1, s,p);
../_images/2022-09-01__1144_weights_36_0.png
plotSTA(681, 1, s,p);
../_images/2022-09-01__1144_weights_37_0.png

And again, shorter window would mitigate.

Average STA window

For every recorded (exc) neuron..
    for all it's (exc) inputs..
        calc STA, and grand average all those
calcSTA(from::Int, to::Int, s, p) = calc_STA(s.signals[to].v, s.spike_times[from], p);
function calcMeanSTA(post; pre)
    avgSTA = nothing
    N = 0
    @showprogress for n in post
        ii = s.input_info[n]
        if pre == :exc
            inputs = ii.exc_inputs
        elseif pre == :inh
            inputs = ii.inh_inputs
        elseif pre == :FP
            perf = cached_conntest_eval(s,n,p)
            tn = perf.tested_neurons
            is_FP = (tn.real_type .== :unconn) .& (tn.predicted_type .!= :unconn)
            inputs = tn.input_neuron_ID[is_FP]
        end
        for m in inputs
            STA = calcSTA(m, n, s, p)
            if isnothing(avgSTA) avgSTA = STA
            else avgSTA .+= STA end
            N += 1
        end
    end
    return avgSTA ./ N
end;
avgSTA_EE = calcMeanSTA(exc_post, pre=:exc)
avgSTA_EI = calcMeanSTA(inh_post, pre=:exc)
avgSTA_IE = calcMeanSTA(exc_post, pre=:inh)
avgSTA_II = calcMeanSTA(inh_post, pre=:inh);
Progress: 100%|█████████████████████████████████████████| Time: 0:00:05
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01
Progress: 100%|█████████████████████████████████████████| Time: 0:00:00
avgSTA_FP_E = calcMeanSTA(exc_post, pre=:FP)
avgSTA_FP_I = calcMeanSTA(inh_post, pre=:FP);
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01
Progress: 100%|█████████████████████████████████████████| Time: 0:00:00
function Plot.plotsig(x, p::ExpParams; tscale = ms, kw...)
    duration = length(x) * p.sim.general.Δt
    t = linspace(zero(duration), duration, length(x)) / tscale
    xlabel = (tscale == ms) ? "Time (ms)" : 
             (tscale == seconds) ? "Time (s)" :
             (tscale == minutes) ? "Time (minutes)" : ""
    plotsig(t, x; xlabel, kw...)
end;
plotsig(avgSTA_EE / mV, p, hylabel="Average E→E STA (mV)", ylim=[-49.4, -48]); plt.subplots();
plotsig(avgSTA_EI / mV, p, hylabel="Average E→I STA (mV)", ylim=[-49.4, -48]); plt.subplots();
plotsig(avgSTA_IE / mV, p, hylabel="Average I→E STA (mV)", ylim=[-51, -48.5]); plt.subplots();
plotsig(avgSTA_II / mV, p, hylabel="Average I→I STA (mV)", ylim=[-51, -48.5]); plt.subplots();
plotsig(avgSTA_FP_E / mV, p, hylabel="Average FP→E STA (mV)"); plt.subplots();
plotsig(avgSTA_FP_I / mV, p, hylabel="Average FP→I STA (mV)");
../_images/2022-09-01__1144_weights_46_0.png ../_images/2022-09-01__1144_weights_46_1.png ../_images/2022-09-01__1144_weights_46_2.png ../_images/2022-09-01__1144_weights_46_3.png ../_images/2022-09-01__1144_weights_46_4.png ../_images/2022-09-01__1144_weights_46_5.png

Inhibitory neurons seem to have a lower average voltage, from looking at their STA baselines.

avg_voltage(group) = mean([mean(s.signals[n].v) for n in group])

avg_voltage(exc_post) / mV
-49
avg_voltage(inh_post) / mV
-49.2

Yup, that tracks.

For the average false positive STAs, we indeed see the 2 x (propagation + integration delay) (± 40 ms) dip seen before.

Disynaptic false positive (FP) hypothesis

We suspect false positive detections are due to an intermediary connected neuron.

A → B → C

A fires, makes B fire¹, which generates a PSP in the recorded neuron C.

But this PSP happens with a larger delay after the A spike than if A would be directly connected to C.

So let’s test if the peak of the STA of unconnected-but-detected (i.e. FP) neurons occurs later than the peak of non-detected unconnected neurons (the timing of which should be random).

¹(sometimes at least)

tn = perf.tested_neurons;
# We'll add columns: for every neuron (tp exc, tp inh, fp, tn),
# we'll calc when the peak occurs (max or min, depending on area-over-start) and add that.
m = 1;
peak_over_start = Float64[]
peakpos_ms = Float64[]
for row in eachrow(tn)
    STA = calcSTA(row.input_neuron_ID, m, s,p)
    f = (row.area_over_start > 0) ? findmax : findmin
    peak, peakpos = f(STA)
    push!(peak_over_start, (peak - STA[1]) / mV)
    push!(peakpos_ms, peakpos * p.sim.general.Δt / ms)
end
tn.peak_over_start = peak_over_start
tn.peakpos_ms = peakpos_ms;
ENV["COLUMNS"] = 100;  # show all columns of df
ydistplot(
    jn("Exc inputs,", "detected")          => tn.peakpos_ms[(tn.real_type .== :exc) .& (tn.predicted_type .== :exc)],
    jn("Inh inputs,", "detected")          => tn.peakpos_ms[(tn.real_type .== :inh) .& (tn.predicted_type .== :inh)],
    jn("Unconnected,", "not detected")     => tn.peakpos_ms[(tn.real_type .== :unconn) .& (tn.predicted_type .== :unconn)],
    jn("Unconnected", "but detected (FP)") => tn.peakpos_ms[(tn.real_type .== :unconn) .& (tn.predicted_type .!= :unconn)],
    figsize = (5, 2.4),
    hylabel = "Position of STA peak", 
    ylabel = "ms after presynaptic spike",
);
../_images/2022-09-01__1144_weights_58_0.png