UnfoldSim.AutoRegressiveNoise
— TypeAutoRegressiveNoise <: AbstractNoise
Not implemented
UnfoldSim.ExponentialNoise
— TypeExponentialNoise <: AbstractNoise
Noise with exponential decay in AR spectrum.
noiselevel
is used to scale the noise
Current implementation: Cholesky of NxN matrix needs to be calculated, which might need lots of RAM.
UnfoldSim.LinearModelComponent
— TypeA multiple regression component for one subject
basis
: an object, if accessed, provides a 'basis-function', e.g.hanning(40)
, this defines the response at a single event. It will be weighted by the model-predictionformula
: StatsModels Formula-Object@formula 0~1+cond
(left side must be 0)β
Vector of betas, must fit the formulacontrasts
: Dict. Default is empty, e.g.Dict(:condA=>EffectsCoding())
All arguments can be named, in that case contrasts
is optional
Works best with SingleSubjectDesign
LinearModelComponent(;
+API / DocStrings · UnfoldSim.jl UnfoldSim.AutoRegressiveNoise
— TypeAutoRegressiveNoise <: AbstractNoise
Not implemented
sourceUnfoldSim.ExponentialNoise
— TypeExponentialNoise <: AbstractNoise
Noise with exponential decay in AR spectrum.
noiselevel
is used to scale the noise
Warning Current implementation: Cholesky of NxN matrix needs to be calculated, which might need lots of RAM.
sourceUnfoldSim.LinearModelComponent
— TypeA multiple regression component for one subject
basis
: an object, if accessed, provides a 'basis-function', e.g. hanning(40)
, this defines the response at a single event. It will be weighted by the model-predictionformula
: StatsModels Formula-Object @formula 0~1+cond
(left side must be 0)β
Vector of betas, must fit the formulacontrasts
: Dict. Default is empty, e.g. Dict(:condA=>EffectsCoding())
All arguments can be named, in that case contrasts
is optional
Works best with SingleSubjectDesign
LinearModelComponent(;
basis=hanning(40),
formula=@formula(0~1+cond),
β = [1.,2.],
contrasts=Dict(:cond=>EffectsCoding())
)
-
sourceUnfoldSim.LogNormalOnset
— Type@with_kw struct LogNormalOnset <: AbstractOnset
Log-normal inter-event distances using the Distributions.jl
truncated LogNormal distribution.
Be careful with large μ
and σ
values, as they are on logscale. σ>8 can quickly give you out-of-memory sized signals!
sourceUnfoldSim.MixedModelComponent
— TypeA component that adds a hierarchical relation between parameters according to a LMM defined via MixedModels.jl
basis
: an object, if accessed, provides a 'basis-function', e.g. hanning(40)
, this defines the response at a single event. It will be weighted by the model-predictionformula
: Formula-Object in the style of MixedModels.jl e.g. @formula 0~1+cond + (1|subject)
- left-handside is ignoredβ
Vector of betas, must fit the formulaσs
Dict of random effect variances, e.g. Dict(:subject=>[0.5,0.4])
or to specify correlationmatrix Dict(:subject=>[0.5,0.4,I(2,2)],...)
. Technically, this will be passed to MixedModels.jl create_re
function, which creates the θ matrices.contrasts
: Dict in the style of MixedModels.jl. Default is empty.
All arguments can be named, in that case contrasts
is optional
Works best with MultiSubjectDesign
MixedModelComponent(;
+
sourceUnfoldSim.LogNormalOnset
— Type@with_kw struct LogNormalOnset <: AbstractOnset
Log-normal inter-event distances using the Distributions.jl
truncated LogNormal distribution.
Be careful with large μ
and σ
values, as they are on logscale. σ>8 can quickly give you out-of-memory sized signals!
sourceUnfoldSim.MixedModelComponent
— TypeA component that adds a hierarchical relation between parameters according to a LMM defined via MixedModels.jl
basis
: an object, if accessed, provides a 'basis-function', e.g. hanning(40)
, this defines the response at a single event. It will be weighted by the model-predictionformula
: Formula-Object in the style of MixedModels.jl e.g. @formula 0~1+cond + (1|subject)
- left-handside is ignoredβ
Vector of betas, must fit the formulaσs
Dict of random effect variances, e.g. Dict(:subject=>[0.5,0.4])
or to specify correlationmatrix Dict(:subject=>[0.5,0.4,I(2,2)],...)
. Technically, this will be passed to MixedModels.jl create_re
function, which creates the θ matrices.contrasts
: Dict in the style of MixedModels.jl. Default is empty.
All arguments can be named, in that case contrasts
is optional
Works best with MultiSubjectDesign
MixedModelComponent(;
basis=hanning(40),
formula=@formula(0~1+cond+(1+cond|subject)),
β = [1.,2.],
σs= Dict(:subject=>[0.5,0.4]),
contrasts=Dict(:cond=>EffectsCoding())
)
-
sourceUnfoldSim.MultiSubjectDesign
— TypeMultiSubjectDesign
n_subjects
::Int -> number of subjectsn_items
::Int -> number of items (sometimes ≈trials)subjects_between
= Dict{Symbol,Vector} -> effects between subjects, e.g. young vs old items_between
= Dict{Symbol,Vector} -> effects between items, e.g. natural vs artificial images, (but shown to all subjects if not specified also in subjects_between
)both_within
= Dict{Symbol,Vector} -> effects completly crossedevent_order_function
= x->x
; # can be used to sort, or e.g. x->shuffle(MersenneTwister(42),x)
- be sure to fix/update the rng accordingly!!
tipp: check the resulting dataframe using generate_events(design)
# declaring same condition both sub-between and item-between results in a full between subject/item design
+
sourceUnfoldSim.MultiSubjectDesign
— TypeMultiSubjectDesign
n_subjects
::Int -> number of subjectsn_items
::Int -> number of items (sometimes ≈trials)subjects_between
= Dict{Symbol,Vector} -> effects between subjects, e.g. young vs old items_between
= Dict{Symbol,Vector} -> effects between items, e.g. natural vs artificial images, (but shown to all subjects if not specified also in subjects_between
)both_within
= Dict{Symbol,Vector} -> effects completly crossedevent_order_function
= x->x
; # can be used to sort, or e.g. x->shuffle(MersenneTwister(42),x)
- be sure to fix/update the rng accordingly!!
tipp: check the resulting dataframe using generate_events(design)
# declaring same condition both sub-between and item-between results in a full between subject/item design
design = MultiSubjectDesign(;
n_items = 10,
n_subjects = 30,
subjects_between = Dict(:cond => ["levelA", "levelB"]),
items_between = Dict(:cond => ["levelA", "levelB"]),
- );
sourceUnfoldSim.MultichannelComponent
— TypeWrapper for an AbstractComponent
to project it to multiple target-channels via projection
. optional adds noise
to the source prior to projection.
sourceUnfoldSim.NoNoise
— TypeNoNoise <: AbstractNoise
Return zeros instead of noise.
sourceUnfoldSim.NoOnset
— Typestruct NoOnset <: AbstractOnset end
In the case that the user directly wants no overlap to be simulated (=> epoched data).
sourceUnfoldSim.PinkNoise
— TypePinkNoise <: AbstractNoise
Generate Pink Noise using the SignalAnalysis.jl implementation.
noiselevel
is used to scale the noise
sourceUnfoldSim.RealisticNoise
— TypeRealisticNoise <: AbstractNoise
Not implemented - planned to use Artefacts.jl to provide real EEG data to add.
sourceUnfoldSim.RedNoise
— TypeRedNoise <: AbstractNoise
Generate Red Noise using the SignalAnalysis.jl implementation.
noiselevel
is used to scale the noise
sourceUnfoldSim.RepeatDesign
— TypeRepeatDesign{T}
Repeat a design DataFrame multiple times to mimick repeatedly recorded trials.
designOnce = MultiSubjectDesign(;
+ );
sourceUnfoldSim.MultichannelComponent
— TypeWrapper for an AbstractComponent
to project it to multiple target-channels via projection
. optional adds noise
to the source prior to projection.
sourceUnfoldSim.NoNoise
— TypeNoNoise <: AbstractNoise
Return zeros instead of noise.
sourceUnfoldSim.NoOnset
— Typestruct NoOnset <: AbstractOnset end
In the case that the user directly wants no overlap to be simulated (=> epoched data).
sourceUnfoldSim.PinkNoise
— TypePinkNoise <: AbstractNoise
Generate Pink Noise using the SignalAnalysis.jl implementation.
noiselevel
is used to scale the noise
sourceUnfoldSim.RealisticNoise
— TypeRealisticNoise <: AbstractNoise
Not implemented - planned to use Artefacts.jl to provide real EEG data to add.
sourceUnfoldSim.RedNoise
— TypeRedNoise <: AbstractNoise
Generate Red Noise using the SignalAnalysis.jl implementation.
noiselevel
is used to scale the noise
sourceUnfoldSim.RepeatDesign
— TypeRepeatDesign{T}
Repeat a design DataFrame multiple times to mimick repeatedly recorded trials.
designOnce = MultiSubjectDesign(;
n_items=2,
n_subjects = 2,
subjects_between =Dict(:cond=>["levelA","levelB"]),
items_between =Dict(:cond=>["levelA","levelB"]),
);
-design = RepeatDesign(designOnce,4);
sourceUnfoldSim.SingleSubjectDesign
— Type- conditions = Dict{Symbol,Vector} of conditions, e.g.
Dict(:A=>["a_small","a_big"],:B=>["b_tiny","b_large"])
event_order_function
= x->x; # can be used to sort, or x->shuffle(MersenneTwister(42),x) - be sure to fix/update the rng accordingly!!
Number of trials / rows in generate_events(design)
depend on the full factorial of your conditions
.
To increase the number of repetitions simply use RepeatDesign(SingleSubjectDesign(...),5)
If conditions are omitted (or set to nothing
), a single trial is simulated with a column :dummy
and content :dummy
- this is for convenience.
tipp: check the resulting dataframe using generate_events(design)
sourceUnfoldSim.UniformOnset
— Typestruct UniformOnset <: AbstractOnset
Provide a Uniform Distribution of the inter-event-distances. width
is the width of the uniform distribution (=> the jitter). Since the lower bound is 0, width
is also the upper bound. offset
is the minimal distance. The maximal distance is offset + width
.
sourceUnfoldSim.WhiteNoise
— TypeWhiteNoise <: WhiteNoise
+design = RepeatDesign(designOnce,4);
sourceUnfoldSim.SingleSubjectDesign
— Type- conditions = Dict{Symbol,Vector} of conditions, e.g.
Dict(:A=>["a_small","a_big"],:B=>["b_tiny","b_large"])
event_order_function
= x->x; # can be used to sort, or x->shuffle(MersenneTwister(42),x) - be sure to fix/update the rng accordingly!!
Number of trials / rows in generate_events(design)
depend on the full factorial of your conditions
.
To increase the number of repetitions simply use RepeatDesign(SingleSubjectDesign(...),5)
If conditions are omitted (or set to nothing
), a single trial is simulated with a column :dummy
and content :dummy
- this is for convenience.
tipp: check the resulting dataframe using generate_events(design)
sourceUnfoldSim.UniformOnset
— Typestruct UniformOnset <: AbstractOnset
Provide a Uniform Distribution of the inter-event-distances. width
is the width of the uniform distribution (=> the jitter). Since the lower bound is 0, width
is also the upper bound. offset
is the minimal distance. The maximal distance is offset + width
.
sourceUnfoldSim.WhiteNoise
— TypeWhiteNoise <: WhiteNoise
noiselevel = 1
-imfilter = 0
Generate White Noise using randn
- thus Gaussian noise. noiselevel
is used to scale the noise
Using imfilter
> 0 it is possible to smooth the noise using Image.imfilter.
sourceBase.size
— MethodReturns dimension of experiment design
sourceDSP.Windows.hanning
— Methodgenerate a hanning window
duration: in s offset: in s, defines hanning peak sfreq: sampling rate in Hz
sourceUnfoldSim.PuRF
— MethodPuRF()
Default generator for PuRF Pupil Response Function.
sourceUnfoldSim.add_noise!
— Methodadd_noise!(rng, noisetype::AbstractNoise, signal)
Generate and add noise to a data matrix. Assumes that the signal can be linearized, that is, that the noise is stationary
sourceUnfoldSim.add_responses!
— Methodadd_responses!(signal, responses::Vector, e, s, tvec, erpvec)
+imfilter = 0
Generate White Noise using randn
- thus Gaussian noise. noiselevel
is used to scale the noise
Using imfilter
> 0 it is possible to smooth the noise using Image.imfilter.
sourceBase.size
— MethodReturns dimension of experiment design
sourceDSP.Windows.hanning
— Methodgenerate a hanning window
duration: in s offset: in s, defines hanning peak sfreq: sampling rate in Hz
sourceUnfoldSim.PuRF
— MethodPuRF()
Default generator for PuRF Pupil Response Function.
sourceUnfoldSim.add_noise!
— Methodadd_noise!(rng, noisetype::AbstractNoise, signal)
Generate and add noise to a data matrix. Assumes that the signal can be linearized, that is, that the noise is stationary
sourceUnfoldSim.add_responses!
— Methodadd_responses!(signal, responses::Vector, e, s, tvec, erpvec)
add_responses!(signal, responses::Matrix, e, s, tvec, erpvec)
-add_responses!(signal, responses::AbstractArray, e, s, tvec, erpvec)
Helper function to add inplace the responses to the signal, but for both 2D (1 channel) and 3D (X channel case).
sourceUnfoldSim.closest_src
— Methodclosest_src(coords_list::AbstractVector{<:AbstractVector}, pos)
-closest_src(coords::Vector{<:Real}, pos)
Takes an array of 'm' target coordinate vector (size 3) (or vector of vectors) and a matrix (n-by-3) of all available positions, and returns an array of size 'm' containing the indices of the respective items in 'pos' that are nearest to each of the target coordinates.
sourceUnfoldSim.closest_src
— Methodclosest_src(head::Hartmut,label::String)
Returns src-ix
of the Headmodel Hartmut
which is closest to the average of the label
.
Important We use the average in eucledean space, but the cortex is a curved surface. In most cases they will not overlap. Ideally we would calculate the average on the surface, but this is a bit more complex to do (you'd need to calculate the vertices etc.)
hartmut = headmodel()
-pos = closest_src(hartmut=>"Left Middle Temporal Gyrus, posterior division")
sourceUnfoldSim.convert
— MethodObsolete - # TODO: Transfer function to Unfold.jl
Function to convert output similar to unfold (data, events)
sourceUnfoldSim.create_continuous_signal
— Methodcreate_continuous_signal(rng, responses, simulation)
Based on the responses and simulation parameters, simulate onset latencies and add together a continuous signal.
sourceUnfoldSim.epoch
— Methodepoch(data::AbstractVector, args...; kwargs...)
+add_responses!(signal, responses::AbstractArray, e, s, tvec, erpvec)
Helper function to add inplace the responses to the signal, but for both 2D (1 channel) and 3D (X channel case).
sourceUnfoldSim.closest_src
— Methodclosest_src(coords_list::AbstractVector{<:AbstractVector}, pos)
+closest_src(coords::Vector{<:Real}, pos)
Takes an array of 'm' target coordinate vector (size 3) (or vector of vectors) and a matrix (n-by-3) of all available positions, and returns an array of size 'm' containing the indices of the respective items in 'pos' that are nearest to each of the target coordinates.
sourceUnfoldSim.closest_src
— Methodclosest_src(head::Hartmut,label::String)
Returns src-ix
of the Headmodel Hartmut
which is closest to the average of the label
.
Important We use the average in eucledean space, but the cortex is a curved surface. In most cases they will not overlap. Ideally we would calculate the average on the surface, but this is a bit more complex to do (you'd need to calculate the vertices etc.)
hartmut = headmodel()
+pos = closest_src(hartmut=>"Left Middle Temporal Gyrus, posterior division")
sourceUnfoldSim.convert
— MethodObsolete - # TODO: Transfer function to Unfold.jl
Function to convert output similar to unfold (data, events)
sourceUnfoldSim.create_continuous_signal
— Methodcreate_continuous_signal(rng, responses, simulation)
Based on the responses and simulation parameters, simulate onset latencies and add together a continuous signal.
sourceUnfoldSim.epoch
— Methodepoch(data::AbstractVector, args...; kwargs...)
epoch(
data::AbstractArray{T,2},
events,
τ::Tuple{Number,Number},
sfreq;
eventtime::Symbol = :latency,
-) where {T<:Union{Missing,Number}}
Helper function to epoch data.
Adapted from Unfold.jl: https://github.com/unfoldtoolbox/Unfold.jl/blob/b3a21c2bb7e93d2f45ec64b0197f4663a6d7939a/src/utilities.jl#L40
sourceUnfoldSim.generate_events
— Methodgenerate_events(design::MultiSubjectDesign)
Generate full factorial Dataframe according to MixedModelsSim.jl 's simdat_crossed
function. Note: n_items = you can think of it as trials
or better, as stimuli
.
Note: No condition can be named dv
which is used internally in MixedModelsSim / MixedModels as a dummy left-side
Afterwards applies design.event_order_function
`. Could be used to duplicate trials, sort, subselect etc.
Finally it sorts by :subject
julia> d = MultiSubjectDesign(;nsubjects = 10,nitems=20,bothwithin= Dict(:A=>nlevels(5),:B=>nlevels(2))) julia> generateevents(d)
sourceUnfoldSim.generate_events
— MethodUnfoldSim.generate_events(design::RepeatDesign{T})
In a repeated design, iteratively calls the underlying {T} Design and concatenates. In case of MultiSubjectDesign, sorts by subject.
sourceUnfoldSim.generate_events
— MethodGenerates full-factorial DataFrame of design.conditions
Afterwards applies design.eventorderfunction.
If conditions is nothing
, a single trial is simulated with a column :dummy
and content :dummy
- this is for convenience.
julia> d = SingleSubjectDesign(;conditions= Dict(:A=>nlevels(5),:B=>nlevels(2))) julia> generate_events(d)
sourceUnfoldSim.hartmut_citation
— MethodReturns citation-string for HArtMuT
sourceUnfoldSim.headmodel
— MethodLoad a headmodel, using Artifacts.jl automatically downloads the required files
Currently only type="hartmut"
is implemented
sourceUnfoldSim.hrf
— MethodGenerate a HRF kernel.
TR = 1/sfreq default parameters taken from SPM
Code adapted from Unfold.jl
sourceUnfoldSim.leadfield
— MethodReturns the leadfield
sourceUnfoldSim.magnitude
— MethodExtracts magnitude of the orientation-including leadfield.
By default uses the orientation specified in the headmodel
Fallback: along the third dimension using norm
- the maximal projection
sourceUnfoldSim.magnitude
— Methodmagnitude(headmodel::Hartmut; type = "perpendicular") = Extract magnitude of 3-orientation-leadfield, type
(default: "perpendicular") => uses the provided source-point orientations - otherwise falls back to norm
.
sourceUnfoldSim.magnitude
— Methodmagnitude(lf::AbstractArray{T,3}) where {T<:Real}
If orientation is not specified, returns the maximal magnitude (norm of leadfield).
sourceUnfoldSim.magnitude
— Methodmagnitude(lf::AbstractArray{T,3}, orientation::AbstractArray{T,2}) where {T<:Real}
Return the magnitude along an orientation of the leadfield.
sourceUnfoldSim.maxlength
— Methodmaxlength(c::Vector{<:AbstractComponent}) = maximum(length.(c))
maximum of individual component lengths
sourceUnfoldSim.n170
— Methodn170(;sfreq=100)
Generator for Hanning window, negative (!) peak at 170ms, width 150ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.n400
— Methodn400(;sfreq=100)
Generator for Hanning window, negative (!) peak at 400ms, width 400ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.n_channels
— Methodn_channels(c::AbstractComponent)
Return the number of channels. By default = 1.
sourceUnfoldSim.n_channels
— Methodn_channels(c::MultichannelComponent)
For MultichannelComponent
return the length of the projection vector.
sourceUnfoldSim.n_channels
— MethodFor a vector of MultichannelComponent
s, return the first but asserts all are of equal length.
sourceUnfoldSim.p100
— Methodp100(;sfreq=100)
Generator for Hanning window, peak at 100ms, width 100ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.p300
— Methodp300(;sfreq=100)
Generator for Hanning window, peak at 300ms, width 300ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.pad_array
— MethodPads array with specified value, length pad_array(arr, len, val)
sourceUnfoldSim.predef_2x2
— Methodpredef_2x2(rng::AbstractRNG;kwargs...)
The most used kwargs
is: return_epoched=true
which returns already epoched data. If you want epoched data without overlap, specify onset=NoOnset()
and return_epoched=true
design
n_items
=100,n_subjects
=1,conditions
= Dict(:A=>["asmall","abig"],:B=>["btiny","blarge"]),event_order_function
= x->shuffle(deepcopy(rng),x),
component / signal
signalsize
= 100, length of simulated hanning windowbasis
= hanning(signalsize), the actual "function",
signalsize` is only used hereβ
= [1,-0.5,.5,+1], the parametersσs
= Dict(:subject=>[1,0.5,0.5,0.5],:item=>[1]), - only in n_subjects>=2 case, specifies the random effectscontrasts
= Dict(:A=>EffectsCoding(),:B=>EffectsCoding()) - effect coding by defaultformula
= n_subjects==1 ? @formula(0~1+AB) : @formula(dv~1+AB+(A*B|subject)+(1|item)),
noise
noiselevel
= 0.2,noise
= PinkNoise(;noiselevel=noiselevel),
onset
overlap
= (0.5,0.2),onset
=UniformOnset(;offset=signalsizeoverlap[1],width=signalsizeoverlap[2]), #put offset to 1 for no overlap. put width to 0 for no jitter
Careful if you modify nitems with nsubjects = 1, n_items has to be a multiple of 4 (or your equivalent conditions factorial, e.g. all combinations length)
sourceUnfoldSim.predef_eeg
— Methodpredefeeg(;kwargs...) predefeeg(rng;kwargs...) predefeeg(rng,nsubjects;kwargs...)
Generate a P1/N1/P3 complex. In case n_subjects
is defined - MixedModelComponents
are generated, else LinearModelComponents
.
The most used kwargs
is: return_epoched=true
which returns already epoched data. If you want epoched data without overlap, specify onset=NoOnset()
and return_epoched=true
Default params:
- n_repeats = 100
- eventorderfunction = x->shuffle(deepcopy(rng),x # random trial order
- conditions = Dict(...),
component / signal
- sfreq = 100,
- p1 = (p100(;sfreq=sfreq), @formula(0~1),[5],Dict()), # P1 amp 5, no effects
- n1 = (n170(;sfreq=sfreq), @formula(0~1+condition),[5,-3],Dict()), # N1 amp 5, dummycoded condition effect (levels "car", "face") of -3
- p3 = (p300(;sfreq=sfreq), @formula(0~1+continuous),[5,1],Dict()), # P3 amp 5, continuous effect range [-5,5] with slope 1
noise
- noiselevel = 0.2,
- noise = PinkNoise(;noiselevel=noiselevel),
onset
- overlap = (0.5,0.2), # offset + width/length of Uniform noise. put offset to 1 for no overlap. put width to 0 for no jitter
- onset=UniformOnset(;offset=sfreq0.5overlap[1],width=sfreq0.5overlap[2]),
sourceUnfoldSim.simulate_and_add!
— Methodsimulate_and_add!(epoch_data::AbstractMatrix, c, simulation, rng)
-simulate_and_add!(epoch_data::AbstractArray, c, simulation, rng)
Helper function to call simulate_component
and add it to a provided Array.
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::AbstractComponent, simulation::Simulation)
By default call simulate_component
with (::Abstractcomponent,::AbstractDesign)
instead of the whole simulation. This allows users to provide a hook to do something completely different :)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::AbstractComponent, simulation::Simulation)
Generate a linear model design matrix, weight it by c.β and multiply the result with the given basis vector.
julia> c = UnfoldSim.LinearModelComponent([0,1,1,0],@formula(0~1+cond),[1,2],Dict()) julia> design = MultiSubjectDesign(;nsubjects=2,nitems=50,itemsbetween=(;:cond=>["A","B"])) julia> simulatecomponent(StableRNG(1),c,design)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::MixedModelComponent, design::AbstractDesign)
Generates a MixedModel and simulates data according to c.β and c.σs.
A trick is used to remove the Normal-Noise from the MixedModel which might lead to rare numerical instabilities. Practically, we upscale the σs by factor 10000, and provide a σ=0.0001. Internally this results in a normalization where the response scale is 10000 times larger than the noise.
Currently, it is not possible to use a different basis for fixed and random effects, but a code-stub exists (it is slow though).
return_parameters
(Bool,false) - can be used to return the per-event parameters used to weight the basis function. Sometimes useful to see what is simulated
julia> design = MultiSubjectDesign(;nsubjects=2,nitems=50,items_between=(;:cond=>["A","B"])) julia> c = UnfoldSim.MixedModelComponent([0.,1,1,0],@formula(0~1+cond+(1|subject)),[1,2],Dict(:subject=>[2],),Dict()) julia> simulate(StableRNG(1),c,design)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng,c::MultichannelComponent,design::AbstractDesign)
Return the projection of a component from source to "sensor" space.
sourceUnfoldSim.simulate_noise
— Methodsimulate_noise(rng, t::NoNoise, n::Int)
Return zeros instead of noise.
sourceUnfoldSim.simulate_noise
— Methodsimulate_noise(rng, t::Union{PinkNoise,RedNoise}, n::Int)
Generate Pink or Red Noise using the SignalAnalysis.jl
implementation.
sourceUnfoldSim.simulate_onsets
— Methodsimulate_onsets(rng, onset::AbstractOnset, simulation::Simulation)
Call simulate_interonset_distances
to generate distances between events and then add them up to generate the actual latencies in samples.
main call from simulation
sourceUnfoldSim.simulate_responses
— Methodsimulate_responses(
+) where {T<:Union{Missing,Number}}
Helper function to epoch data.
Adapted from Unfold.jl: https://github.com/unfoldtoolbox/Unfold.jl/blob/b3a21c2bb7e93d2f45ec64b0197f4663a6d7939a/src/utilities.jl#L40
sourceUnfoldSim.generate_events
— Methodgenerate_events(design::MultiSubjectDesign)
Generate full factorial Dataframe according to MixedModelsSim.jl 's simdat_crossed
function. Note: n_items = you can think of it as trials
or better, as stimuli
.
Note: No condition can be named dv
which is used internally in MixedModelsSim / MixedModels as a dummy left-side
Afterwards applies design.event_order_function
`. Could be used to duplicate trials, sort, subselect etc.
Finally it sorts by :subject
julia> d = MultiSubjectDesign(;nsubjects = 10,nitems=20,bothwithin= Dict(:A=>nlevels(5),:B=>nlevels(2))) julia> generateevents(d)
sourceUnfoldSim.generate_events
— MethodUnfoldSim.generate_events(design::RepeatDesign{T})
In a repeated design, iteratively calls the underlying {T} Design and concatenates. In case of MultiSubjectDesign, sorts by subject.
sourceUnfoldSim.generate_events
— MethodGenerates full-factorial DataFrame of design.conditions
Afterwards applies design.eventorderfunction.
If conditions is nothing
, a single trial is simulated with a column :dummy
and content :dummy
- this is for convenience.
julia> d = SingleSubjectDesign(;conditions= Dict(:A=>nlevels(5),:B=>nlevels(2))) julia> generate_events(d)
sourceUnfoldSim.hartmut_citation
— MethodReturns citation-string for HArtMuT
sourceUnfoldSim.headmodel
— MethodLoad a headmodel, using Artifacts.jl automatically downloads the required files
Currently only type="hartmut"
is implemented
sourceUnfoldSim.hrf
— MethodGenerate a HRF kernel.
TR = 1/sfreq default parameters taken from SPM
Code adapted from Unfold.jl
sourceUnfoldSim.leadfield
— MethodReturns the leadfield
sourceUnfoldSim.magnitude
— MethodExtracts magnitude of the orientation-including leadfield.
By default uses the orientation specified in the headmodel
Fallback: along the third dimension using norm
- the maximal projection
sourceUnfoldSim.magnitude
— Methodmagnitude(headmodel::Hartmut; type = "perpendicular") = Extract magnitude of 3-orientation-leadfield, type
(default: "perpendicular") => uses the provided source-point orientations - otherwise falls back to norm
.
sourceUnfoldSim.magnitude
— Methodmagnitude(lf::AbstractArray{T,3}) where {T<:Real}
If orientation is not specified, returns the maximal magnitude (norm of leadfield).
sourceUnfoldSim.magnitude
— Methodmagnitude(lf::AbstractArray{T,3}, orientation::AbstractArray{T,2}) where {T<:Real}
Return the magnitude along an orientation of the leadfield.
sourceUnfoldSim.maxlength
— Methodmaxlength(c::Vector{<:AbstractComponent}) = maximum(length.(c))
maximum of individual component lengths
sourceUnfoldSim.n170
— Methodn170(;sfreq=100)
Generator for Hanning window, negative (!) peak at 170ms, width 150ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.n400
— Methodn400(;sfreq=100)
Generator for Hanning window, negative (!) peak at 400ms, width 400ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.n_channels
— Methodn_channels(c::AbstractComponent)
Return the number of channels. By default = 1.
sourceUnfoldSim.n_channels
— Methodn_channels(c::MultichannelComponent)
For MultichannelComponent
return the length of the projection vector.
sourceUnfoldSim.n_channels
— MethodFor a vector of MultichannelComponent
s, return the first but asserts all are of equal length.
sourceUnfoldSim.p100
— Methodp100(;sfreq=100)
Generator for Hanning window, peak at 100ms, width 100ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.p300
— Methodp300(;sfreq=100)
Generator for Hanning window, peak at 300ms, width 300ms, at kwargs sfreq
(default 100). Returns a vector.
sourceUnfoldSim.pad_array
— MethodPads array with specified value, length pad_array(arr, len, val)
sourceUnfoldSim.predef_2x2
— Methodpredef_2x2(rng::AbstractRNG;kwargs...)
The most used kwargs
is: return_epoched=true
which returns already epoched data. If you want epoched data without overlap, specify onset=NoOnset()
and return_epoched=true
design
n_items
=100,n_subjects
=1,conditions
= Dict(:A=>["asmall","abig"],:B=>["btiny","blarge"]),event_order_function
= x->shuffle(deepcopy(rng),x),
component / signal
signalsize
= 100, length of simulated hanning windowbasis
= hanning(signalsize), the actual "function",
signalsize` is only used hereβ
= [1,-0.5,.5,+1], the parametersσs
= Dict(:subject=>[1,0.5,0.5,0.5],:item=>[1]), - only in n_subjects>=2 case, specifies the random effectscontrasts
= Dict(:A=>EffectsCoding(),:B=>EffectsCoding()) - effect coding by defaultformula
= n_subjects==1 ? @formula(0~1+AB) : @formula(dv~1+AB+(A*B|subject)+(1|item)),
noise
noiselevel
= 0.2,noise
= PinkNoise(;noiselevel=noiselevel),
onset
overlap
= (0.5,0.2),onset
=UniformOnset(;offset=signalsizeoverlap[1],width=signalsizeoverlap[2]), #put offset to 1 for no overlap. put width to 0 for no jitter
Careful if you modify nitems with nsubjects = 1, n_items has to be a multiple of 4 (or your equivalent conditions factorial, e.g. all combinations length)
sourceUnfoldSim.predef_eeg
— Methodpredefeeg(;kwargs...) predefeeg(rng;kwargs...) predefeeg(rng,nsubjects;kwargs...)
Generate a P1/N1/P3 complex. In case n_subjects
is defined - MixedModelComponents
are generated, else LinearModelComponents
.
The most used kwargs
is: return_epoched=true
which returns already epoched data. If you want epoched data without overlap, specify onset=NoOnset()
and return_epoched=true
Default params:
- n_repeats = 100
- eventorderfunction = x->shuffle(deepcopy(rng),x # random trial order
- conditions = Dict(...),
component / signal
- sfreq = 100,
- p1 = (p100(;sfreq=sfreq), @formula(0~1),[5],Dict()), # P1 amp 5, no effects
- n1 = (n170(;sfreq=sfreq), @formula(0~1+condition),[5,-3],Dict()), # N1 amp 5, dummycoded condition effect (levels "car", "face") of -3
- p3 = (p300(;sfreq=sfreq), @formula(0~1+continuous),[5,1],Dict()), # P3 amp 5, continuous effect range [-5,5] with slope 1
noise
- noiselevel = 0.2,
- noise = PinkNoise(;noiselevel=noiselevel),
onset
- overlap = (0.5,0.2), # offset + width/length of Uniform noise. put offset to 1 for no overlap. put width to 0 for no jitter
- onset=UniformOnset(;offset=sfreq0.5overlap[1],width=sfreq0.5overlap[2]),
sourceUnfoldSim.simulate_and_add!
— Methodsimulate_and_add!(epoch_data::AbstractMatrix, c, simulation, rng)
+simulate_and_add!(epoch_data::AbstractArray, c, simulation, rng)
Helper function to call simulate_component
and add it to a provided Array.
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::AbstractComponent, simulation::Simulation)
By default call simulate_component
with (::Abstractcomponent,::AbstractDesign)
instead of the whole simulation. This allows users to provide a hook to do something completely different :)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::AbstractComponent, simulation::Simulation)
Generate a linear model design matrix, weight it by c.β and multiply the result with the given basis vector.
julia> c = UnfoldSim.LinearModelComponent([0,1,1,0],@formula(0~1+cond),[1,2],Dict()) julia> design = MultiSubjectDesign(;nsubjects=2,nitems=50,itemsbetween=(;:cond=>["A","B"])) julia> simulatecomponent(StableRNG(1),c,design)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng, c::MixedModelComponent, design::AbstractDesign)
Generates a MixedModel and simulates data according to c.β and c.σs.
A trick is used to remove the Normal-Noise from the MixedModel which might lead to rare numerical instabilities. Practically, we upscale the σs by factor 10000, and provide a σ=0.0001. Internally this results in a normalization where the response scale is 10000 times larger than the noise.
Currently, it is not possible to use a different basis for fixed and random effects, but a code-stub exists (it is slow though).
return_parameters
(Bool,false) - can be used to return the per-event parameters used to weight the basis function. Sometimes useful to see what is simulated
julia> design = MultiSubjectDesign(;nsubjects=2,nitems=50,items_between=(;:cond=>["A","B"])) julia> c = UnfoldSim.MixedModelComponent([0.,1,1,0],@formula(0~1+cond+(1|subject)),[1,2],Dict(:subject=>[2],),Dict()) julia> simulate(StableRNG(1),c,design)
sourceUnfoldSim.simulate_component
— Methodsimulate_component(rng,c::MultichannelComponent,design::AbstractDesign)
Return the projection of a component from source to "sensor" space.
sourceUnfoldSim.simulate_noise
— Methodsimulate_noise(rng, t::NoNoise, n::Int)
Return zeros instead of noise.
sourceUnfoldSim.simulate_noise
— Methodsimulate_noise(rng, t::Union{PinkNoise,RedNoise}, n::Int)
Generate Pink or Red Noise using the SignalAnalysis.jl
implementation.
sourceUnfoldSim.simulate_onsets
— Methodsimulate_onsets(rng, onset::AbstractOnset, simulation::Simulation)
Call simulate_interonset_distances
to generate distances between events and then add them up to generate the actual latencies in samples.
main call from simulation
sourceUnfoldSim.simulate_responses
— Methodsimulate_responses(
rng,
components::Vector{<:AbstractComponent},
- simulation::Simulation)
Simulate multiple component responses and accumulates them on a per-event basis.
sourceUnfoldSim.weight_σs
— MethodWeights a σs Dict for MixedModels.jl by a Float64
Finally sales it by σ_lmm, as a trick to simulate noise-free LMMs
I anticipate a function function weight_σs(σs::Dict,b_σs::Dict,σ_lmm::Float64)
where each σs entry can be weighted individually
sourceSettings
This document was generated with Documenter.jl version 1.4.1 on Thursday 6 June 2024. Using Julia version 1.10.4.
+ simulation::Simulation)
Simulate multiple component responses and accumulates them on a per-event basis.
UnfoldSim.weight_σs
— MethodWeights a σs Dict for MixedModels.jl by a Float64
Finally sales it by σ_lmm, as a trick to simulate noise-free LMMs
I anticipate a function function weight_σs(σs::Dict,b_σs::Dict,σ_lmm::Float64)
where each σs entry can be weighted individually