Define a new component (with variable duration and shift)

We want a new component that changes its duration and shift depending on a column in the event design. This is somewhat already implemented in the HRF + Pupil bases.

Setup

Click to expand
using UnfoldSim
using Unfold
using Random
using DSP
using CairoMakie, UnfoldMakie

sfreq = 100;

Design

Let's generate a design with two columns, shift + duration

design = UnfoldSim.SingleSubjectDesign(;
    conditions = Dict(
        :shift => rand(100) .* sfreq / 5,
        :duration => 20 .+ rand(100) .* sfreq / 5,
    ),
)
SingleSubjectDesign
  conditions: Dict{Symbol, Vector}
  event_order_function: #3 (function of type UnfoldSim.var"#3#7")

Implement a new AbstractComponent

We also need a new AbstractComponent

struct TimeVaryingComponent <: AbstractComponent
    basisfunction::Any
    maxlength::Any
end

We have to define the length of a component

Base.length(c::TimeVaryingComponent) = length(c.maxlength)

While we could have put the TimeVaryingComponent.basisfunction directly into the simulate function, I thought this is a bit more modular

function UnfoldSim.simulate(rng, c::TimeVaryingComponent, design::AbstractDesign)
    evts = generate_events(design)
    return c.basisfunction(evts, c.maxlength)
end

finally, the actual function that does the shifting + duration

function basis_shiftduration(evts, maxlength)
    basis = hanning.(Int.(round.(evts.duration))) ## hanning as long as duration
    if "shift" ∈ names(evts)
        basis = pad_array.(basis, Int.(round.(.-evts.shift)), 0) ## shift by adding 0 in front
    end
    # we should make sure that all bases have maxlength by appending / truncating
    difftomax = maxlength .- length.(basis)
    if any(difftomax .< 0)
        @warn "basis longer than max length in at least one case. either increase maxlength or redefine function. Trying to truncate the basis"
        basis[difftomax.>0] = pad_array.(basis[difftomax.>0], difftomax[difftomax.>0], 0)
        return [b[1:maxlength] for b in basis]
    else
        return pad_array.(basis, difftomax, 0)
    end
end
basis_shiftduration (generic function with 1 method)

Simulate data with the new component type

erp = UnfoldSim.simulate(
    MersenneTwister(1),
    TimeVaryingComponent(basis_shiftduration, 50),
    design,
)
plot_erpimage(hcat(erp...), sortvalues = generate_events(design).shift)
Example block output

This page was generated using Literate.jl.