Skip to content

Commit 118d200

Browse files
authored
Merge pull request #288 from fooof-tools/interpg
[ENH] - Add `interpolate_spectra` function
2 parents 72acddc + 6fe727d commit 118d200

File tree

5 files changed

+83
-2
lines changed

5 files changed

+83
-2
lines changed

doc/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ Utilities for working with data.
341341

342342
trim_spectrum
343343
interpolate_spectrum
344+
interpolate_spectra
344345
subsample_spectra
345346

346347
Parameter Utilities

fooof/core/modutils.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def docs_append_to_section(docstring, section, add):
164164
for split in docstring.split('\n\n')])
165165

166166

167-
def docs_get_section(docstring, section, output='extract'):
167+
def docs_get_section(docstring, section, output='extract', end=None):
168168
"""Extract and/or remove a specified section from a docstring.
169169
170170
Parameters
@@ -177,6 +177,9 @@ def docs_get_section(docstring, section, output='extract'):
177177
Run mode, options:
178178
'extract' - returns the extracted section from the docstring.
179179
'remove' - returns the docstring after removing the specified section.
180+
end : str, optional
181+
Indicates the contents of a line that signals the end of the section to select.
182+
If not provided, the section is selected until a blank line.
180183
181184
Returns
182185
-------
@@ -193,7 +196,12 @@ def docs_get_section(docstring, section, output='extract'):
193196
# Track whether in the desired section
194197
if section in line and '--' in docstring_split[ind + 1]:
195198
in_section = True
196-
if in_section and line == '':
199+
if end:
200+
if in_section and ' ' + end == line:
201+
in_section = False
202+
# In this approach, an extra newline is caught - so pop it off
203+
outs.pop()
204+
elif in_section and line == '':
197205
in_section = False
198206

199207
# Collect desired outputs based on whether extracting or removing section

fooof/tests/core/test_modutils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ def test_docs_get_section(tdocstring):
7373
assert 'Parameters' not in out2
7474
assert 'Returns' in out2
7575

76+
# Test with end_selection
77+
out3 = docs_get_section(tdocstring, 'Parameters', output='extract', end='Returns')
78+
assert 'Parameters' in out3
79+
assert 'Returns' not in out3
80+
7681
def test_docs_add_section(tdocstring):
7782

7883
tdocstring = tdocstring + \

fooof/tests/utils/test_data.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,21 @@ def test_interpolate_spectrum():
5050
mask = np.logical_and(freqs >= f_range[0], freqs <= f_range[1])
5151
assert powers[mask].sum() > powers_out[mask].sum()
5252

53+
def test_interpolate_spectra():
54+
55+
freqs, powers = gen_group_power_spectra(\
56+
5, [1, 150], [1, 100, 1], [[10, 0.5, 1.0], [60, 1, 0.1], [120, 0.5, 0.1]])
57+
58+
exclude = [[58, 62], [118, 122]]
59+
freqs_out, powers_out = interpolate_spectra(freqs, powers, exclude)
60+
assert np.array_equal(freqs, freqs_out)
61+
assert np.all(powers)
62+
assert powers.shape == powers_out.shape
63+
64+
for f_range in exclude:
65+
mask = np.logical_and(freqs >= f_range[0], freqs <= f_range[1])
66+
assert powers[:, mask].sum() > powers_out[:, mask].sum()
67+
5368
def test_subsample_spectra():
5469

5570
# Simulate spectra, each with unique osc peak (for checking)

fooof/utils/data.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Utilities for working with data and models."""
22

33
from itertools import repeat
4+
from functools import partial
45

56
import numpy as np
67

8+
from fooof.core.modutils import docs_get_section, replace_docstring_sections
9+
710
###################################################################################################
811
###################################################################################################
912

@@ -138,6 +141,55 @@ def interpolate_spectrum(freqs, powers, interp_range, buffer=3):
138141
return freqs, powers
139142

140143

144+
def wrap_interpolate_spectrum(powers, freqs, interp_range, buffer):
145+
"""Wraps interpolate function, organizing inputs & outputs to use `partial`."""
146+
return interpolate_spectrum(freqs, powers, interp_range, buffer)[1]
147+
148+
149+
@replace_docstring_sections(docs_get_section(interpolate_spectrum.__doc__, 'Notes', end='Examples'))
150+
def interpolate_spectra(freqs, powers, interp_range, buffer=3):
151+
"""Interpolate a frequency region across a group of power spectra.
152+
153+
Parameters
154+
----------
155+
freqs : 1d array
156+
Frequency values for the power spectrum.
157+
powers : 2d array
158+
Power values for the power spectra.
159+
interp_range : list of float or list of list of float
160+
Frequency range to interpolate, as [lowest_freq, highest_freq].
161+
If a list of lists, applies each as it's own interpolation range.
162+
buffer : int or list of int
163+
The number of samples to use on either side of the interpolation
164+
range, that are then averaged and used to calculate the interpolation.
165+
166+
Returns
167+
-------
168+
freqs : 1d array
169+
Frequency values for the power spectrum.
170+
powers : 2d array
171+
Power values, with interpolation, for the power spectra.
172+
173+
Notes
174+
-----
175+
% copied in from interpolate_spectrum
176+
177+
Examples
178+
--------
179+
Using simulated spectra, interpolate away line noise peaks:
180+
181+
>>> from fooof.sim import gen_group_power_spectra
182+
>>> freqs, powers = gen_group_power_spectra(5, [1, 75], [1, 1], [[10, 0.5, 1.0], [60, 2, 0.1]])
183+
>>> freqs, powers = interpolate_spectra(freqs, powers, [58, 62])
184+
"""
185+
186+
tfunc = partial(wrap_interpolate_spectrum, freqs=freqs,
187+
interp_range=interp_range, buffer=buffer)
188+
powers = np.apply_along_axis(tfunc, 1, powers)
189+
190+
return freqs,powers
191+
192+
141193
def subsample_spectra(spectra, selection, return_inds=False):
142194
"""Subsample a group of power spectra.
143195

0 commit comments

Comments
 (0)