FIR-Scaled duration predictors
using Unfold
using Interpolations
using UnfoldSim
using UnfoldMakie, CairoMakie
using DataFrames
data, evts = UnfoldSim.predef_eeg(sfreq = 10, n_repeats = 1)
evts.duration = 5:24
5:24
putting scale_duration = Interpolation.Linear()
will introduce a Cameron-Hassall 2022 PNAS- Style basisfunction, that scales with the :duration
column
basisfunction = firbasis(τ = (-1, 2), sfreq = 5, scale_duration = Interpolations.Linear())
�[0m�[22m╭──────────────────────────────────────────────────────────────────────────────╮�[22m�[0m8×16 SparseArrays.SparseMatrixCSC with 16 stored entries:
�[22m│�[22m �[1m�[34m::BasisFunction�[22m�[39m �[22m│�[22m⎡⠉⠒⠤⣀⠀⠀⠀⠀⎤
�[22m│�[22m �[1mname: �[22m�[38;2;144;202;249m�[39m �[22m│�[22m⎣⠀⠀⠀⠀⠉⠒⠤⣀⎦
�[22m│�[22m �[1mkerneltype: �[22m�[38;2;144;202;249mFIRBasis�[39m �[22m│�[22m
�[22m│�[22m �[1mwidth: �[22m�[38;2;144;202;249m16�[39m �[22m│�[22m
�[22m│�[22m �[1mheight: �[22m�[38;2;144;202;249mNaN�[39m �[22m│�[22m
�[22m│�[22m �[1mcolnames: �[22m�[38;2;144;202;249m[-1.0, -0.8 ... 2.0]�[39m �[22m│�[22m
�[22m│�[22m �[1mtimes: �[22m�[38;2;144;202;249m[-1.0, -0.8 ... 2.0]�[39m �[22m│�[22m
�[22m│�[22m �[1mcollabel: �[22m�[38;2;144;202;249mtime�[39m �[22m│�[22m
�[22m│�[22m �[1mshift_onset: �[22m�[38;2;144;202;249m-5�[39m �[22m│�[22m
�[22m│�[22m �[22m│�[22m
�[0m�[22m╰──────────────────────────────────────────────────────────────────────────────╯�[22m�[0m�[0m
Two examples with duration = 10
Unfold.kernel(basisfunction, [0, 10])
10×16 SparseArrays.SparseMatrixCSC{Float64, Int64} with 20 stored entries:
⎡⠙⠢⢄⡀⠀⠀⠀⠀⎤
⎢⠀⠀⠀⠉⠲⢄⡀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠈⠓⎦
and duration = 20
Unfold.kernel(basisfunction, [0, 20])
20×16 SparseArrays.SparseMatrixCSC{Float64, Int64} with 38 stored entries:
⎡⠳⣄⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠘⢧⡀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠹⣆⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠈⢳⡄⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠙⢦⎦
let's fit a model
f = @formula 0 ~ 1 + condition
bf_vec = [Any => (f, basisfunction)]
m = fit(UnfoldModel, bf_vec, evts, data; eventfields = [:latency, :duration]);
# currently bugged for small matrices
# plot_designmatrix(designmatrix(m))
# thus using
heatmap(Matrix(modelmatrix(m))')

As one can see, the designmatrix is nicely scaled
We can predict overlap-corrected results
p = predict(m; overlap = false)[1]
heatmap(p[1, :, :])

note the missings
which are displayed as white pixels.
Block-design predictors
In contrast, it is also possible to put scale_duration = true
- which wil not scale the matrix as before, but introduce a step-function.
putting scale_duration = Interpolation.Linear()
will introduce a Cameron-Hassall 2022 PNAS- Style basisfunction, that scales with the :duration
column
basisfunction = firbasis(τ = (-1, 2), sfreq = 5, scale_duration = true)
�[0m�[22m╭──────────────────────────────────────────────────────────────────────────────╮�[22m�[0m23×16 SparseArrays.SparseMatrixCSC with 128 stored entries:
�[22m│�[22m �[1m�[34m::BasisFunction�[22m�[39m �[22m│�[22m⎡⣷⣄⠀⠀⠀⠀⠀⠀⎤
�[22m│�[22m �[1mname: �[22m�[38;2;144;202;249m�[39m �[22m│�[22m⎢⣿⣿⣷⣄⠀⠀⠀⠀⎥
�[22m│�[22m �[1mkerneltype: �[22m�[38;2;144;202;249mFIRBasis�[39m �[22m│�[22m⎢⠈⠻⣿⣿⣷⣄⠀⠀⎥
�[22m│�[22m �[1mwidth: �[22m�[38;2;144;202;249m16�[39m �[22m│�[22m⎢⠀⠀⠈⠻⣿⣿⣷⣄⎥
�[22m│�[22m �[1mheight: �[22m�[38;2;144;202;249m16�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠈⠻⣿⣿⎥
�[22m│�[22m �[1mcolnames: �[22m�[38;2;144;202;249m[-1.0, -0.8 ... 2.0]�[39m �[22m│�[22m⎣⠀⠀⠀⠀⠀⠀⠈⠻⎦
�[22m│�[22m �[1mtimes: �[22m�[38;2;144;202;249m[-1.0, -0.8 ... 2.0]�[39m �[22m│�[22m
�[22m│�[22m �[1mcollabel: �[22m�[38;2;144;202;249mtime�[39m �[22m│�[22m
�[22m│�[22m �[1mshift_onset: �[22m�[38;2;144;202;249m-5�[39m �[22m│�[22m
�[22m│�[22m �[22m│�[22m
�[0m�[22m╰──────────────────────────────────────────────────────────────────────────────╯�[22m�[0m�[0m
Two examples with duration = 10
Unfold.kernel(basisfunction, [0, 10])
25×16 SparseArrays.SparseMatrixCSC{Int64, Int64} with 160 stored entries:
⎡⣷⣄⠀⠀⠀⠀⠀⠀⎤
⎢⣿⣿⣷⣄⠀⠀⠀⠀⎥
⎢⠻⣿⣿⣿⣷⣄⠀⠀⎥
⎢⠀⠈⠻⣿⣿⣿⣷⣄⎥
⎢⠀⠀⠀⠈⠻⣿⣿⣿⎥
⎢⠀⠀⠀⠀⠀⠈⠻⣿⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠈⎦
and duration = 20
Unfold.kernel(basisfunction, [0, 20])
35×16 SparseArrays.SparseMatrixCSC{Int64, Int64} with 320 stored entries:
⎡⣷⣄⠀⠀⠀⠀⠀⠀⎤
⎢⣿⣿⣷⣄⠀⠀⠀⠀⎥
⎢⣿⣿⣿⣿⣷⣄⠀⠀⎥
⎢⣿⣿⣿⣿⣿⣿⣷⣄⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⠈⠻⣿⣿⣿⣿⣿⣿⎥
⎢⠀⠀⠈⠻⣿⣿⣿⣿⎥
⎢⠀⠀⠀⠀⠈⠻⣿⣿⎥
⎣⠀⠀⠀⠀⠀⠀⠈⠻⎦
let's fit a model
f = @formula 0 ~ 1 + condition
bf_vec = [Any => (f, basisfunction)]
m = fit(UnfoldModel, bf_vec, evts, data; eventfields = [:latency, :duration]);
heatmap(Matrix(modelmatrix(m))')

as one can see, now the designmatrix is not stretched - but rather "block"-ed
p = predict(m; overlap = false)[1]
heatmap(p[1, :, :])

This page was generated using Literate.jl.