Skip to content

Commit 1a237f4

Browse files
authored
Merge pull request #130 from fooof-tools/set_avg
Update data objects and some settings handling
2 parents 3b7abb6 + 4bc5e10 commit 1a237f4

19 files changed

+532
-348
lines changed

fooof/core/info.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""Internal functions to manage info related to FOOOF objects."""
2+
3+
def get_obj_desc():
4+
"""Get dictionary specifying FOOOF object names and kind of attributes.
5+
6+
Returns
7+
-------
8+
attibutes : dict
9+
Mapping of FOOOF object attributes, and what kind of data they are.
10+
"""
11+
12+
attributes = {'results' : ['aperiodic_params_', 'peak_params_',
13+
'r_squared_', 'error_',
14+
'_gaussian_params'],
15+
'settings' : ['peak_width_limits', 'max_n_peaks',
16+
'min_peak_amplitude', 'peak_threshold',
17+
'aperiodic_mode'],
18+
'data' : ['power_spectrum', 'freq_range', 'freq_res'],
19+
'data_info' : ['freq_range', 'freq_res'],
20+
'arrays' : ['freqs', 'power_spectrum', 'aperiodic_params_',
21+
'peak_params_', '_gaussian_params'],
22+
'model_components' : ['_spectrum_flat', '_spectrum_peak_rm',
23+
'_ap_fit', '_peak_fit']}
24+
25+
return attributes
26+
27+
28+
def get_data_indices(aperiodic_mode):
29+
"""Get a dictionary mapping the column labels to indices in FOOOF data (FOOOFResults).
30+
31+
Parameters
32+
----------
33+
aperiodic_mode : {'fixed', 'knee'}
34+
Which approach taken to fit the aperiodic component.
35+
36+
Returns
37+
-------
38+
indices : dict
39+
Mapping for data columns to the column indices in which they appear.
40+
"""
41+
42+
indices = {
43+
'CF' : 0,
44+
'Amp' : 1,
45+
'BW' : 2,
46+
'offset' : 0,
47+
'knee' : 1 if aperiodic_mode == 'knee' else None,
48+
'exponent' : 1 if aperiodic_mode == 'fixed' else 2
49+
}
50+
51+
return indices

fooof/core/io.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import json
66
from json import JSONDecodeError
77

8-
from fooof.core.utils import dict_array_to_lst, dict_select_keys, dict_lst_to_array, get_obj_desc
8+
from fooof.core.info import get_obj_desc
9+
from fooof.core.utils import dict_array_to_lst, dict_select_keys, dict_lst_to_array
910

1011
###################################################################################################
1112
###################################################################################################
@@ -89,7 +90,7 @@ def save_fm(fm, file_name, file_path=None, append=False,
8990
# Set and select which variables to keep. Use a set to drop any potential overlap
9091
# Note that results also saves frequency information to be able to recreate freq vector
9192
attributes = get_obj_desc()
92-
keep = set((attributes['results'] + attributes['freq_info'] if save_results else []) + \
93+
keep = set((attributes['results'] + attributes['data_info'] if save_results else []) + \
9394
(attributes['settings'] if save_settings else []) + \
9495
(attributes['data'] if save_data else []))
9596
obj_dict = dict_select_keys(obj_dict, keep)

fooof/core/strings.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def gen_wid_warn_str(freq_res, bwl):
2727

2828
output = '\n'.join([
2929
'',
30-
"FOOOF WARNING: Lower-bound peak width limit is < or ~= the frequency resolution: " + \
31-
"{:1.2f} <= {:1.2f}".format(freq_res, bwl),
30+
'FOOOF WARNING: Lower-bound peak width limit is < or ~= the frequency resolution: ' + \
31+
'{:1.2f} <= {:1.2f}'.format(freq_res, bwl),
3232
'\tLower bounds below frequency-resolution have no effect (effective lower bound is freq-res)',
3333
'\tToo low a limit may lead to overfitting noise as small bandwidth peaks.',
3434
'\tWe recommend a lower bound of approximately 2x the frequency resolution.',
@@ -57,11 +57,11 @@ def gen_settings_str(f_obj, description=False, concise=False):
5757
"""
5858

5959
# Parameter descriptions to print out, if requested
60-
desc = {'aperiodic_mode' : 'The aproach taken to fitting the aperiodic component.',
61-
'peak_width_limits' : 'Enforced limits for peak widths, in Hz.',
60+
desc = {'peak_width_limits' : 'Enforced limits for peak widths, in Hz.',
6261
'max_n_peaks' : 'The maximum number of peaks that can be extracted.',
63-
'min_peak_amplitude' : "Minimum absolute amplitude of a peak, above aperiodic component.",
64-
'peak_threshold' : "Threshold at which to stop searching for peaks."}
62+
'min_peak_amplitude' : 'Minimum absolute amplitude of a peak, above aperiodic component.',
63+
'peak_threshold' : 'Threshold at which to stop searching for peaks.',
64+
'aperiodic_mode' : 'The aproach taken to fitting the aperiodic component.'}
6565

6666
# Clear description for printing if not requested
6767
if not description:
@@ -77,16 +77,16 @@ def gen_settings_str(f_obj, description=False, concise=False):
7777
'',
7878

7979
# Settings - include descriptions if requested
80-
*[el for el in ['Aperiodic Mode : {}'.format(f_obj.aperiodic_mode),
81-
'{}'.format(desc['aperiodic_mode']),
82-
'Peak Width Limits : {}'.format(f_obj.peak_width_limits),
80+
*[el for el in ['Peak Width Limits : {}'.format(f_obj.peak_width_limits),
8381
'{}'.format(desc['peak_width_limits']),
8482
'Max Number of Peaks : {}'.format(f_obj.max_n_peaks),
8583
'{}'.format(desc['max_n_peaks']),
8684
'Minimum Amplitude : {}'.format(f_obj.min_peak_amplitude),
8785
'{}'.format(desc['min_peak_amplitude']),
8886
'Amplitude Threshold: {}'.format(f_obj.peak_threshold),
89-
'{}'.format(desc['peak_threshold'])] if el != ''],
87+
'{}'.format(desc['peak_threshold']),
88+
'Aperiodic Mode : {}'.format(f_obj.aperiodic_mode),
89+
'{}'.format(desc['aperiodic_mode'])] if el != ''],
9090

9191
# Footer
9292
'',
@@ -280,7 +280,7 @@ def gen_issue_str(concise=False):
280280
'If FOOOF gives you any weird / bad fits, please let us know!',
281281
'To do so, send us a FOOOF report, and a FOOOF data file, ',
282282
'',
283-
"With a FOOOF object (fm), after fitting, run the following commands:",
283+
'With a FOOOF object (fm), after fitting, run the following commands:',
284284
"fm.create_report('FOOOF_bad_fit_report')",
285285
"fm.save('FOOOF_bad_fit_data', True, True, True)",
286286
'',

fooof/core/utils.py

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -100,53 +100,6 @@ def check_array_dim(arr):
100100
return np.empty([0, 3]) if arr.ndim == 1 else arr
101101

102102

103-
def get_obj_desc():
104-
"""Get dictionary specifying FOOOF object names and kind of attributes.
105-
106-
Returns
107-
-------
108-
attibutes : dict
109-
Mapping of FOOOF object attributes, and what kind of data they are.
110-
"""
111-
112-
attributes = {'results' : ['aperiodic_params_', 'peak_params_', 'error_',
113-
'r_squared_', '_gaussian_params'],
114-
'settings' : ['peak_width_limits', 'max_n_peaks', 'min_peak_amplitude',
115-
'peak_threshold', 'aperiodic_mode'],
116-
'data' : ['power_spectrum', 'freq_range', 'freq_res'],
117-
'freq_info' : ['freq_range', 'freq_res'],
118-
'arrays' : ['freqs', 'power_spectrum', 'aperiodic_params_',
119-
'peak_params_', '_gaussian_params']}
120-
121-
return attributes
122-
123-
124-
def get_data_indices(aperiodic_mode):
125-
"""Get a dictionary mapping the column labels to indices in FOOOF data (FOOOFResults).
126-
127-
Parameters
128-
----------
129-
aperiodic_mode : {'fixed', 'knee'}
130-
Which approach taken to fit the aperiodic component.
131-
132-
Returns
133-
-------
134-
indices : dict
135-
Mapping for data columns to the column indices in which they appear.
136-
"""
137-
138-
indices = {
139-
'CF' : 0,
140-
'Amp' : 1,
141-
'BW' : 2,
142-
'offset' : 0,
143-
'knee' : 1 if aperiodic_mode == 'knee' else None,
144-
'exponent' : 1 if aperiodic_mode == 'fixed' else 2
145-
}
146-
147-
return indices
148-
149-
150103
def check_iter(obj, length):
151104
"""Check an object to ensure that it is iterable, and make it iterable if not.
152105

fooof/data.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Data objects for FOOOF."""
2+
3+
from collections import namedtuple
4+
5+
###################################################################################################
6+
###################################################################################################
7+
8+
FOOOFSettings = namedtuple('FOOOFSettings', ['peak_width_limits', 'max_n_peaks',
9+
'min_peak_amplitude', 'peak_threshold',
10+
'aperiodic_mode'])
11+
FOOOFSettings.__doc__ = """\
12+
The user defined settings for a FOOOF object.
13+
14+
Attributes
15+
----------
16+
peak_width_limits : tuple of (float, float), optional, default: (0.5, 12.0)
17+
Limits on possible peak width, as (lower_bound, upper_bound).
18+
max_n_peaks : int, optional, default: inf
19+
Maximum number of gaussians to be fit in a single spectrum.
20+
min_peak_amplitude : float, optional, default: 0
21+
Minimum amplitude threshold for a peak to be modeled.
22+
peak_threshold : float, optional, default: 2.0
23+
Threshold for detecting peaks, units of standard deviation.
24+
aperiodic_mode : {'fixed', 'knee'}
25+
Which approach to take for fitting the aperiodic component.
26+
"""
27+
28+
29+
FOOOFDataInfo = namedtuple('FOOOFDataInfo', ['freq_range', 'freq_res'])
30+
31+
FOOOFDataInfo.__doc__ = """\
32+
Data related information for a FOOOF object.
33+
34+
Attributes
35+
----------
36+
freq_range : list of [float, float]
37+
Frequency range of the power spectrum, as [lowest_freq, highest_freq].
38+
freq_res : float
39+
Frequency resolution of the power spectrum.
40+
"""
41+
42+
43+
FOOOFResults = namedtuple('FOOOFResults', ['aperiodic_params', 'peak_params',
44+
'r_squared', 'error', 'gaussian_params'])
45+
FOOOFResults.__doc__ = """\
46+
The resulting parameters and associated data of a FOOOF model fit.
47+
48+
Attributes
49+
----------
50+
aperiodic_params : 1d array
51+
Parameters that define the aperiodic fit. As [Offset, (Knee), Exponent].
52+
The knee parameter is only included if aperiodic is fit with knee.
53+
peak_params : 2d array
54+
Fitted parameter values for the peaks. Each row is a peak, as [CF, Amp, BW].
55+
r_squared : float
56+
R-squared of the fit between the input power spectrum and the full model fit.
57+
error : float
58+
Root mean squared error of the full model fit.
59+
gaussian_params : 2d array
60+
Parameters that define the gaussian fit(s). Each row is a gaussian, as [mean, amp, std].
61+
"""
62+
63+
64+
SynParams = namedtuple('SynParams', ['aperiodic_params', 'gaussian_params', 'nlv'])
65+
66+
SynParams.__doc__ = """\
67+
Stores parameters used to synthesize a single power spectra.
68+
69+
Attributes
70+
----------
71+
aperiodic_params : list, len 2 or 3
72+
Parameters that define the aperiodic fit. As [Offset, (Knee), Exponent].
73+
The knee parameter is only included if aperiodic is fit with knee. Otherwise, length is 2.
74+
gaussian_params : list or list of lists
75+
Fitted parameter values for the peaks. Each list is a peak, as [CF, Amp, BW].
76+
nlv : float
77+
Noise level added to the generated power spectrum.
78+
"""

0 commit comments

Comments
 (0)