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))')
Example block output

As one can see, the designmatrix is nicely scaled

We can predict overlap-corrected results

p = predict(m; overlap = false)[1]
heatmap(p[1, :, :])
Example block output

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))')
Example block output

as one can see, now the designmatrix is not stretched - but rather "block"-ed

p = predict(m; overlap = false)[1]
heatmap(p[1, :, :])
Example block output

This page was generated using Literate.jl.