Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions specparam/algorithms/spectral_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,15 @@ def _fit(self):

# Take an initial fit of the aperiodic component
temp_aperiodic_params = self._robust_ap_fit(self.data.freqs, self.data.power_spectrum)
temp_ap_fit = self.modes.aperiodic.func(self.data.freqs, *temp_aperiodic_params)
temp_ap_fit = self.modes.aperiodic.generate(self.data.freqs, *temp_aperiodic_params)

# Find peaks from the flattened power spectrum, and fit them
temp_spectrum_flat = self.data.power_spectrum - temp_ap_fit
self.results.params.periodic.add_params('fit', self._fit_peaks(temp_spectrum_flat))

# Calculate the peak fit
# Note: if no peaks are found, this creates a flat (all zero) peak fit
self.results.model._peak_fit = self.modes.periodic.func(\
self.results.model._peak_fit = self.modes.periodic.generate(\
self.data.freqs, *np.ndarray.flatten(self.results.params.periodic.get_params('fit')))

# Create peak-removed (but not flattened) power spectrum
Expand All @@ -178,7 +178,7 @@ def _fit(self):
# Run final aperiodic fit on peak-removed power spectrum
self.results.params.aperiodic.add_params('fit', \
self._simple_ap_fit(self.data.freqs, self.results.model._spectrum_peak_rm))
self.results.model._ap_fit = self.modes.aperiodic.func(\
self.results.model._ap_fit = self.modes.aperiodic.generate(\
self.data.freqs, *self.results.params.aperiodic.params)

# Create remaining model components: flatspec & full power_spectrum model fit
Expand Down Expand Up @@ -305,7 +305,7 @@ def _robust_ap_fit(self, freqs, power_spectrum):

# Do a quick, initial aperiodic fit
popt = self._simple_ap_fit(freqs, power_spectrum)
initial_fit = self.modes.aperiodic.func(freqs, *popt)
initial_fit = self.modes.aperiodic.generate(freqs, *popt)

# Flatten power_spectrum based on initial aperiodic fit
flatspec = power_spectrum - initial_fit
Expand Down Expand Up @@ -406,7 +406,7 @@ def _fit_peaks(self, flatspec):

# Fit and subtract guess peak from the spectrum
guess = np.vstack((guess, cur_guess))
peak_fit = self.modes.periodic.func(self.data.freqs, *cur_guess)
peak_fit = self.modes.periodic.generate(self.data.freqs, *cur_guess)
flat_iter = flat_iter - peak_fit

# Check peaks based on edges, and on overlap, dropping any that violate requirements
Expand Down
19 changes: 19 additions & 0 deletions specparam/modes/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,25 @@ def n_params(self):
return self.params.n_params


def generate(self, freqs, *params):
"""Generate component values from component function.

Parameters
----------
freqs : 1d array
Frequency values to generate component for.
*params
Parameters for the fit mode to generate with.

Returns
-------
1d array
Generated component values.
"""

return self.func(freqs, *params)


def check_params(self):
"""Check the description of the parameters for the current mode."""

Expand Down
6 changes: 2 additions & 4 deletions specparam/sim/gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ def gen_aperiodic(freqs, aperiodic_mode, aperiodic_params):
"""

ap_mode = check_mode_definition(aperiodic_mode, 'aperiodic')

ap_vals = ap_mode.func(freqs, *aperiodic_params)
ap_vals = ap_mode.generate(freqs, *aperiodic_params)

return ap_vals

Expand All @@ -84,8 +83,7 @@ def gen_periodic(freqs, periodic_mode, periodic_params):
"""

pe_mode = check_mode_definition(periodic_mode, 'periodic')

pe_vals = pe_mode.func(freqs, *check_flat(periodic_params))
pe_vals = pe_mode.generate(freqs, *check_flat(periodic_params))

return pe_vals

Expand Down
116 changes: 32 additions & 84 deletions specparam/sim/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@ def sim_power_spectrum(freq_range, aperiodic_params, periodic_params,
Frequency range to simulate power spectrum across, as [f_low, f_high], inclusive.
aperiodic_params : dict of {str : array}
Mode definition and parameters to create the aperiodic component of a power spectrum.
Should be organized as {mode : params}.
periodic_params : list of float or list of list of float
Should be organized as {mode : params}, where `mode` is a string label for a mode to
simulate with and `params` is a set of parameter values of length aperiodic_mode.n_params.
periodic_params : dict of {str : list of float or list of list of float}
Mode definition and parameters to create the periodic component of a power spectrum.
Should be organized as {mode : params}.
Should be organized as {mode : params}, where `mode` is a string label for a mode to
simulate with and `params` corresponds to the number of desired peaks, with a total number
of values matching periodic_mode.n_params * n_peaks.
This can can be a flat list (ex: [10, 1, 1, 20, 0.5, 1]) or be grouped into a
list of lists (ex: [[10, 1, 1], [20, 0.5, 1]]).
nlv : float, optional, default: 0.005
Noise level to add to generated power spectrum.
freq_res : float, optional, default: 0.5
Frequency resolution for the simulated power spectrum.
f_rotation : float, optional
Frequency value, in Hz, to rotate around.
Should only be set if spectrum is to be rotated.
Frequency value, in Hz, to rotate around. Should only be set if spectrum is to be rotated.
Can only be used with `powerlaw` aperiodic mode.
return_params : bool, optional, default: False
Whether to return the parameters for the simulated spectrum.

Expand All @@ -48,44 +53,21 @@ def sim_power_spectrum(freq_range, aperiodic_params, periodic_params,

Notes
-----
Aperiodic Parameters:

- The function for the aperiodic process to use is inferred from the provided parameters.
- If length of 2, the 'fixed' aperiodic mode is used, if length of 3, 'knee' is used.

Periodic Parameters:

- The periodic component is comprised of a set of 'peaks', each of which is described as:

* Mean (Center Frequency), height (Power), and standard deviation (Bandwidth).
* Make sure any center frequencies you request are within the simulated frequency range.

- The total number of parameters that need to be specified is number of peaks * 3

* These can be specified in as all together in a flat list (ex: [10, 1, 1, 20, 0.5, 1])
* They can also be grouped into a list of lists (ex: [[10, 1, 1], [20, 0.5, 1]])
- See `check_modes` for more information on the available modes to use to simulate,
as well as descriptions of the parameters for each mode.

Rotating Power Spectra:

- You can optionally specify a rotation frequency, such that power spectra will be
simulated and rotated around that point to the specified aperiodic exponent.
- For the powerlaw aperiodic component only, you can optionally specify a rotation frequency,
such that power spectra will be simulated and rotated around that point to the specified
aperiodic exponent. Any power spectra simulated with the same rotation frequency will relate
to each other by having the specified rotation point.

* This can be used so that any power spectra simulated with the same 'f_rotation'
will relate to each other by having the specified rotation point.

- Note that rotating power spectra changes the offset.

* If you specify an offset value to simulate as well as 'f_rotation', the returned
spectrum will NOT have the requested offset. It instead will have the offset
value required to create the requested aperiodic exponent with the requested
rotation point.
* If you return SimParams, the recorded offset will be the calculated offset
of the data post rotation, and not the entered value.

- You cannot rotate power spectra simulated with a knee.

* The procedure we use to rotate does not support spectra with a knee, and so
setting 'f_rotation' with a knee will lead to an error.
- Note that rotating power spectra changes the offset. If a simulated spectrum is rotated,
the returned spectrum will NOT have the offset of the input parameters, and will instead
have offset value required to create the given aperiodic exponent with the requested
rotation point. If you return SimParams, the recorded offset will be the calculated offset
of the data post rotation, and not the entered value.

Examples
--------
Expand Down Expand Up @@ -139,22 +121,22 @@ def sim_group_power_spectra(n_spectra, freq_range, aperiodic_params, periodic_pa
The number of power spectra to generate.
freq_range : list of [float, float]
Frequency range to simulate power spectra across, as [f_low, f_high], inclusive.
aperiodic_params : list of float or generator
Parameters for the aperiodic component of the power spectra.
aperiodic_mode : Mode or str
Which kind of aperiodic component to simulate.
periodic_params : list of float or generator
Parameters for the periodic component of the power spectra.
Length of n_peaks * 3.
periodic_mode : Mode or str
Which kind of periodic component to simulate.
aperiodic_params : dict of {str : array}
Mode definition and parameters to create the aperiodic components of the power spectra.
Should be organized as {mode : params}, where `mode` is a string label for a mode to
simulate with and `params` (array_like or generator) defines the aperiodic parameters.
periodic_params : dict of {str : list of float or list of list of float}
Mode definition and parameters to create the periodic components of the power spectras.
Should be organized as {mode : params}, where `mode` is a string label for a mode to
simulate with and `params` (array_like or generator) defines the periodic parameters.
nlvs : float or list of float or generator, optional, default: 0.005
Noise level to add to generated power spectrum.
freq_res : float, optional, default: 0.5
Frequency resolution for the simulated power spectra.
f_rotation : float, optional
Frequency value, in Hz, to rotate around.
Should only be set if spectra are to be rotated.
Frequency value, in Hz, to rotate around. Should only be set if spectrum is to be rotated.
Can only be used with `powerlaw` aperiodic mode.
See additional notes in `sim_power_spectra` on rotating simulated power spectra.
return_params : bool, optional, default: False
Whether to return the parameters for the simulated spectra.

Expand All @@ -179,40 +161,6 @@ def sim_group_power_spectra(n_spectra, freq_range, aperiodic_params, periodic_pa
- A generator object that returns parameters for a power spectrum.
If so, each spectrum has parameters sampled from the generator.

Aperiodic Parameters:

- The function for the aperiodic process to use is inferred from the provided parameters.
- If length of 2, the 'fixed' aperiodic mode is used, if length of 3, 'knee' is used.

Periodic Parameters:

- The periodic component is comprised of a set of 'peaks', each of which is described as:

* Mean (Center Frequency), height (Power), and standard deviation (Bandwidth).
* Make sure any center frequencies you request are within the simulated frequency range.

Rotating Power Spectra:

- You can optionally specify a rotation frequency, such that power spectra will be
simulated and rotated around that point to the specified aperiodic exponent.

* This can be used so that any power spectra simulated with the same 'f_rotation'
will relate to each other by having the specified rotation point.

- Note that rotating power spectra changes the offset.

* If you specify an offset value to simulate as well as 'f_rotation', the returned
spectrum will NOT have the requested offset. It instead will have the offset
value required to create the requested aperiodic exponent with the requested
rotation point.
* If you return SimParams, the recorded offset will be the calculated offset
of the data post rotation, and not the entered value.

- You cannot rotate power spectra simulated with a knee.

* The procedure we use to rotate does not support spectra with a knee, and so
setting 'f_rotation' with a knee will lead to an error.

Examples
--------
Generate 2 power spectra using the same parameters:
Expand Down
11 changes: 11 additions & 0 deletions specparam/tests/modes/test_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

from collections import OrderedDict

import numpy as np

from specparam.modes.params import ParamDefinition
from specparam.modes.definitions import ap_powerlaw

from specparam.modes.mode import *

Expand Down Expand Up @@ -41,3 +44,11 @@ def tfit2(xs, *params):
ndim=2, freq_space='linear', powers_space='linear')
assert tmode
assert isinstance(tmode.params, ParamDefinition)

def test_mode_generate():

freqs = np.linspace(1, 40, 40)
params = [1, 1]

output = ap_powerlaw.generate(freqs, *params)
assert isinstance(output, np.ndarray)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test functions for specparam.sim.utils."""
"""Test functions for specparam.utils.random"""

from specparam.sim.utils import *
from specparam.utils.random import *

###################################################################################################
###################################################################################################
Expand Down
2 changes: 1 addition & 1 deletion specparam/sim/utils.py → specparam/utils/random.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Utilities related to simulations."""
"""Utilities related to managing randomness."""

import numpy as np

Expand Down
Loading