lrkrol / SEREEGA

SEREEGA: Simulating Event-Related EEG Activity
64 stars 17 forks source link

My simulated data signals look alike across different channels #7

Closed Ojayedwards closed 4 years ago

Ojayedwards commented 5 years ago

I am trying to simulate EEG data from the channels around the prefrontal cortex... F3, F4, FC5, FC6, AF1, AF3, F7 and F8.. I just noticed that the channels F3, FC5, AF3 and F7 generated signals that look alike having the same peak... Likewise the other channels generated another similar wave... I don't know what I did wrong cos m new to EEG and I don't understand because I don't expect d generated signals to be like that... Please what can I do to get a realistic simulated data.. And my data doesn't have channel locations when I used it on eeglab

lrkrol commented 5 years ago

In general, due to volume conduction, electrical activity generated in one location in the brain automatically and immediately spreads to all electrodes at once.

Let's for example take a look at a source more or less in the middle of the brain, pointing upwards:

lf = lf_generate_fromnyhead();
plot_source_location(lf_get_source_nearest(lf, [0 0 0]), lf);
plot_source_projection(lf_get_source_nearest(lf, [0 0 0]), lf, 'orientation', [0 0 1], 'orientedonly', 1);

image

The projection pattern shows how any "peak" generated in this source is represented on the scalp. As you can see, the activity ends up everywhere, at every channel, just at different amplitudes -- including inversed amplitudes, due to the source's dipolar nature.

The reason why real EEG doesn't look alike on every channel is because there are many different sources active at the same time, all of which spread their activity to all channels at once, but with different projection patterns; therefore, the signals interfere with each other differently on every channel, and you end up with unique activations on every channel. (Although there will still be similarities between neighbouring channels.)

You probably didn't have enough (different) sources in your simulation yet.

As for not having channel locations: if you use utl_create_eeglabdataset, an EEGLAB dataset is created that uses the channel locations from the lead field. If you did use that function, please open a separate issue and post sample code so I can look into what happened.

Ojayedwards commented 5 years ago

Thanks... The channel location worked now... Please help me look into my code for the simulation... The source locations I added didn't seem to work

%{ simulating beta wave activity (12-30) from the following electrodes, %}

epochs = struct(); epochs.n = 100; epochs.srate = 1000; epochs.length = 1000; epochs.marker = 'event 1'; epochs.prestim = 0;

lf = lf_generate_fromnyhead('labels', {'AF3', 'AF4', 'F3', 'F4', 'F7', 'F8', 'FC6', 'FC5', 'Fp1', 'Fp2', 'Fz'});

% i dont know any other way to add more than one source location, so! for i = 1:8 source = source(i); source(1) = lf_get_source_nearest(lf, [-48 26 4]); source(2) = lf_get_source_nearest(lf, [-38 28 38]); source(3) = lf_get_source_nearest(lf, [48 24 -8]); source(4) = lf_get_source_nearest(lf, [24 60 0]); source(5) = lf_get_source_nearest(lf, [4 62 0]); source(6) = lf_get_source_nearest(lf, [2 32 54]); source(7) = lf_get_source_nearest(lf, [-18 62 0]); source(8) = lf_get_source_nearest(lf, [42 30 34]); end

erp = struct(); erp.peakLatency = 300; erp.peakWidth = 100; erp.peakAmplitude = .7; erp = utl_check_class(erp, 'type', 'erp'); erp.peakLatencyDv = 50; erp.peakAmplitudeDv = .2; erp.peakAmplitudeSlope = -.55;

noise = struct( ... 'type', 'noise', ... 'color', 'brown', ... 'amplitude', 1); noise = utl_check_class(noise);

ersp = struct( ... 'type', 'ersp', ... 'frequency', [12 15 27 30], ... 'amplitude', .25); ersp.modulation = 'burst'; ersp.modLatency = 300; % ersp.modWidth = 80; ersp.modTaper = 0.5; ersp = utl_check_class(ersp);

c = struct(); c.source = source;

c.signal = {erp, noise}; c = utl_check_component(c, lf); scalpdata = generate_scalpdata(c, lf, epochs); c.signal = {erp, ersp, noise}; EEG = utl_create_eeglabdataset(generate_scalpdata(c, lf, epochs), ... epochs, lf); pop_eegplot(EEG, 1, 1, 1); pop_saveset(EEG); %{ TRIED USING THE GUI TO ADD ERP, NOISE AND ERSP.... BUT IT DOESNT %TAKE THE ERSP.. It gives me the error below Output argument "isvalidcomponent" (and maybe others) not assigned during call to "utl_isvalidcomponent".

Error in utl_isvalidcomponent (line 40) isvalidcomponent(i) = utl_isvalidcomponent(c(i), leadfield);

Error in pop_sereega_components (line 200) valid = utl_isvalidcomponent(EEG.etc.sereega.components, EEG.etc.sereega.leadfield);

Error while evaluating Menu Callback %}

lrkrol commented 5 years ago

I can find a few things in that code you may want to have a look at.

First of all, I had to remove the line source = source(i); to end up with source being a 1-by-8 array of source indices which I assume you were looking for. lf_get_source_inradius, lf_get_source_random, and lf_get_source_spaced, are other ways to obtain (multiple) sources from a lead field.

Next, the creation of components from source indices requires some attention. The first component c you create is:

c = 
  struct with fields:
           source: [7536 13563 45997 59042 72809 72532 24694 47912]
           signal: {[1×1 struct]  [1×1 struct]}
      orientation: [8×3 double]
    orientationDv: [8×3 double]

As you can see, this is one component (1x1 struct) with eight source indices. When SEREEGA simulates data, it once simulates each component for each epoch. Since you only have one component, this is the only thing it simulates. What SEREEGA does with one single component having multiple sources, is take one randomly selected source for each epoch. As we saw above, one single source affects all electrodes and receives no further interference. Therefore, all electrodes will show the same activity, just scaled differently.

What you wanted is not one component with eight sources, but eight components with one source each.

Have a look at the utl_create_component function. Using that, you can e.g. get:

>> utl_create_component(source, noise, lf)
ans = 
  1×8 struct array with fields:
    source
    signal
    orientation
    orientationDv

As you can see, this created eight different components, each with the noise signal. The ERP and ERSP you probably each wanted to add to only one of these components. You can do this manually by simply adding it to the signal field of the component, or use utl_add_signal_tocomponent.

Then, you will have eight different components, all of which emit noise, one of which also emits an ERP, and one of which also emits an ERSP. That should be what you intended.

Finally, your code once simulates scalpdata without the ERSP and then doesn't do anything with it, but I assume you're aware of that.

SEREEGA supports both scripting and a (limited) GUI workflow, but they are difficult to combine. In the GUI, you start with an empty EEG dataset, and the GUI functions save all your information in that dataset. Since you started with a script, these GUI functions can't find the information, and thus don't work. The other way around of course does work (GUI -> script instead of script -> GUI).