# Forward modelling EEG from simulated sources

**URL:** <https://mne.discourse.group/t/forward-modelling-eeg-from-simulated-sources/11652>\
**Category:** Support & Discussions\
**Created:** [January 9, 2026, 4:07pm UTC](https://mne.discourse.group/t/forward-modelling-eeg-from-simulated-sources/11652 "2026-01-09T16:07:38Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dominik](https://avatars.discourse-cdn.com/v4/letter/d/ee7513/32.png) [@Dominik](https://mne.discourse.group/u/Dominik)\
**Post date:** [January 9, 2026, 4:07pm UTC](https://mne.discourse.group/t/forward-modelling-eeg-from-simulated-sources/11652/1 "2026-01-09T16:07:38Z")

</div>

Hi all,

I want to forwad model EEG data from simulated source activity. I have two questions

1. My intuition would be to average-reference the simulated EEG but [in your tutorial](https://mne.tools/stable/auto_examples/simulation/simulated_raw_data_using_subject_anatomy.html) you apply set\_eeg\_reference(projection=True), which I believe makes the simulated EEG reference-free. Is there a particular reason why you’d do that?
2. My simulation has 1000 cortical regions. So far, I have assigned the same simulated cortical activity to several sources per region and fixed the dipole orientation. Testing this looks fine but the simulate\_raw() function takes ages, which makes me wonder if there’s a good way to reduce my source space to 1000 simulated regions/sources?

This is how I prepare the forward model:

```python
# Download fsaverage files
fs_dir = Path(mne.datasets.fetch_fsaverage(verbose=True))

trans = "fsaverage"
src = fs_dir / "bem" / "fsaverage-ico-5-src.fif"
bem = fs_dir / "bem" / "fsaverage-5120-5120-5120-bem-sol.fif"

# get the montage 
easycap_montage = mne.channels.make_standard_montage("easycap-M1")

# Create info of EEG data
info = mne.create_info(easycap_montage.ch_names, sfreq=sfreq, ch_types='eeg')
info.set_montage(easycap_montage)

# Get regions from parcellation
subject_path = os.path.join(project_root, derivatives_path, 'structural_connectivity/Schaefer1000')             

regions = np.array(mne.read_labels_from_annot('fsaverage', 'Schaefer2018_1000Parcels_17Networks_order', 'both', surf_name='pial', subjects_dir=subject_path, sort=False))
regions = list(regions[["background" not in r.name.lower() for r in regions]]) # remove background

# Create forward model
fwd = mne.make_forward_solution(info, trans=trans, src=src, bem=bem, eeg=True, n_jobs=None)

fwd = mne.forward.restrict_forward_to_label(fwd, regions)

mne.write_forward_solution(os.path.join(project_root, fwd_path), fwd, overwrite=True)

```

This is how I use it for the simulations:

```python
# Get montage
easycap_montage = mne.channels.make_standard_montage(montage)

# Create info for simulated EEG data
info = mne.create_info(easycap_montage.ch_names, sfreq=sfreq, ch_types='eeg')
info.set_montage(easycap_montage)

# Prepare forward model
fwd = mne.read_forward_solution(fwd_path)
fwd = mne.convert_forward_solution(fwd, force_fixed=True, surf_ori=True, use_cps=True)

subject_path = os.path.join(project_root, derivatives_path, 'structural_connectivity/Schaefer1000')             

regions = np.array(mne.read_labels_from_annot('fsaverage', 'Schaefer2018_1000Parcels_17Networks_order', 'both', surf_name='pial', subjects_dir=subject_path, sort=False))
regions = list(regions[["background" not in r.name.lower() for r in regions]]) # remove medial wall

# Prepare source space
src_space = fwd['src']

# Assign simulations to source space
source_simulator = mne.simulation.SourceSimulator(src_space, tstep=time_step_in_seconds)
events = np.array([[0, 0, 1]]) 

for i, s in enumerate(regions):
    source_simulator.add_data(s, simulated_lfp[i], events)

# Simulate raw EEG
info["dev_head_t"] = fwd["info"]["dev_head_t"] # throws error if they don't match
raw = mne.simulation.simulate_raw(info, source_simulator, forward=fwd, n_jobs=1)
raw.set_eeg_reference(projection=True)

```

Thanks for your help!

Setup  
MNE 1.11.0  
MacOS 15.6
