Use existing experimental designs & onsets in the simulation
Let's say you want to use the events data frame (containing the levels of the experimental variables and the event onsets (latencies)) from a previous study in your simulation.
Setup
Click to expand
# Load required packages
using UnfoldSim
using DataFrames
using Random
using CairoMakie # for plottingFrom a previous study, we (somehow, e.g. by using pyMNE.jl) imported an event data frame like this:
my_events = DataFrame(:condition => [:A, :B, :B, :A, :A], :latency => [7, 13, 22, 35, 41])| Row | condition | latency |
|---|---|---|
| Symbol | Int64 | |
| 1 | A | 7 |
| 2 | B | 13 |
| 3 | B | 22 |
| 4 | A | 35 |
| 5 | A | 41 |
To use exactly these values, we can generate a new AbstractDesign, which will always return this event dataframe
struct MyManualDesign <: AbstractDesign
my_events::Any
end
UnfoldSim.generate_events(rng, d::MyManualDesign) = deepcopy(d.my_events) ## generate function which is called internally in UnfoldSim
UnfoldSim.size(d::MyManualDesign) = size(d.my_events, 1); ## necessary function to tell what the dimensionality of the experimental design isNote the UnfoldSim.generate_events which tells Julia to "overload" the generate_events function as defined in UnfoldSim.
Next we generate a MyManualDesign
mydesign = MyManualDesign(my_events);We could already use this "solo" and simulate some data, for example:
signal = LinearModelComponent(;
basis = [1, 1, 0.5, 0, 0],
formula = @formula(0 ~ 1 + condition),
β = [1, 0.5],
);
data, events =
simulate(MersenneTwister(1), mydesign, signal, UniformOnset(; width = 10, offset = 5))
lines(data) # plotting
vlines!(my_events.latency; linestyle = :dash)
current_figure()
Looks good, but the events don't match our custom onsets yet.
Custom Timings
Finally, we want to use our custom timings as well. For this we define a new AbstractOnset. Again, it simply returns our manually provided latencies
struct MyManualOnset <: AbstractOnset end
UnfoldSim.simulate_onsets(rng, onset::MyManualOnset, simulation::Simulation) =
generate_events(rng, simulation.design).latencyThis is a bit of a trick, it relies that MyManualOnset is always used in combination with MyManualDesign. You could of course repeat the structure from MyManualDesign also for MyManualOnset and have an explicit field in the structure containing the onsets.
And that's it
data, events = simulate(MersenneTwister(1), mydesign, signal, MyManualOnset())
lines(data) # plotting
vlines!(my_events.latency, linestyle = :dash)
current_figure()
now everything matches, lovely!
This page was generated using Literate.jl.