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.