-
Notifications
You must be signed in to change notification settings - Fork 7
trf #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4.0
Are you sure you want to change the base?
trf #107
Changes from all commits
59f5364
5726ec2
4f93a54
26ad7fb
8ea515b
73425fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,81 @@ | ||||||||||||||||||||||||
| using UnfoldSim | ||||||||||||||||||||||||
| using CairoMakie | ||||||||||||||||||||||||
| using Random | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # # Temporal response functions | ||||||||||||||||||||||||
| # So far, we simulated event-related potentials. In this tutorial, we will switch gears a bit, and simulate a continuous response to a continuous feature vector. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # One good example is the visual response to a grayscale circle, which continuously changes its luminance (this goes back to VESPA, described in the ground breaking [Lalor 2006 paper](https://doi.org/10.1016/j.neuroimage.2006.05.054). The brain will react to this luminance change continuously. TRFs typically describe the process to recover the brain response (in terms of a filter response). Here we set out to simulate such a dataset first and foremost. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # ## Simulation | ||||||||||||||||||||||||
| # we start with the simplest possible design, one condition | ||||||||||||||||||||||||
| design = SingleSubjectDesign(conditions=Dict(:dummy=>["A"])); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # next we define the convolution kernel that the feature signal should be convolved with (= the brain response == the TRF) | ||||||||||||||||||||||||
| brain_response = [LinearModelComponent(basis=p100(),formula=@formula(0~1),β=[1]), | ||||||||||||||||||||||||
| LinearModelComponent(basis=n170(),formula=@formula(0~1),β=[1]), | ||||||||||||||||||||||||
| LinearModelComponent(basis=p300(),formula=@formula(0~1),β=[1])]; | ||||||||||||||||||||||||
|
Comment on lines
+15
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # !!! hint | ||||||||||||||||||||||||
| # For a fancy way to write the above code, you could use `LinearModelComponent.([p100,n170,p300],@formula(0~1),Ref([1]))`, notice the `.(...)` indicating broadcasting | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Now we can simulate our feature signal, 10_000 samples of random gray scale values | ||||||||||||||||||||||||
| feature = rand(1_000) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Next we have to nest the response in a `TRFComponent` and add ou | ||||||||||||||||||||||||
| trf_component = TRFComponent(brain_response,feature); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Finally, when simulating, we have only a single "event" (that is, TRF-) onset, the first sample. Therefore, we use `TRFOnset` to indicate this. | ||||||||||||||||||||||||
| dat,evts = simulate(design,trf_component,UnfoldSim.TRFOnset()); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Let's plot the feature signal and the TRF response | ||||||||||||||||||||||||
| f,ax,h =lines(dat) | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
| lines!(feature) | ||||||||||||||||||||||||
| f | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # ## Multivariate TRFs | ||||||||||||||||||||||||
| # Now TRFs can depend on multiple variables e.g. the luminance and the size of the circle. | ||||||||||||||||||||||||
| feature_luminance = rand(1_000) | ||||||||||||||||||||||||
| feature_size = rand(1_000) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # We could call the `simulate` function twice and simply add the results: | ||||||||||||||||||||||||
| dat_l,_ = simulate(design,TRFComponent(brain_response,feature_luminance),UnfoldSim.TRFOnset()); | ||||||||||||||||||||||||
| dat_r,_ = simulate(design,TRFComponent(brain_response,feature_size),UnfoldSim.TRFOnset()); | ||||||||||||||||||||||||
|
Comment on lines
+42
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # let's plot and compare to the previous plot | ||||||||||||||||||||||||
| f,ax,h = lines(dat_l .+ dat_r) | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
| lines!(dat) | ||||||||||||||||||||||||
| f | ||||||||||||||||||||||||
| # as visible, the blue line (luminance+size) has ~double the amplitude. This is because we simulated two brain responses and simply added them. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # A bit more convenient way is to do the following | ||||||||||||||||||||||||
| dat_combined,_ = simulate(design,[TRFComponent(brain_response,feature_size),TRFComponent(brain_response,feature_luminance)],UnfoldSim.TRFOnset()); | ||||||||||||||||||||||||
| f,ax,h = lines(dat_combined) | ||||||||||||||||||||||||
|
Comment on lines
+52
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
| lines!(dat_l .+ dat_r) | ||||||||||||||||||||||||
| f | ||||||||||||||||||||||||
| # where you can see that the results are equivalent. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # ## Another cool feature is to modulate the feature vector based on the design | ||||||||||||||||||||||||
| design_mod = SingleSubjectDesign(conditions=Dict(:condition=>["A","B"])); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Let's take only a single component for simplicity. Note how the `formula` has been changed. The β allows to control the amplitude. In this linear model component, the default contrast-function is `Dummy` (also known as `Reference` coding), which means, the second beta indicated a "difference" | ||||||||||||||||||||||||
| brain_response_mod = LinearModelComponent(basis=p100(),formula=@formula(0~1+condition),β=[1,1]); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # let's simulate another feature signal, but this time, we simulate a Matrix. | ||||||||||||||||||||||||
| feature_mod = rand(1000,2) | ||||||||||||||||||||||||
| feature_mod[:,2] .= 0 | ||||||||||||||||||||||||
| feature_mod[500:600,2] .= 1; | ||||||||||||||||||||||||
|
Comment on lines
+65
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # to better understand how our (experimental) feature now looks like, let's visualize it | ||||||||||||||||||||||||
| series(feature_mod') | ||||||||||||||||||||||||
| # As visible, the first column has again a random signal, indicating e.g. luminance changes. The second temporal feature indicates some offset (a colorchange?) between 500 and 600 samples. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| dat_mod,_ = simulate(design_mod,TRFComponent([brain_response_mod],feature_mod),UnfoldSim.TRFOnset()); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||
| lines(dat_mod) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # !!! hint | ||||||||||||||||||||||||
| # Excourse: now you rightfully might ask why the jump is to >10 a.u.? The reason is that you are effectively convolving a feature-signal above 1 (feature_mod * (β_0 + β_1) = 1 * (1+1)), and with a kernel with maximum = 1, these 2's add up. The kernel has a rough width of ~5 which results in additional 5*2 => 10 per affected sample | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # ## Combination with a event-related design | ||||||||||||||||||||||||
| # Right now there is no easy interface to do this. You have to simulate a TRF signal, and an rERP signal and then add the two signals. | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -35,6 +35,15 @@ In the case that the user directly wants no overlap to be simulated (=> epoched | |||||||||||
| """ | ||||||||||||
| struct NoOnset <: AbstractOnset end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| """ | ||||||||||||
| struct TRFOnset <: AbstractOnset end | ||||||||||||
| In the case that a TRF is simulated (via `TRFComponent`). This onset returns a vector of zero-latencies, indicating that the TRF starts at the beginning of the signal. | ||||||||||||
| """ | ||||||||||||
| struct TRFOnset <: AbstractOnset end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| """ | ||||||||||||
| simulate_interonset_distances(rng, onset::UniformOnset, design::AbstractDesign) | ||||||||||||
| simulate_interonset_distances(rng, onset::LogNormalOnset, design::AbstractDesign) | ||||||||||||
|
|
@@ -59,6 +68,16 @@ function simulate_interonset_distances(rng, onset::LogNormalOnset, design::Abstr | |||||||||||
| end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| """ | ||||||||||||
| simulate_interonset_distances(rng, onset::UniformOnset, design::AbstractDesign) | ||||||||||||
| In the case that a TRF is simulated (via `TRFComponent`). This onset returns a vector of zero-latencies, indicating that the TRF starts at the beginning of the signal. | ||||||||||||
| """ | ||||||||||||
| function simulate_interonset_distances(rng, onset::TRFOnset, design) | ||||||||||||
| sz = size(design) | ||||||||||||
| return Int.(zeros(sz)) | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| #function simulate_interonset_distances(rng, onset::AbstractOnset,design::) | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
@@ -135,10 +154,10 @@ end | |||||||||||
| function simulate_interonset_distances(rng, o::UniformOnsetFormula, design::AbstractDesign) | ||||||||||||
| events = generate_events(design) | ||||||||||||
| widths = | ||||||||||||
| UnfoldSim.generate_designmatrix(o.width_formula, events, o.width_contrasts) * | ||||||||||||
| generate_designmatrix(o.width_formula, events, o.width_contrasts) * | ||||||||||||
| o.width_β | ||||||||||||
|
Comment on lines
156
to
158
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||
| offsets = | ||||||||||||
| UnfoldSim.generate_designmatrix(o.offset_formula, events, o.offset_contrasts) * | ||||||||||||
| generate_designmatrix(o.offset_formula, events, o.offset_contrasts) * | ||||||||||||
| o.offset_β | ||||||||||||
|
Comment on lines
+160
to
161
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||
|
|
||||||||||||
| return Int.( | ||||||||||||
|
|
@@ -193,10 +212,10 @@ function simulate_interonset_distances( | |||||||||||
| events = generate_events(design) | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| μs = UnfoldSim.generate_designmatrix(o.μ_formula, events, o.μ_contrasts) * o.μ_β | ||||||||||||
| σs = UnfoldSim.generate_designmatrix(o.σ_formula, events, o.σ_contrasts) * o.σ_β | ||||||||||||
| μs = generate_designmatrix(o.μ_formula, events, o.μ_contrasts) * o.μ_β | ||||||||||||
| σs = generate_designmatrix(o.σ_formula, events, o.σ_contrasts) * o.σ_β | ||||||||||||
| offsets = | ||||||||||||
| UnfoldSim.generate_designmatrix(o.offset_formula, events, o.offset_contrasts) * | ||||||||||||
| generate_designmatrix(o.offset_formula, events, o.offset_contrasts) * | ||||||||||||
| o.offset_β | ||||||||||||
|
Comment on lines
+218
to
219
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶