Skip to content
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

[ENH] - Add functionality for managing sim params and simulating multiple signals together #329

Merged
merged 47 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bbac0b4
add sim_combined_peak
TomDonoghue Apr 13, 2024
6df1cfa
add counter util
TomDonoghue Apr 13, 2024
03fc40b
add new udpate funcs
TomDonoghue Apr 13, 2024
2168f01
add multi sim funcs
TomDonoghue Apr 13, 2024
693769c
cleans / lints
TomDonoghue Apr 14, 2024
b26598d
minor tutorial fixes
TomDonoghue Apr 14, 2024
3702f27
sim/objs -> sim/params
TomDonoghue Apr 14, 2024
1ccfba7
use objs instead of wrappers
TomDonoghue Apr 14, 2024
36ba785
drop wrapper funcs (offer no new functionality)
TomDonoghue Apr 14, 2024
a2f2307
allow pass through of SimParams in derived objs
TomDonoghue Apr 14, 2024
3cea869
add sim params tutorial
TomDonoghue Apr 14, 2024
74d65f0
add sim multi tutorial
TomDonoghue Apr 14, 2024
5f6c349
add new sim things to API list
TomDonoghue Apr 14, 2024
de8e269
udpate docstrings
TomDonoghue Apr 14, 2024
8a8a09a
fix object initialization
TomDonoghue Apr 14, 2024
d36656c
add docstring examples
TomDonoghue Jul 19, 2024
2c7c371
Merge branch 'main' into simp
TomDonoghue Jul 19, 2024
ec90e54
udpate API list for new functionaloity
TomDonoghue Jul 19, 2024
09f137c
fix up docs & details of sig_sampler
TomDonoghue Jul 19, 2024
4b55936
add SimParams to_* methods
TomDonoghue Jul 20, 2024
6cfae41
drop allowing SimParams object into init of derived obks
TomDonoghue Jul 20, 2024
e24a0a9
add copy method
TomDonoghue Aug 17, 2024
b27848d
add new conftest objects for sim params
TomDonoghue Aug 17, 2024
12d4c6d
extend tests for sim params
TomDonoghue Aug 17, 2024
e2770f5
add docstring examples
TomDonoghue Aug 17, 2024
ce3b1f8
minor lints
TomDonoghue Aug 17, 2024
cd45e0f
add ParamIter as doc'd input to sim_multi
TomDonoghue Aug 17, 2024
260188f
add drop_base_params helper func
TomDonoghue Aug 19, 2024
d7b3450
add Simulations object
TomDonoghue Aug 19, 2024
1de2b4c
move drop_base_params func (circ import)
TomDonoghue Aug 19, 2024
cc3d76b
use sims object in sim_multiple
TomDonoghue Aug 19, 2024
9406855
add SampledSims object
TomDonoghue Aug 19, 2024
e9534a1
use SampledSims object in sim multi
TomDonoghue Aug 25, 2024
fbddfe3
add get_base_params helper
TomDonoghue Aug 28, 2024
eab6301
rework details of sims obejcts
TomDonoghue Aug 28, 2024
91e31d8
add/move listify helper func
TomDonoghue Aug 28, 2024
0f6c16b
extend tests & associated updates / fixes
TomDonoghue Aug 28, 2024
62e7938
add MultiSims object
TomDonoghue Aug 28, 2024
277a569
updates to sims objs
TomDonoghue Aug 29, 2024
68a6a6f
use object for sim_multi
TomDonoghue Aug 29, 2024
3a629da
sim/sims - sim/signals
TomDonoghue Aug 29, 2024
7792e7e
order sim tutorials
TomDonoghue Aug 29, 2024
da362f7
update tutorials for sim signal objects
TomDonoghue Aug 29, 2024
c56a1dc
allow for callable to be pased for sim_func
TomDonoghue Aug 29, 2024
1afb821
Merge branch 'main' into simp
TomDonoghue Sep 1, 2024
33c8c47
update sim init
TomDonoghue Sep 1, 2024
97ca7b2
Merge branch 'main' into simp
TomDonoghue Sep 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,31 @@ Combined Signals

sim_combined
sim_peak_oscillation
sim_combined_peak
sim_modulated_signal

Multiple Signals
~~~~~~~~~~~~~~~~

.. currentmodule:: neurodsp.sim.multi
.. autosummary::
:toctree: generated/

sim_multiple
sim_across_values
sim_from_sampler

Simulation Parameters
~~~~~~~~~~~~~~~~~~~~~

.. currentmodule:: neurodsp.sim.params
.. autosummary::
:toctree: generated/

SimParams
SimIters
SimSamplers

Utilities
~~~~~~~~~

Expand Down
32 changes: 32 additions & 0 deletions neurodsp/sim/combined.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,38 @@ def sim_peak_oscillation(sig_ap, fs, freq, bw, height):
return sig


@normalize
def sim_combined_peak(n_seconds, fs, components):
"""Simulate a combined signal with an aperiodic component and a peak.

Parameters
----------
n_seconds : float
Simulation time, in seconds.
fs : float
Sampling rate of simulated signal, in Hz.
components : dict
A dictionary of simulation functions to run, with their desired parameters.

Returns
-------
sig : 1d array
Simulated combined peak signal.
"""

sim_names = list(components.keys())
assert len(sim_names) == 2, 'Expected only 2 components.'
assert sim_names[1] == 'sim_peak_oscillation', \
'Expected `sim_peak_oscillation` as the second key.'

ap_func = get_sim_func(sim_names[0]) if isinstance(sim_names[0], str) else sim_names[0]

sig = sim_peak_oscillation(\
ap_func(n_seconds, fs, **components[sim_names[0]]), fs, **components[sim_names[1]])

return sig


@normalize
def sim_modulated_signal(n_seconds, fs, sig_func, sig_params, mod_func, mod_params):
"""Simulate an amplitude modulated signal.
Expand Down
166 changes: 166 additions & 0 deletions neurodsp/sim/multi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
"""Simulation functions that return multiple instances."""

import numpy as np

from neurodsp.utils.core import counter

###################################################################################################
###################################################################################################

def sig_yielder(sim_func, sim_params, n_sims):
"""Generator to yield simulated signals from a given simulation function and parameters.

Parameters
----------
sim_func : callable
Function to create the simulated time series.
sim_params : dict
The parameters for the simulated signal, passed into `sim_func`.
n_sims : int, optional
Number of simulations to set as the max.
If None, creates an infinite generator.

Yields
------
sig : 1d array
Simulated time series.
"""

for _ in counter(n_sims):
yield sim_func(**sim_params)


def sig_sampler(sim_func, sim_params, return_sim_params=False, n_sims=None):
"""Generator to yield simulated signals from a parameter sampler.

Parameters
----------
sim_func : callable
Function to create the simulated time series.
sim_params : iterable
The parameters for the simulated signal, passed into `sim_func`.
return_sim_params : bool, optional, default: False
Whether to yield the simulation parameters as well as the simulated time series.
n_sims : int, optional
Number of simulations to set as the max.
If None, creates an infinite generator.

Yields
------
sig : 1d array
Simulated time series.
sample_params : dict
Simulation parameters for the yielded time series.
"""

if len(sim_params) and n_sims and n_sims > len(sim_params):
msg = 'Cannot simulate the requested number of sims with the given parameters.'
raise ValueError(msg)

for ind, sample_params in zip(counter(n_sims), sim_params):

if return_sim_params:
yield sim_func(**sample_params), sample_params
else:
yield sim_func(**sample_params)

if n_sims and ind >= n_sims:
break


def sim_multiple(sim_func, sim_params, n_sims):
"""Simulate multiple samples of a specified simulation.

Parameters
----------
sim_func : callable
Function to create the simulated time series.
sim_params : dict
The parameters for the simulated signal, passed into `sim_func`.
n_sims : int
Number of simulations to create.

Returns
-------
sigs : 2d array
Simulations, as [n_sims, sig length].
"""

sigs = np.zeros([n_sims, sim_params['n_seconds'] * sim_params['fs']])
for ind, sig in enumerate(sig_yielder(sim_func, sim_params, n_sims)):
sigs[ind, :] = sig

return sigs


def sim_across_values(sim_func, sim_params, n_sims, output='dict'):
"""Simulate multiple signals across different parameter values.

Parameters
----------
sim_func : callable
Function to create the simulated time series.
sim_params : iterable or list of dict
Simulation parameters for `sim_func`.
n_sims : int
Number of simulations to create per parameter definition.
output : {'dict', 'array'}
Organization of the output for the sims.
If 'dict', stored in a dictionary, organized by simulation parameter.
If 'array', all sims are organized into a 2D array.

Returns
-------
sims : dict of {float : array} or array
If dict, dictionary of simulated signals, where:
Each key is the simulation parameter value for the set of simulations.
Each value is the set of simulations for that value, as [n_sims, sig_length].
If array, is all signals collected together as [n_sims, sig_length].
"""

sims = {}
for ind, cur_sim_params in enumerate(sim_params):
label = sim_params.values[ind] if hasattr(sim_params, 'values') else ind
label = label[-1] if isinstance(label, list) else label
sims[label] = sim_multiple(sim_func, cur_sim_params, n_sims)
if output == 'array':
sims = np.squeeze(np.array(list(sims.values())))

return sims


def sim_from_sampler(sim_func, sim_sampler, n_sims, return_params=False):
"""Simulate a set of signals from a parameter sampler.

Parameters
----------
sim_func : callable
Function to create the simulated time series.
sim_sampler : ParamSampler
Parameter definition to sample from.
n_sims : int
Number of simulations to create per parameter definition.
return_params : bool, default: False
Whether to collect and return the parameters of all the generated simulations.

Returns
-------
sigs : 2d array
Simulations, as [n_sims, sig length].
all_params : list of dict
Simulation parameters for each returned time series.
Only returned if `return_params` is True.
"""

all_params = [None] * n_sims
sigs = np.zeros([n_sims, sim_sampler.params['n_seconds'] * sim_sampler.params['fs']])
for ind, (sig, params) in enumerate(sig_sampler(sim_func, sim_sampler, True, n_sims)):
sigs[ind, :] = sig

if return_params:
all_params[ind] = params

if return_params:
return sigs, all_params
else:
return sigs
Loading
Loading